diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml new file mode 100644 index 000000000..e4a7507fd --- /dev/null +++ b/.github/workflows/linux-build.yml @@ -0,0 +1,83 @@ +name: Linux-Build + +on: + pull_request: + push: + paths-ignore: + - '.github/workflows/windows-build.yml' + - '.gitignore' + - 'LICENSE' + - 'CHANGELOG.md' + - 'README.md' + - 'README_en.md' + - 'README_fr.md' + +jobs: + build: + strategy: + matrix: + os: [ubuntu-20.04] + arch: [x64] + mode: [debug, releasedbg] + + runs-on: ${{ matrix.os }} + if: "!contains(github.event.head_commit.message, 'ci skip')" + + steps: + - uses: actions/checkout@v2 + + # Install Qt (required for shader nodes editor) + - name: Install Qt + uses: jurplel/install-qt-action@v2 + + # Install Nazara dependencies + - name: Update apt repositories + run: sudo apt-get update + + # Install Nazara dependencies + - name: Install system dependencies + run: sudo apt-get install libsndfile1-dev libfreetype6-dev libsdl2-dev mesa-common-dev libxcb-ewmh-dev libxcb-randr0-dev libxcb-icccm4-dev libxcb-keysyms1-dev libgl1-mesa-dev -y + + # Force xmake to a specific folder (for cache) + - name: Set xmake env + run: echo "XMAKE_GLOBALDIR=${{ runner.workspace }}/xmake-global" >> $GITHUB_ENV + + # Install xmake + - name: Setup xmake + uses: xmake-io/github-action-setup-xmake@v1 + with: + xmake-version: branch@dev + + # Update xmake repository (in order to have the file that will be cached) + - name: Update xmake repository + run: xmake repo --update + + # Fetch xmake dephash + - name: Retrieve dependencies hash + id: dep_hash + run: echo "::set-output name=hash::$(xmake l utils.ci.packageskey)" + + # Cache xmake dependencies + - name: Retrieve cached xmake dependencies + uses: actions/cache@v2 + with: + path: ${{ env.XMAKE_GLOBALDIR }}/.xmake/packages + key: ${{ runner.os }}-${{ matrix.arch }}-${{ matrix.mode }}-${{ steps.dep_hash.outputs.hash }} + + # Setup compilation mode and install project dependencies + - name: Configure xmake and install dependencies + run: xmake config --arch=${{ matrix.arch }} --mode=${{ matrix.mode }} --yes --verbose + + # Build the engine + - name: Build Nazara + run: xmake + + # Install the result files + - name: Install Nazara + run: xmake install -vo package + + # Upload artifacts + - uses: actions/upload-artifact@v2 + with: + name: ${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.mode }} + path: package diff --git a/.github/workflows/windows-build.yml b/.github/workflows/windows-build.yml new file mode 100644 index 000000000..135950066 --- /dev/null +++ b/.github/workflows/windows-build.yml @@ -0,0 +1,75 @@ +name: Windows-Build + +on: + pull_request: + push: + paths-ignore: + - '.github/workflows/linux-build.yml' + - '.gitignore' + - 'LICENSE' + - 'CHANGELOG.md' + - 'README.md' + - 'README_en.md' + - 'README_fr.md' + +jobs: + build: + strategy: + matrix: + os: [windows-latest] + arch: [x64] + mode: [debug, releasedbg] + + runs-on: ${{ matrix.os }} + if: "!contains(github.event.head_commit.message, 'ci skip')" + + steps: + - uses: actions/checkout@v2 + + # Install Qt (required for shader nodes editor) + - name: Install Qt + uses: jurplel/install-qt-action@v2 + + # Force xmake to a specific folder (for cache) + - name: Set xmake env + run: echo "XMAKE_GLOBALDIR=${{ runner.workspace }}/xmake-global" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + + # Install xmake + - name: Setup xmake + uses: xmake-io/github-action-setup-xmake@v1 + with: + xmake-version: branch@dev + + # Update xmake repository (in order to have the file that will be cached) + - name: Update xmake repository + run: xmake.exe repo --update + + # Fetch xmake dephash + - name: Retrieve dependencies hash + id: dep_hash + run: echo "::set-output name=hash::$(xmake.exe l utils.ci.packageskey)" + + # Cache xmake dependencies + - name: Retrieve cached xmake dependencies + uses: actions/cache@v2 + with: + path: ${{ env.XMAKE_GLOBALDIR }}\.xmake\packages + key: ${{ runner.os }}-${{ matrix.arch }}-${{ matrix.mode }}-${{ steps.dep_hash.outputs.hash }} + + # Setup compilation mode and install project dependencies + - name: Configure xmake and install dependencies + run: xmake.exe config --arch=${{ matrix.arch }} --mode=${{ matrix.mode }} --yes --verbose + + # Build the engine + - name: Build Nazara + run: xmake.exe + + # Install the result files + - name: Install Nazara + run: xmake.exe install -vo package + + # Upload artifacts + - uses: actions/upload-artifact@v2 + with: + name: ${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.mode }} + path: package diff --git a/.gitignore b/.gitignore index 52e7c505e..1b9a63d4e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,19 @@ -# Nazara build -build/config.lua +# xmake-related files +.xmake/* +.vs/* +.vscode/* +CMakeLists.txt +Makefile +vs/* +vsxmake*/* # Nazara binaries bin/* +!bin/resources +!bin/resources/* # Build files -build/gmake*/ -build/vs*/ +build/* # Nazara libraries lib/* diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 17bccbd36..000000000 --- a/.travis.yml +++ /dev/null @@ -1,26 +0,0 @@ -language: - cpp - -sudo: - required - -notifications: - email: true - -services: - - docker - -before_install: - - docker build -t nazara . - -script: - - docker run --name Nazara -v `pwd`:/NazaraEngine nazara - sh -c " - cd build && - ./premake5-linux64 --cc=clang gmake && - cd gmake && - make -j4 && - cd ../../tests && - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../lib/gmake/x64/:../extlibs/lib/gmake/x64/ && - ./NazaraUnitTestsServer - " diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index b1ab55789..000000000 --- a/Dockerfile +++ /dev/null @@ -1,6 +0,0 @@ -FROM debian:buster - -RUN apt-get update && apt-get install -y build-essential clang libopenal-dev libsndfile1-dev libfreetype6-dev libassimp-dev libsdl2-dev libxcb-keysyms1-dev libxcb-ewmh-dev libx11-dev libfreetype6-dev mesa-common-dev libgl1-mesa-dev - -RUN mkdir /NazaraEngine -WORKDIR /NazaraEngine \ No newline at end of file diff --git a/SDK/include/NDK/Components.hpp b/SDK/include/NDK/Components.hpp deleted file mode 100644 index 97f597990..000000000 --- a/SDK/include/NDK/Components.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// This file was automatically generated - -#pragma once - -#ifndef NDK_COMPONENTS_GLOBAL_HPP -#define NDK_COMPONENTS_GLOBAL_HPP - - -#endif // NDK_COMPONENTS_GLOBAL_HPP diff --git a/SDK/include/NDK/Systems.hpp b/SDK/include/NDK/Systems.hpp deleted file mode 100644 index 33edfc17a..000000000 --- a/SDK/include/NDK/Systems.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// This file was automatically generated - -#pragma once - -#ifndef NDK_SYSTEMS_GLOBAL_HPP -#define NDK_SYSTEMS_GLOBAL_HPP - - -#endif // NDK_SYSTEMS_GLOBAL_HPP diff --git a/SDK/include/NDK/Widgets.hpp b/SDK/include/NDK/Widgets.hpp deleted file mode 100644 index b009f3a17..000000000 --- a/SDK/include/NDK/Widgets.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// This file was automatically generated - -#pragma once - -#ifndef NDK_WIDGETS_GLOBAL_HPP -#define NDK_WIDGETS_GLOBAL_HPP - - -#endif // NDK_WIDGETS_GLOBAL_HPP diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index c3c44154d..000000000 --- a/appveyor.yml +++ /dev/null @@ -1,59 +0,0 @@ -version: '{branch}-rev{build}' - -shallow_clone: true - -skip_commits: - files: - - .travis.yml - - Dockerfile - - Doxyfile - - LICENSE - - License-Cabin.txt - - Logo.png - - LogoMini.png - - readme.md - - readme_fr.md - - 'writing style.md' - - doc/* - - NazaraModuleTemplate/* - message: /\[Posix\]/ - -os: - - Visual Studio 2019 - -environment: - matrix: - - TOOLSET: vs2019 - -install: - - cd build && "./premake5.exe" %TOOLSET% && cd .. - -configuration: - - DebugDynamic - - ReleaseDynamic - -platform: - - Win32 - - x64 - -build: - project: build/$(TOOLSET)/NazaraEngine.sln - -after_build: - - cd build && "./premake5.exe" package && cd ../package - - 7z a NazaraEngine.7z * && cd .. - -artifacts: - - path: package/NazaraEngine.7z - name: 'NazaraEngine-$(CONFIGURATION)-$(PLATFORM)-$(APPVEYOR_REPO_COMMIT)' - -on_success: - - cd tests && "./NazaraUnitTestsServer.exe" - -notifications: - - provider: Slack - incoming_webhook: - secure: 5FSnJzsZCMXNDqPYGhN4ZSX7qa1KMmbV0UGT9i0LcElk3X91z3fs1TZRpZZ3++Tkw8qAk1G/qDChom5GQ7Vj7X29cScQHvGHXffl3qaC5EdSiGpjloMZKfeiGTnf798IX0n/ABSlDHG7GrB8IiulRGx3iVOpPQmrPWCiz9ZPtY8h84xpd65FGd8gETKG/sYk - on_build_success: true - on_build_failure: true - on_build_status_changed: false diff --git a/tests/resources/Engine/Audio/Cat.flac.REMOVED.git-id b/bin/resources/Engine/Audio/Cat.flac.REMOVED.git-id similarity index 100% rename from tests/resources/Engine/Audio/Cat.flac.REMOVED.git-id rename to bin/resources/Engine/Audio/Cat.flac.REMOVED.git-id diff --git a/tests/resources/Engine/Audio/The_Brabanconne.ogg.REMOVED.git-id b/bin/resources/Engine/Audio/The_Brabanconne.ogg.REMOVED.git-id similarity index 100% rename from tests/resources/Engine/Audio/The_Brabanconne.ogg.REMOVED.git-id rename to bin/resources/Engine/Audio/The_Brabanconne.ogg.REMOVED.git-id diff --git a/tests/resources/Engine/Audio/copyrights.txt b/bin/resources/Engine/Audio/copyrights.txt similarity index 100% rename from tests/resources/Engine/Audio/copyrights.txt rename to bin/resources/Engine/Audio/copyrights.txt diff --git a/tests/resources/Engine/Core/FileTest.txt b/bin/resources/Engine/Core/FileTest.txt similarity index 100% rename from tests/resources/Engine/Core/FileTest.txt rename to bin/resources/Engine/Core/FileTest.txt diff --git a/tests/resources/Engine/Graphics/Bob lamp/Readme.txt b/bin/resources/Engine/Graphics/Bob lamp/Readme.txt similarity index 100% rename from tests/resources/Engine/Graphics/Bob lamp/Readme.txt rename to bin/resources/Engine/Graphics/Bob lamp/Readme.txt diff --git a/tests/resources/Engine/Graphics/copyrights.txt b/bin/resources/Engine/Graphics/copyrights.txt similarity index 100% rename from tests/resources/Engine/Graphics/copyrights.txt rename to bin/resources/Engine/Graphics/copyrights.txt diff --git a/tests/resources/Engine/Graphics/dragon_recon/README b/bin/resources/Engine/Graphics/dragon_recon/README similarity index 100% rename from tests/resources/Engine/Graphics/dragon_recon/README rename to bin/resources/Engine/Graphics/dragon_recon/README diff --git a/examples/bin/resources/Spaceship/readme.txt b/bin/resources/Spaceship/readme.txt similarity index 100% rename from examples/bin/resources/Spaceship/readme.txt rename to bin/resources/Spaceship/readme.txt diff --git a/bin/resources/bloom_bright.nzsl b/bin/resources/bloom_bright.nzsl new file mode 100644 index 000000000..ea2a477ec --- /dev/null +++ b/bin/resources/bloom_bright.nzsl @@ -0,0 +1,69 @@ +[layout(std140)] +struct ViewerData +{ + projectionMatrix: mat4, + invProjectionMatrix: mat4, + viewMatrix: mat4, + invViewMatrix: mat4, + viewProjMatrix: mat4, + invViewProjMatrix: mat4, + renderTargetSize: vec2, + invRenderTargetSize: vec2, + eyePosition: vec3 +} + +external +{ + [binding(0)] colorTexture: sampler2D, + [binding(1)] viewerData: uniform +} + +struct FragIn +{ + [builtin(fragcoord)] fragcoord: vec4 +} + +struct FragOut +{ + [location(0)] color: vec4 +} + +struct VertIn +{ + [location(0)] pos: vec3 +} + +struct VertOut +{ + [builtin(position)] position: vec4 +} + +[entry(frag)] +fn main(input: FragIn) -> FragOut +{ + let BrightLuminance = 0.8; + let BrightMiddleGrey = 0.5; + let BrightThreshold = 0.7; + + let fragcoord = input.fragcoord.xy * viewerData.invRenderTargetSize * 10.0; + + let color = colorTexture.Sample(fragcoord).rgb; + color = color * (BrightMiddleGrey/BrightLuminance); + color = color * (vec3(1.0, 1.0, 1.0) + (color / (BrightThreshold*BrightThreshold))); + color = color - vec3(0.5, 0.5, 0.5); + color = color / (vec3(1.0, 1.0, 1.0) + color); + + let output: FragOut; + output.color = vec4(color, 1.0); + + return output; +} + +[entry(vert)] +fn main(input: VertIn) -> VertOut +{ + let output: VertOut; + output.position = vec4(input.pos, 1.0); + + return output; +} diff --git a/bin/resources/bloom_final.nzsl b/bin/resources/bloom_final.nzsl new file mode 100644 index 000000000..506917ffe --- /dev/null +++ b/bin/resources/bloom_final.nzsl @@ -0,0 +1,60 @@ +[layout(std140)] +struct ViewerData +{ + projectionMatrix: mat4, + invProjectionMatrix: mat4, + viewMatrix: mat4, + invViewMatrix: mat4, + viewProjMatrix: mat4, + invViewProjMatrix: mat4, + renderTargetSize: vec2, + invRenderTargetSize: vec2, + eyePosition: vec3 +} + +external +{ + [binding(0)] colorTexture: sampler2D, + [binding(1)] bloomTexture: sampler2D, + [binding(2)] viewerData: uniform +} + +struct FragIn +{ + [builtin(fragcoord)] fragcoord: vec4 +} + +struct FragOut +{ + [location(0)] color: vec4 +} + +struct VertIn +{ + [location(0)] pos: vec3 +} + +struct VertOut +{ + [builtin(position)] position: vec4 +} + +[entry(frag)] +fn main(input: FragIn) -> FragOut +{ + let fragcoord = input.fragcoord.xy * viewerData.invRenderTargetSize; + + let output: FragOut; + output.color = colorTexture.Sample(fragcoord) + bloomTexture.Sample(fragcoord); + + return output; +} + +[entry(vert)] +fn main(input: VertIn) -> VertOut +{ + let output: VertOut; + output.position = vec4(input.pos, 1.0); + + return output; +} diff --git a/bin/resources/deferred_frag.nzsl b/bin/resources/deferred_frag.nzsl new file mode 100644 index 000000000..f487e4ce1 --- /dev/null +++ b/bin/resources/deferred_frag.nzsl @@ -0,0 +1,72 @@ +option HAS_DIFFUSE_TEXTURE: bool; +option HAS_ALPHA_TEXTURE: bool; +option ALPHA_TEST: bool; + +[layout(std140)] +struct BasicSettings +{ + AlphaThreshold: f32, + DiffuseColor: vec4 +} + +[layout(std140)] +struct InstanceData +{ + worldMatrix: mat4, + invWorldMatrix: mat4 +} + +[layout(std140)] +struct ViewerData +{ + projectionMatrix: mat4, + invProjectionMatrix: mat4, + viewMatrix: mat4, + invViewMatrix: mat4, + viewProjMatrix: mat4, + invViewProjMatrix: mat4, + renderTargetSize: vec2, + invRenderTargetSize: vec2, + eyePosition: vec3 +} + +external +{ + [binding(5)] viewerData: uniform, + [binding(4)] instanceData: uniform, + [binding(3)] settings: uniform, + [binding(0)] MaterialAlphaMap: sampler2D, + [binding(1)] MaterialDiffuseMap: sampler2D, + [binding(2)] TextureOverlay: sampler2D +} + +struct InputData +{ + [location(0)] vertNormal: vec3, + [location(1)] vertUV: vec2, + [location(2)] vertPos: vec3 +} + +struct OutputData +{ + [location(0)] diffuseMap: vec4, + [location(1)] normalMap: vec4, + [location(2)] positionMap: vec4 +} + +[entry(frag)] +fn main(input: InputData) -> OutputData +{ + let textureColor = select_opt(HAS_DIFFUSE_TEXTURE, MaterialDiffuseMap.Sample(input.vertUV) * settings.DiffuseColor, settings.DiffuseColor); + let alpha = select_opt(HAS_ALPHA_TEXTURE, MaterialAlphaMap.Sample(input.vertUV).x * textureColor.w, 1.0); + /*if ((select_opt(ALPHA_TEST, var0.w < settings.AlphaThreshold, false)) == (true)) + { + discard; + }*/ + + let output: OutputData; + output.diffuseMap = textureColor; + output.normalMap = vec4((vec3(1.0, 1.0, 1.0) + input.vertNormal) * 0.5, 1.0); + output.positionMap = vec4(input.vertPos, 1.0); + return output; +} diff --git a/bin/resources/deferred_vert.nzsl b/bin/resources/deferred_vert.nzsl new file mode 100644 index 000000000..b4ac86099 --- /dev/null +++ b/bin/resources/deferred_vert.nzsl @@ -0,0 +1,62 @@ +[layout(std140)] +struct BasicSettings +{ + AlphaThreshold: f32, + DiffuseColor: vec4 +} + +[layout(std140)] +struct InstanceData +{ + worldMatrix: mat4, + invWorldMatrix: mat4 +} + +[layout(std140)] +struct ViewerData +{ + projectionMatrix: mat4, + invProjectionMatrix: mat4, + viewMatrix: mat4, + invViewMatrix: mat4, + viewProjMatrix: mat4, + invViewProjMatrix: mat4, + renderTargetSize: vec2, + invRenderTargetSize: vec2, + eyePosition: vec3 +} + +external +{ + [binding(5)] viewerData: uniform, + [binding(4)] instanceData: uniform, + [binding(3)] settings: uniform +} + +struct InputData +{ + [location(0)] inPos: vec3, + [location(1)] inNormals: vec3, + [location(2)] inTexCoord: vec2 +} + +struct OutputData +{ + [location(0)] vertNormal: vec3, + [location(1)] vertUV: vec2, + [location(2)] vertPos: vec3, + [builtin(position)] position: vec4 +} + +[entry(vert)] +fn main(input: InputData) -> OutputData +{ + let worldPos = instanceData.worldMatrix * vec4(input.inPos, 1.0); + + let output: OutputData; + output.vertUV = input.inTexCoord; + output.vertNormal = input.inNormals; + output.vertPos = worldPos.xyz; + output.position = viewerData.projectionMatrix * viewerData.viewMatrix * instanceData.worldMatrix * vec4(input.inPos, 1.0); + return output; +} diff --git a/bin/resources/file_example_MP3_700KB.txt b/bin/resources/file_example_MP3_700KB.txt new file mode 100644 index 000000000..fca4d8ad8 --- /dev/null +++ b/bin/resources/file_example_MP3_700KB.txt @@ -0,0 +1 @@ +https://file-examples.com/index.php/sample-audio-files/sample-mp3-download/ \ No newline at end of file diff --git a/bin/resources/fullscreen.frag.shader b/bin/resources/fullscreen.frag.shader new file mode 100644 index 000000000..db4945aca Binary files /dev/null and b/bin/resources/fullscreen.frag.shader differ diff --git a/bin/resources/fullscreen.vert.shader b/bin/resources/fullscreen.vert.shader new file mode 100644 index 000000000..468a6a244 Binary files /dev/null and b/bin/resources/fullscreen.vert.shader differ diff --git a/bin/resources/gaussian_blur.nzsl b/bin/resources/gaussian_blur.nzsl new file mode 100644 index 000000000..24907fb7d --- /dev/null +++ b/bin/resources/gaussian_blur.nzsl @@ -0,0 +1,78 @@ +[layout(std140)] +struct ViewerData +{ + projectionMatrix: mat4, + invProjectionMatrix: mat4, + viewMatrix: mat4, + invViewMatrix: mat4, + viewProjMatrix: mat4, + invViewProjMatrix: mat4, + renderTargetSize: vec2, + invRenderTargetSize: vec2, + eyePosition: vec3 +} + +external +{ + [binding(0)] colorTexture: sampler2D, + [binding(1)] viewerData: uniform +} + +struct FragIn +{ + [builtin(fragcoord)] fragcoord: vec4 +} + +struct FragOut +{ + [location(0)] color: vec4 +} + +struct VertIn +{ + [location(0)] pos: vec3 +} + +struct VertOut +{ + [builtin(position)] position: vec4 +} + +[entry(frag)] +fn main(input: FragIn) -> FragOut +{ + let invTargetSize = viewerData.invRenderTargetSize * 10.0; + let fragcoord = input.fragcoord.xy * invTargetSize; + + let color = colorTexture.Sample(fragcoord).rgb * 0.2270270270; + + let filter = vec2(1.0, 0.0); + + color = color + colorTexture.Sample(fragcoord + filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162; + color = color + colorTexture.Sample(fragcoord - filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162; + + color = color + colorTexture.Sample(fragcoord + filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703; + color = color + colorTexture.Sample(fragcoord - filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703; + + filter = vec2(0.0, 1.0); + + color = color + colorTexture.Sample(fragcoord + filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162; + color = color + colorTexture.Sample(fragcoord - filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162; + + color = color + colorTexture.Sample(fragcoord + filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703; + color = color + colorTexture.Sample(fragcoord - filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703; + + let output: FragOut; + output.color = vec4(color, 1.0); + + return output; +} + +[entry(vert)] +fn main(input: VertIn) -> VertOut +{ + let output: VertOut; + output.position = vec4(input.pos, 1.0); + + return output; +} diff --git a/bin/resources/lighting.nzsl b/bin/resources/lighting.nzsl new file mode 100644 index 000000000..c3366facb --- /dev/null +++ b/bin/resources/lighting.nzsl @@ -0,0 +1,108 @@ +[layout(std140)] +struct PointLight +{ + color: vec3, + position: vec3, + + radius: f32, + invRadius: f32, +} + +[layout(std140)] +struct SpotLight +{ + transformMatrix: mat4, + + color: vec3, + position: vec3, + direction: vec3, + + radius: f32, + invRadius: f32, + + innerAngle: f32, + outerAngle: f32 +} + +[layout(std140)] +struct ViewerData +{ + projectionMatrix: mat4, + invProjectionMatrix: mat4, + viewMatrix: mat4, + invViewMatrix: mat4, + viewProjMatrix: mat4, + invViewProjMatrix: mat4, + renderTargetSize: vec2, + invRenderTargetSize: vec2, + eyePosition: vec3 +} + +external +{ + [binding(0)] colorTexture: sampler2D, + [binding(1)] normalTexture: sampler2D, + [binding(2)] positionTexture: sampler2D, + [binding(3)] lightParameters: uniform, + [binding(4)] viewerData: uniform +} + +struct FragIn +{ + [builtin(fragcoord)] fragcoord: vec4 +} + +struct FragOut +{ + [location(0)] color: vec4 +} + +struct VertIn +{ + [location(0)] pos: vec3 +} + +struct VertOut +{ + [builtin(position)] position: vec4 +} + +[entry(frag)] +fn main(input: FragIn) -> FragOut +{ + let fragcoord = input.fragcoord.xy * viewerData.invRenderTargetSize; + let normal = normalTexture.Sample(fragcoord).xyz * 2.0 - vec3(1.0, 1.0, 1.0); + let position = positionTexture.Sample(fragcoord).xyz; + + let attenuation = compute_attenuation(position, normal); + + let output: FragOut; + output.color = vec4(lightParameters.color, 1.0) * attenuation * colorTexture.Sample(fragcoord); + + return output; +} + +[entry(vert)] +fn main(input: VertIn) -> VertOut +{ + let output: VertOut; + output.position = viewerData.projectionMatrix * viewerData.viewMatrix * lightParameters.transformMatrix * vec4(input.pos, 1.0); + + return output; +} + +fn compute_attenuation(worldPos: vec3, normal: vec3) -> f32 +{ + let distance = length(lightParameters.position - worldPos); + + let posToLight = (lightParameters.position - worldPos) / distance; + let lambert = dot(normal, posToLight); + + let curAngle = dot(lightParameters.direction, -posToLight); + let innerMinusOuterAngle = lightParameters.innerAngle - lightParameters.outerAngle; + + let attenuation = max(1.0 - distance * lightParameters.invRadius, 0.0); + attenuation = attenuation * lambert * max((curAngle - lightParameters.outerAngle) / innerMinusOuterAngle, 0.0); + + return attenuation; +} diff --git a/examples/bin/resources/shaders/spirv-triangle.bat b/bin/resources/shaders/spirv-triangle.bat similarity index 100% rename from examples/bin/resources/shaders/spirv-triangle.bat rename to bin/resources/shaders/spirv-triangle.bat diff --git a/examples/bin/resources/shaders/triangle.frag b/bin/resources/shaders/triangle.frag similarity index 100% rename from examples/bin/resources/shaders/triangle.frag rename to bin/resources/shaders/triangle.frag diff --git a/examples/bin/resources/shaders/triangle.frag.spv b/bin/resources/shaders/triangle.frag.spv similarity index 100% rename from examples/bin/resources/shaders/triangle.frag.spv rename to bin/resources/shaders/triangle.frag.spv diff --git a/examples/bin/resources/shaders/triangle.vert b/bin/resources/shaders/triangle.vert similarity index 100% rename from examples/bin/resources/shaders/triangle.vert rename to bin/resources/shaders/triangle.vert diff --git a/examples/bin/resources/shaders/triangle.vert.spv b/bin/resources/shaders/triangle.vert.spv similarity index 100% rename from examples/bin/resources/shaders/triangle.vert.spv rename to bin/resources/shaders/triangle.vert.spv diff --git a/bin/resources/skybox.nzsl b/bin/resources/skybox.nzsl new file mode 100644 index 000000000..159323c05 --- /dev/null +++ b/bin/resources/skybox.nzsl @@ -0,0 +1,68 @@ +[layout(std140)] +struct ViewerData +{ + projectionMatrix: mat4, + invProjectionMatrix: mat4, + viewMatrix: mat4, + invViewMatrix: mat4, + viewProjMatrix: mat4, + invViewProjMatrix: mat4, + renderTargetSize: vec2, + invRenderTargetSize: vec2, + eyePosition: vec3 +} + +external +{ + [binding(1)] skybox: samplerCube +} + +struct VertOut +{ + [location(0)] uvw: vec3, + [builtin(position)] position: vec4 +} + +struct FragOut +{ + [location(0)] color: vec4, + [builtin(fragdepth)] depth: f32 +} + +[entry(frag)] +[depth_write(greater)] +fn main(input: VertOut) -> FragOut +{ + let output: FragOut; + output.color = skybox.Sample(input.uvw); + output.depth = 1.0; + + return output; +} + +external +{ + [binding(0)] viewerData: uniform +} + +struct VertIn +{ + [location(0)] position: vec3 +} + +[entry(vert)] +fn main(input: VertIn) -> VertOut +{ + // Set translation part to zero + let rotationMat = viewerData.viewMatrix; + // rotationMat[3].xyz = vec3(0.0, 0.0, 0.0); // Requires SPIRV generator to handle swizzle for store expressions + rotationMat[3][0] = 0.0; + rotationMat[3][1] = 0.0; + rotationMat[3][2] = 0.0; + + let output: VertOut; + output.position = viewerData.projectionMatrix * rotationMat * vec4(input.position, 1.0); + output.uvw = vec3(input.position.xy * -1.0, input.position.z); + + return output; +} diff --git a/build/Build_CodeBlocks.bat b/build/Build_CodeBlocks.bat deleted file mode 100644 index f660c144d..000000000 --- a/build/Build_CodeBlocks.bat +++ /dev/null @@ -1 +0,0 @@ -.\premake5.exe codeblocks diff --git a/build/Build_CodeLite.bat b/build/Build_CodeLite.bat deleted file mode 100644 index 2a1634776..000000000 --- a/build/Build_CodeLite.bat +++ /dev/null @@ -1 +0,0 @@ -.\premake5.exe codelite diff --git a/build/Build_VS2015.bat b/build/Build_VS2015.bat deleted file mode 100644 index 8657a02cb..000000000 --- a/build/Build_VS2015.bat +++ /dev/null @@ -1 +0,0 @@ -.\premake5.exe --premakeproject vs2015 diff --git a/build/Build_VS2017.bat b/build/Build_VS2017.bat deleted file mode 100644 index c172c5a59..000000000 --- a/build/Build_VS2017.bat +++ /dev/null @@ -1 +0,0 @@ -.\premake5.exe --premakeproject vs2017 diff --git a/build/Build_VS2019.bat b/build/Build_VS2019.bat deleted file mode 100644 index f9dd7c987..000000000 --- a/build/Build_VS2019.bat +++ /dev/null @@ -1 +0,0 @@ -.\premake5.exe --premakeproject vs2019 diff --git a/build/EncodeResources.bat b/build/EncodeResources.bat deleted file mode 100644 index b7dc0f860..000000000 --- a/build/EncodeResources.bat +++ /dev/null @@ -1,2 +0,0 @@ -.\premake5.exe encoderesources -pause diff --git a/build/Generate_GlobalIncludes.bat b/build/Generate_GlobalIncludes.bat deleted file mode 100644 index df132e9ad..000000000 --- a/build/Generate_GlobalIncludes.bat +++ /dev/null @@ -1,2 +0,0 @@ -.\premake5.exe generateheaders -pause diff --git a/build/Generate_UnicodeData.bat b/build/Generate_UnicodeData.bat deleted file mode 100644 index cff81bd31..000000000 --- a/build/Generate_UnicodeData.bat +++ /dev/null @@ -1,2 +0,0 @@ -.\premake5.exe parseunicode -pause diff --git a/build/Package_AutoDetect.bat b/build/Package_AutoDetect.bat deleted file mode 100644 index f86a8c6e5..000000000 --- a/build/Package_AutoDetect.bat +++ /dev/null @@ -1,2 +0,0 @@ -.\premake5.exe package -pause diff --git a/build/Package_MSVC.bat b/build/Package_MSVC.bat deleted file mode 100644 index c39f1cd6c..000000000 --- a/build/Package_MSVC.bat +++ /dev/null @@ -1,2 +0,0 @@ -.\premake5.exe --pack-libdir=msvc package -pause diff --git a/build/Package_MinGW.bat b/build/Package_MinGW.bat deleted file mode 100644 index 21d4c01fc..000000000 --- a/build/Package_MinGW.bat +++ /dev/null @@ -1,2 +0,0 @@ -.\premake5.exe --pack-libdir=mingw package -pause diff --git a/build/config.lua.default b/build/config.lua.default deleted file mode 100644 index b30566fcb..000000000 --- a/build/config.lua.default +++ /dev/null @@ -1,41 +0,0 @@ --- This file contains special configurations values, such as directories to extern libraries (Qt) --- Editing this file is not required to use/compile the engine, as default values should be enough - --- Additionnal compilation options ---AdditionalCompilationOptions = "-fsanitize=address" -- Enable ASan - --- Builds Nazara extern libraries (such as lua/STB) -BuildDependencies = true - --- Builds Nazara examples -BuildExamples = true - --- Setup configurations array (valid values: Debug, Release, ReleaseWithDebug) -Configurations = "Debug,Release,ReleaseWithDebug" -- "Debug,Release,ReleaseWithDebug" - --- Setup additionnals install directories, separated by a semi-colon ; (library binaries will be copied there) ---InstallDir = "/usr/local/lib64" - --- Adds a project which will recall premake with its original arguments when built (only works on Windows for now) -PremakeProject = false - --- Excludes client-only modules/tools/examples -ServerMode = false - --- Builds modules as one united library (useless on POSIX systems) -UniteModules = false - --- Qt5 directories (required for ShaderNodes editor) ---Qt5IncludeDir = [[C:\Projets\Libs\Qt\5.15.0\msvc2019\include]] ---Qt5BinDir_x86 = [[C:\Projets\Libs\Qt\5.15.0\msvc2019\bin]] ---Qt5BinDir_x64 = [[C:\Projets\Libs\Qt\5.15.0\msvc2019_64\bin]] ---Qt5LibDir_x86 = [[C:\Projets\Libs\Qt\5.15.0\msvc2019\lib]] ---Qt5LibDir_x64 = [[C:\Projets\Libs\Qt\5.15.0\msvc2019_64\lib]] - - --- QtNodes directories (required for ShaderNodes editor) ---QtNodesIncludeDir = [[C:\Projets\Libs\nodeeditor\include]] ---QtNodesBinDir_x86 = [[C:\Projets\Libs\nodeeditor\build32\bin\Release]] ---QtNodesBinDir_x64 = [[C:\Projets\Libs\nodeeditor\build64\bin\Release]] ---QtNodesLibDir_x86 = [[C:\Projets\Libs\nodeeditor\build32\lib\Release]] ---QtNodesLibDir_x64 = [[C:\Projets\Libs\nodeeditor\build64\lib\Release]] \ No newline at end of file diff --git a/build/scripts/actions/codeblocks.lua b/build/scripts/actions/codeblocks.lua deleted file mode 100644 index f96a6d591..000000000 --- a/build/scripts/actions/codeblocks.lua +++ /dev/null @@ -1,4 +0,0 @@ -dofile("codeblocks/_codeblocks.lua") -dofile("codeblocks/codeblocks.lua") - -ACTION.Manual = true diff --git a/build/scripts/actions/codeblocks/_codeblocks.lua b/build/scripts/actions/codeblocks/_codeblocks.lua deleted file mode 100644 index 6a52bc404..000000000 --- a/build/scripts/actions/codeblocks/_codeblocks.lua +++ /dev/null @@ -1,44 +0,0 @@ --- --- _codeblocks.lua --- Define the Code::Blocks action(s). --- Copyright (c) 2002-2011 Jason Perkins and the Premake project --- - local p = premake - - p.modules.codeblocks = {} - p.modules.codeblocks._VERSION = p._VERSION - - local codeblocks = p.modules.codeblocks - - newaction { - trigger = "codeblocks", - shortname = "Code::Blocks", - description = "Generate Code::Blocks project files", - - valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib" }, - - valid_languages = { "C", "C++" }, - - valid_tools = { - cc = { "clang", "gcc", "ow" }, - }, - - onWorkspace = function(wks) - p.modules.codeblocks.generateWorkspace(wks) - end, - - onProject = function(prj) - p.modules.codeblocks.generateProject(prj) - end, - - onCleanWorkspace = function(wks) - p.clean.file(wks, wks.name .. ".workspace") - p.clean.file(wks, wks.name .. ".workspace.layout") - end, - - onCleanProject = function(prj) - p.clean.file(prj, prj.name .. ".workspace") - p.clean.file(prj, prj.name .. ".depend") - p.clean.file(prj, prj.name .. ".layout") - end - } diff --git a/build/scripts/actions/codeblocks/codeblocks.lua b/build/scripts/actions/codeblocks/codeblocks.lua deleted file mode 100644 index ebd8d11fa..000000000 --- a/build/scripts/actions/codeblocks/codeblocks.lua +++ /dev/null @@ -1,67 +0,0 @@ --- --- codeblocks_workspace.lua --- Generate a Code::Blocks workspace. --- Copyright (c) 2009 Jason Perkins and the Premake project --- - - local p = premake - - p.modules.codeblocks = {} - p.modules.codeblocks._VERSION = p._VERSION - - local codeblocks = p.modules.codeblocks - local project = p.project - - - function codeblocks.cfgname(cfg) - local cfgname = cfg.buildcfg - if codeblocks.workspace.multiplePlatforms then - cfgname = string.format("%s|%s", cfg.platform, cfg.buildcfg) - end - return cfgname - end - - function codeblocks.esc(value) - local result = value:gsub('"', '"') - result = result:gsub('<', '<') - result = result:gsub('>', '>') - return result - end - - function codeblocks.generateWorkspace(wks) - p.eol("\r\n") - p.indent("\t") - p.escaper(codeblocks.esc) - - p.generate(wks, ".workspace", codeblocks.workspace.generate) - end - - function codeblocks.generateProject(prj) - p.eol("\r\n") - p.indent("\t") - p.escaper(codeblocks.esc) - - if project.iscpp(prj) then - p.generate(prj, ".cbp", codeblocks.project.generate) - end - end - - function codeblocks.cleanWorkspace(wks) - p.clean.file(wks, wks.name .. ".workspace") - p.clean.file(wks, wks.name .. ".workspace.layout") - end - - function codeblocks.cleanProject(prj) - p.clean.file(prj, prj.name .. ".workspace") - p.clean.file(prj, prj.name .. ".depend") - p.clean.file(prj, prj.name .. ".layout") - end - - function codeblocks.cleanTarget(prj) - -- TODO.. - end - - include("codeblocks_workspace.lua") - include("codeblocks_project.lua") - - diff --git a/build/scripts/actions/codeblocks/codeblocks_project.lua b/build/scripts/actions/codeblocks/codeblocks_project.lua deleted file mode 100644 index acfede4c2..000000000 --- a/build/scripts/actions/codeblocks/codeblocks_project.lua +++ /dev/null @@ -1,243 +0,0 @@ --- --- codeblocks_cbp.lua --- Generate a Code::Blocks C/C++ project. --- Copyright (c) 2009, 2011 Jason Perkins and the Premake project --- - - local p = premake - local project = p.project - local config = p.config - local tree = p.tree - local codeblocks = p.modules.codeblocks - - codeblocks.project = {} - local m = codeblocks.project - m.elements = {} - - m.ctools = { - gcc = "gcc", - msc = "Visual C++", - } - - function m.getcompilername(cfg) - local tool = _OPTIONS.cc or cfg.toolset or p.GCC - - local toolset = p.tools[tool] - if not toolset then - error("Invalid toolset '" + (_OPTIONS.cc or cfg.toolset) + "'") - end - - return m.ctools[tool] - end - - function m.getcompiler(cfg) - local toolset = p.tools[_OPTIONS.cc or cfg.toolset or p.GCC] - if not toolset then - error("Invalid toolset '" + (_OPTIONS.cc or cfg.toolset) + "'") - end - return toolset - end - - function m.header(prj) - _p('') - _p('') - _p(1,'') - - -- write project block header - _p(1,'') - _p(2,'') - _p('') - end - - m.elements.project = function(prj) - return { - m.header, - m.configurations, - m.files, - m.extensions, - m.footer - } - end - --- --- Project: Generate the CodeBlocks project file. --- - function m.generate(prj) - p.utf8() - - p.callArray(m.elements.project, prj) - end - - function m.configurations(prj) - -- write configuration blocks - _p(2,'') - local platforms = {} - for cfg in project.eachconfig(prj) do - local found = false - for k,v in pairs(platforms) do - if (v.platform == cfg.platform) then - table.insert(v.configs, cfg) - found = true - break - end - end - - if (not found) then - table.insert(platforms, {platform = cfg.platform, configs = {cfg}}) - end - end - - for k,platform in pairs(platforms) do - for k,cfg in pairs(platform.configs) do - local compiler = m.getcompiler(cfg) - - _p(3,'', cfg.longname) - - _p(4,'') - end - end - _p(2,'') - end - --- --- Write out a list of the source code files in the project. --- - - function m.files(prj) - local pchheader - if (prj.pchheader) then - pchheader = path.getrelative(prj.location, prj.pchheader) - end - - local tr = project.getsourcetree(prj) - tree.traverse(tr, { - -- source files are handled at the leaves - onleaf = function(node, depth) - if node.relpath == node.vpath then - _p(2,'', node.relpath) - else - _p(2,'', node.name) - _p(3,'') - - end, - }, false, 1) - end - - function m.extensions(prj) - for cfg in project.eachconfig(prj) do - if cfg.debugenvs and #cfg.debugenvs > 0 then - --Assumption: if gcc is being used then so is gdb although this section will be ignored by - --other debuggers. If using gcc and not gdb it will silently not pass the - --environment arguments to the debugger - if m.getcompilername(cfg) == "gcc" then - _p(3,'') - _p(4,'', p.esc(cfg.longname)) - local args = '' - local sz = #cfg.debugenvs - for idx, v in ipairs(cfg.debugenvs) do - args = args .. 'set env ' .. v - if sz ~= idx then args = args .. ' ' end - end - _p(5,'',args) - _p(4,'') - _p(3,'') - else - error('Sorry at this moment there is no support for debug environment variables with this debugger and codeblocks') - end - end - end - end diff --git a/build/scripts/actions/codeblocks/codeblocks_workspace.lua b/build/scripts/actions/codeblocks/codeblocks_workspace.lua deleted file mode 100644 index 3de935877..000000000 --- a/build/scripts/actions/codeblocks/codeblocks_workspace.lua +++ /dev/null @@ -1,44 +0,0 @@ --- --- Name: codelite/codelite_workspace.lua --- Purpose: Generate a CodeLite workspace. --- Author: Ryan Pusztai --- Modified by: Andrea Zanellato --- Manu Evans --- Created: 2013/05/06 --- Copyright: (c) 2008-2015 Jason Perkins and the Premake project --- - - local p = premake - local project = p.project - local workspace = p.workspace - local tree = p.tree - local codeblocks = p.modules.codeblocks - - codeblocks.workspace = {} - local m = codeblocks.workspace - --- --- Generate a CodeBlocks workspace --- - function m.generate(wks) - p.utf8() - - _p('') - _p('') - _p(1,'', wks.name) - - for prj in workspace.eachproject(wks) do - local fname = path.join(path.getrelative(wks.location, prj.location), prj.name) - local active = iif(prj.project == wks.projects[1], ' active="1"', '') - - _p(2,'', fname, active) - for _,dep in ipairs(project.getdependencies(prj)) do - _p(3,'', path.join(path.getrelative(wks.location, dep.location), dep.name)) - end - - _p(2,'') - end - - _p(1,'') - _p('') - end \ No newline at end of file diff --git a/build/scripts/actions/encodesresources.lua b/build/scripts/actions/encodesresources.lua deleted file mode 100644 index f508c5c69..000000000 --- a/build/scripts/actions/encodesresources.lua +++ /dev/null @@ -1,49 +0,0 @@ -ACTION.Name = "EncodeResources" -ACTION.Description = "Generate a includable header version of resources" - -ACTION.Function = function () - print("Encoding resources ...") - local startClock = os.clock() - local modules = os.matchdirs("../src/Nazara/*") - table.insert(modules, "../SDK/src/NDK") - for k, modulePath in pairs(modules) do - local moduleName - if (modulePath:sub(4, 6) == "src") then - moduleName = modulePath:sub(15, -1) - else - moduleName = "SDK" - end - local files = os.matchfiles(modulePath .. "/Resources/**") - for k, filePath in pairs(files) do - if (filePath:sub(-2) ~= ".h") then - local file = filePath:sub(modulePath:len() + 12, -1) - local resource, err = io.open(filePath, "rb") - if (not resource) then - error("Failed to read resource file " .. file .. ": " .. err) - end - - local resourceContent = resource:read("*a") - resource:close() - - local contentLength = resourceContent:len() - - local headerContentTable = {} - for i = 1, contentLength do - table.insert(headerContentTable, string.format("%d,", resourceContent:byte(i))) - end - local headerContent = table.concat(headerContentTable) - - local header, err = io.open(filePath .. ".h", "w+") - if (not header) then - error("Failed to create header file for " .. file .. ": " .. err) - end - - header:write(headerContent) - header:close() - - print(string.format("%s: %s (raw: %.3g kB, header: %.3g kB)", moduleName, file, contentLength/1024, string.format("%.3g", headerContent:len()/1024))) - end - end - end - print("Finished (took " .. os.clock() - startClock .. "s)") -end diff --git a/build/scripts/actions/generatefeatures.lua b/build/scripts/actions/generatefeatures.lua deleted file mode 100644 index 50c3f6334..000000000 --- a/build/scripts/actions/generatefeatures.lua +++ /dev/null @@ -1,237 +0,0 @@ -function PrintTable ( t, indent, done ) - done = done or {} - indent = indent or 0 - - local txt = {} - for key, value in pairs (t) do - table.insert(txt, string.rep (" ", indent)) - if (type(value) == "table" and not done[value]) then - done [value] = true - table.insert(txt, tostring(key) .. ":" .. "\n") - table.insert(txt, PrintTable (value, indent + 2, done)) - else - table.insert(txt, tostring (key) .. "\t=\t" ) - table.insert(txt, tostring(value) .. "\n" ) - end - end - - return table.concat(txt) -end - -Feature = {} - --- Tables de vérité -local andTable = -{ - {0,0}, - {0,1}, -} -local orTable = -{ - {0,1}, - {1,1}, -} - -local xorTable = -{ - {0,1}, - {1,0}, -} - -local bitFunc = function (a, b, truthTable) - local power = 1 - local c = 0 - while (a > 0 or b > 0) do - c = c + (truthTable[(a % 2)+1][(b % 2)+1] * power) - a = math.floor(a/2) - b = math.floor(b/2) - power = power * 2 - end - - return c -end - -function Feature.AND(a, b) - return bitFunc(a, b, andTable) -end - -function Feature.OR(a, b) - return bitFunc(a, b, orTable) -end - -function Feature.XOR(a, b) - return bitFunc(a, b, xorTable) -end - -Feature.NotApplicable = 0 -Feature.Windows = 2 ^ 0 -Feature.Linux = 2 ^ 1 -Feature.MacOSX = 2 ^ 2 -Feature.RaspberryPi = 2 ^ 3 -Feature.POSIX = Feature.Linux + Feature.MacOSX + Feature.RaspberryPi - -function Feature.CompleteData(tab, requiredPortability) - if (not requiredPortability) then - assert(tab.RequiredPortability) - requiredPortability = tab.RequiredPortability - elseif (tab.RequiredPortability) then - requiredPortability = Feature.OR(requiredPortability, tab.RequiredPortability) - end - - tab.RequiredPortability = requiredPortability - - if (not tab.Portability) then - tab.Portability = Feature.NotApplicable - end - - if (tab.Features) then - local acc = 0 - for k,v in pairs(tab.Features) do - if (type(v) == "string") then - v = {Title = v} - tab.Features[k] = v - end - - Feature.CompleteData(v, requiredPortability) - - v.Progress = v.Progress or 100 - - acc = acc + v.Progress - end - - tab.Progress = acc/#tab.Features - end -end - -function Feature.Generate() - local files = os.matchfiles("scripts/features/*.lua") - - local modules = {} - - for k, filePath in pairs(files) do - local moduleName = filePath:match(".*/(.*).lua") - - local data = dofile(filePath) - Feature.CompleteData(data) - - modules[moduleName] = data - end - - local content = {} - - local contentType = - { - ["(%s*)%%MODULELIST%%"] = Feature.GenerateModuleList, - ["(%s*)%%MODULEDESCRIPTION%%"] = Feature.GenerateModuleDescriptions, - ["(%s*)%%DATE%%"] = function (dontcare, space, content) - table.insert(content, string.format("%s%s", space, os.date("%d/%m/%Y"))) - end, - } - - local index = io.open("scripts/features/index_template.html") - for line in index:lines() do - local matched = false - for k,v in pairs(contentType) do - local space = line:match(k) - if (space) then - matched = true - v(modules, space, content) - break - end - end - - if (not matched) then - table.insert(content, line) - end - end - - io.open("scripts/features/index.html", "w+"):write(table.concat(content, "\n")) -end - -function Feature.Interpolate(from, to, p) - return from + (to - from)*p -end - -function Feature.ComputeColor(progress) - local stable = {0, 200, 0} - local partial = {255, 127, 0} - local unusable = {255, 0, 0} - - local a, b, p - if (progress < 20) then - a = unusable - b = partial - p = progress/20.0 - else - a = partial - b = stable - p = math.min(20 * 1.020321705^(progress - 20), 100.0)/100.0 -- Je me complique certainement la vie pour ce qui est d'avoir une interpolation exponentielle, mais ça remonte tout ça ... - end - - local color = {nil, nil, nil} - for i = 1, 3 do - color[i] = Feature.Interpolate(a[i], b[i], p) - end - - return color -end - -function Feature.GenerateModuleList(modules, space, content) - for k,v in pairs(modules) do - local c = Feature.ComputeColor(v.Progress) - - table.insert(content, string.format([[%s]], space)) - table.insert(content, string.format([[%s %s]], space, k, v.Title)) - table.insert(content, string.format([[%s %d%%]], space, c[1], c[2], c[3], v.Progress)) - table.insert(content, string.format([[%s]], space)) - end -end - -function Feature.GenerateModuleDescriptions(modules, space, content) - for k,v in pairs(modules) do - table.insert(content, string.format([[%s
]], space)) - table.insert(content, string.format([[%s
]], space, k, v.Title)) - table.insert(content, string.format([[%s %s (%s) : %d%%]], space, k, v.Title, v.LibName, math.floor(v.Progress))) - - table.insert(content, string.format([[%s

Fonctionnalités:

]], space)) - Feature.GenerateFeatureList(v.Features, space .. "\t\t", content) - - table.insert(content, string.format([[%s
]], space)) - end -end - -function Feature.GenerateFeatureList(featureTable, space, content) - table.insert(content, string.format("%s
    ", space)) - for k,v in pairs(featureTable) do - local progress = v.Progress - local c = Feature.ComputeColor(progress) - local desc = (progress == 100) and "" or string.format(" (%d%%)", math.floor(progress)) - - table.insert(content, string.format("%s
  • ", space)) - table.insert(content, string.format([[%s %s%s]], space, c[1], c[2], c[3], v.Title, desc)) - - if (v.Description) then - table.insert(content, string.format([[%s
    %s]], space, v.Description)) - end - - if (v.Features) then - Feature.GenerateFeatureList(v.Features, space .. "\t\t\t", content) - end - - if (v.Note) then - table.insert(content, string.format([[%s
    Note: %s]], space, v.Note)) - end - - if (v.Portability ~= Feature.NotApplicable and Feature.AND(v.Portability, v.RequiredPortability) ~= v.RequiredPortability) then - table.insert(content, string.format([[%s
    Il manque une implémentation sur au moins un des OS supportés]], space)) - end - - table.insert(content, string.format("%s
  • ", space)) - end - table.insert(content, string.format("%s
", space)) -end - -ACTION.Name = "GenerateFeatures" -ACTION.Description = "Generate a web page describing each module's feature" - -ACTION.Function = Feature.Generate diff --git a/build/scripts/actions/generateheaders.lua b/build/scripts/actions/generateheaders.lua deleted file mode 100644 index c8e90ebe0..000000000 --- a/build/scripts/actions/generateheaders.lua +++ /dev/null @@ -1,116 +0,0 @@ -ACTION.Name = "GenerateHeaders" -ACTION.Description = "Generate a global header for each module" - -ACTION.ModuleExcludes = {} -ACTION.ModuleExcludes["ConfigCheck.hpp"] = true -ACTION.ModuleExcludes["Debug.hpp"] = true -ACTION.ModuleExcludes["DebugOff.hpp"] = true -ACTION.ModuleExcludes["ThreadSafety.hpp"] = true -ACTION.ModuleExcludes["ThreadSafetyOff.hpp"] = true - -local action = ACTION -ACTION.Function = function () - local paths = {} - - local modules = os.matchdirs("../include/Nazara/*") - for k, modulePath in pairs(modules) do - local moduleName = modulePath:match(".*/(.*)") - - local config, err = io.open(modulePath .. "/Config.hpp", "r") - local head = "" - if (not config) then - error("Failed to read config file: " .. err) - end - - for line in config:lines() do - if (line == "#pragma once") then -- Stop before including the #pragma once as it's already written automatically - break - end - head = head .. line .. "\n" - end - - config:close() - - table.insert(paths, { - Excludes = action.ModuleExcludes, - Header = head, - HeaderGuard = "NAZARA_GLOBAL_" .. moduleName:upper() .. "_HPP", - Name = "Nazara" .. moduleName, - SearchDir = modulePath, - Target = modulePath .. ".hpp", - TopDir = "Nazara" - }) - end - - table.insert(paths, { - Excludes = { - ["DeviceFunctions.hpp"] = true, - ["GlobalFunctions.hpp"] = true, - ["InstanceFunctions.hpp"] = true, - }, - HeaderGuard = "NAZARA_GLOBAL_VULKANRENDERER_WRAPPER_HPP", - Name = "Vulkan wrapper", - SearchDir = "../include/Nazara/VulkanRenderer/Wrapper", - TopDir = "Nazara", - Target = "../include/Nazara/VulkanRenderer/Wrapper.hpp" - }) - - table.insert(paths, { - Excludes = {}, - HeaderGuard = "NDK_COMPONENTS_GLOBAL_HPP", - Name = "NDK Components", - SearchDir = "../SDK/include/NDK/Components", - TopDir = "NDK", - Target = "../SDK/include/NDK/Components.hpp" - }) - - table.insert(paths, { - Excludes = {}, - HeaderGuard = "NDK_SYSTEMS_GLOBAL_HPP", - Name = "NDK Systems", - SearchDir = "../SDK/include/NDK/Systems", - TopDir = "NDK", - Target = "../SDK/include/NDK/Systems.hpp" - }) - - table.insert(paths, { - Excludes = {}, - HeaderGuard = "NDK_WIDGETS_GLOBAL_HPP", - Name = "NDK Widgets", - SearchDir = "../SDK/include/NDK/Widgets", - TopDir = "NDK", - Target = "../SDK/include/NDK/Widgets.hpp" - }) - - for k,v in ipairs(paths) do - print(v.Name) - local header, err = io.open(v.Target, "w+") - if (not header) then - error("Failed to create header file (" .. v.Target .. "): " .. err) - end - - header:write("// This file was automatically generated\n\n") - if (v.Header) then - header:write(v.Header) - end - - header:write("#pragma once\n\n") - header:write("#ifndef " .. v.HeaderGuard .. "\n") - header:write("#define " .. v.HeaderGuard .. "\n\n") - - local files = os.matchfiles(v.SearchDir .. "/*.hpp") - local count = 0 - for k, filePath in pairs(files) do - local include, fileName = filePath:match(".*(" .. v.TopDir .. "/.*/(.*))") - if (not v.Excludes[fileName]) then - header:write("#include <" .. include .. ">\n") - count = count + 1 - end - end - - header:write("\n#endif // " .. v.HeaderGuard .. "\n") - header:close() - - print(string.format("-#include count: %d", count)) - end -end diff --git a/build/scripts/actions/package.lua b/build/scripts/actions/package.lua deleted file mode 100644 index f263f8faf..000000000 --- a/build/scripts/actions/package.lua +++ /dev/null @@ -1,200 +0,0 @@ -newoption({ - trigger = "pack-libdir", - description = "Specifies the subdirectory in lib/ to be used when packaging the project" -}) - -ACTION.Name = "Package" -ACTION.Description = "Pack Nazara binaries/include/lib together" - -ACTION.Function = function () - local libDir = _OPTIONS["pack-libdir"] - if (not libDir or #libDir == 0) then - local libDirs = os.matchdirs("../lib/*") - if (#libDirs > 1) then - error("More than one subdirectory was found in the lib directory, please use the --pack-libdir command to clarify which directory should be used") - elseif (#libDirs == 0) then - error("No subdirectory was found in the lib directory, have you built the engine yet?") - else - libDir = path.getname(libDirs[1]) - print("No directory was set by the --pack-libdir command, \"" .. libDir .. "\" will be used") - end - end - - local realLibDir = "../lib/" .. libDir .. "/" - if (not os.isdir(realLibDir)) then - error(string.format("\"%s\" doesn't seem to be an existing directory", realLibDir)) - end - - local archEnabled = { - ["x64"] = false, - ["x86"] = false - } - - local enabledArchs = {} - for k,v in pairs(os.matchdirs(realLibDir .. "*")) do - local arch = path.getname(v) - if (archEnabled[arch] ~= nil) then - archEnabled[arch] = true - table.insert(enabledArchs, arch) - else - print("Unknown directory " .. v .. " found, ignored") - end - end - enabledArchs = table.concat(enabledArchs, ", ") - print(enabledArchs .. " arch found") - - local packageDir = "../package/" - - local copyTargets = { - { -- Engine headers - Masks = {"**.hpp", "**.inl"}, - Source = "../include/", - Target = "include/" - }, - { -- SDK headers - Masks = {"**.hpp", "**.inl"}, - Source = "../SDK/include/", - Target = "include/" - }, - { -- Examples files - Masks = {"**.hpp", "**.inl", "**.cpp"}, - Source = "../examples/", - Target = "examples/" - }, - { -- Demo resources - Masks = {"**.*"}, - Source = "../examples/bin/resources/", - Target = "examples/bin/resources/" - }, - -- Unit test sources - { - Masks = {"**.hpp", "**.inl", "**.cpp"}, - Source = "../tests/", - Target = "tests/src/" - }, - -- Unit test resources - { - Masks = {"**.*"}, - Source = "../tests/resources/", - Target = "tests/resources/" - } - } - - local binFileMasks - local libFileMasks - local exeFileExt - local exeFilterFunc - if (os.ishost("windows")) then - binFileMasks = {"**.dll", "**.pdb"} - libFileMasks = {"**.lib", "**.a"} - exeFileExt = ".exe" - exeFilterFunc = function (filePath) return true end - else - if (os.ishost("macosx")) then - binFileMasks = {"**.dynlib"} - else - binFileMasks = {"**.so"} - end - - libFileMasks = {"**.a"} - exeFileExt = "" - exeFilterFunc = function (filePath) return path.getextension(filePath):contains('/') end - end - - for arch, enabled in pairs(archEnabled) do - if (enabled) then - local archLibSrc = realLibDir .. arch .. "/" - local arch3rdPartyBinSrc = "../thirdparty/lib/common/" .. arch .. "/" - local archBinDst = "bin/" .. arch .. "/" - local archLibDst = "lib/" .. arch .. "/" - - -- Engine/SDK binaries - table.insert(copyTargets, { - Masks = binFileMasks, - Source = archLibSrc, - Target = archBinDst - }) - - -- Engine/SDK libraries - table.insert(copyTargets, { - Masks = libFileMasks, - Source = archLibSrc, - Target = archLibDst - }) - - -- 3rd party binary dep - table.insert(copyTargets, { - Masks = binFileMasks, - Source = arch3rdPartyBinSrc, - Target = archBinDst - }) - end - end - - -- Demo executable - table.insert(copyTargets, { - Masks = {"Demo*" .. exeFileExt}, - Filter = exeFilterFunc, - Source = "../examples/bin/", - Target = "examples/bin/" - }) - - -- Unit test - table.insert(copyTargets, { - Masks = {"*" .. exeFileExt}, - Filter = exeFilterFunc, - Source = "../tests/", - Target = "tests/" - }) - - -- Processing - os.mkdir(packageDir) - - local size = 0 - for k,v in pairs(copyTargets) do - local target = packageDir .. v.Target - local includePrefix = v.Source - - local targetFiles = {} - for k, mask in pairs(v.Masks) do - print(includePrefix .. mask .. " => " .. target) - local files = os.matchfiles(includePrefix .. mask) - if (v.Filter) then - for k,path in pairs(files) do - if (not v.Filter(path)) then - files[k] = nil - end - end - end - - targetFiles = table.join(targetFiles, files) - end - - for k,v in pairs(targetFiles) do - local relPath = v:sub(#includePrefix + 1) - - local targetPath = target .. relPath - local targetDir = path.getdirectory(targetPath) - - if (not os.isdir(targetDir)) then - local ok, err = os.mkdir(targetDir) - if (not ok) then - print("Failed to create directory \"" .. targetDir .. "\": " .. err) - end - end - - local ok, err = os.copyfile(v, targetPath) - if (not ok) then - print("Failed to copy \"" .. v .. "\" to \"" .. targetPath .. "\": " .. err) - end - - local stat = os.stat(targetPath) - if (stat) then - size = size + stat.size - end - end - end - - local config = libDir .. " - " .. enabledArchs - print(string.format("Package successfully created at \"%s\" (%u MB, %s)", packageDir, size // (1024 * 1024), config)) -end diff --git a/build/scripts/common.lua b/build/scripts/common.lua deleted file mode 100644 index 1000c7a16..000000000 --- a/build/scripts/common.lua +++ /dev/null @@ -1,1239 +0,0 @@ -NazaraBuild = {} - --- I wish Premake had a way to know the compiler in advance -local clangGccActions = "action:" .. table.concat({"codeblocks", "codelite", "gmake*", "xcode3", "xcode4"}, " or ") - -function NazaraBuild:AddExecutablePath(path) - self.ExecutableDir[path] = true - - self:AddInstallPath(path) -end - -function NazaraBuild:AddInstallPath(path) - self.InstallDir[path] = true -end - -function NazaraBuild:FilterLibDirectory(prefix, func) - filter({"action:codeblocks or codelite or gmake*", "architecture:x86", "system:Windows"}) - func(prefix .. "mingw/x86") - - filter({"action:codeblocks or codelite or gmake*", "architecture:x86_64", "system:Windows"}) - func(prefix .. "mingw/x64") - - filter({"action:codeblocks or codelite or gmake*", "architecture:x86", "system:not Windows"}) - func(prefix .. "gmake/x86") - - filter({"action:codeblocks or codelite or gmake*", "architecture:x86_64", "system:not Windows"}) - func(prefix .. "gmake/x64") - - filter({"action:vs*", "architecture:x86"}) - func(prefix .. "msvc/x86") - - filter({"action:vs*", "architecture:x86_64"}) - func(prefix .. "msvc/x64") - - filter({"action:xcode3 or xcode4", "architecture:x86"}) - func(prefix .. "xcode/x86") - - filter({"action:xcode3 or xcode4", "architecture:x86_64"}) - func(prefix .. "xcode/x64") - - filter({}) -end - -function NazaraBuild:Execute() - if (_ACTION == nil) then -- If no action is specified, the user probably only wants to know how all of this works - return - end - - local platformData - if (os.is64bit()) then - platformData = {"x64", "x86"} - else - platformData = {"x86", "x64"} - end - - if (self.Actions[_ACTION] == nil) then - -- Start defining projects - workspace("NazaraEngine") - platforms(platformData) - - startproject "DemoFirstScene" - location(_ACTION) - - do - local linkTypes = {"Dynamic"} -- {"Static", "Dynamic"} - local configs = {} - for k,linkType in pairs(linkTypes) do - for k,config in pairs(self.Config["Configurations"]) do - table.insert(configs, config .. linkType) - end - end - - configurations(configs) - end - - if (self.Config["PremakeProject"] and os.ishost("windows")) then - group("_Premake") - - local commandLine = "premake5.exe " .. table.concat(_ARGV, ' ') - project("Regenerate premake") - kind("Utility") - prebuildcommands("cd .. && " .. commandLine) - end - - -- Extern libraries - if (self.Config["BuildDependencies"]) then - group("Thirdparties") - - for k, libTable in ipairs(self.OrderedExtLibs) do - project(libTable.Name) - - self:PreconfigGenericProject() - - language(libTable.Language) - location(_ACTION .. "/thirdparty") - - files(libTable.Files) - excludes(libTable.FilesExcluded) - - if (libTable.DisableWarnings) then - warnings("Off") - end - - defines(libTable.Defines) - flags(libTable.Flags) - kind("StaticLib") -- Force them as static libs - includedirs("../thirdparty/include") - includedirs(libTable.Includes) - links(libTable.Libraries) - libdirs("../thirdparty/lib/common") - - self:FilterLibDirectory("../thirdparty/genlib/", targetdir) -- For generated libraries - - filter(clangGccActions) - buildoptions("-U__STRICT_ANSI__") - - filter("architecture:x86") - libdirs(libTable.LibraryPaths.x86) - - filter("architecture:x86_64") - libdirs(libTable.LibraryPaths.x64) - - for k,v in pairs(libTable.ConfigurationLibraries) do - filter(k) - links(v) - end - - filter({}) - - if (libTable.Custom) then - libTable.Custom() - end - - self:PostconfigGenericProject() - end - end - - -- Modules - group("Engine Modules") - - if (_OPTIONS["united"]) then - project("NazaraEngine") - - self:PreconfigNazaraProject() - end - - for k, moduleTable in ipairs(self.OrderedModules) do - if (not _OPTIONS["united"]) then - project("Nazara" .. moduleTable.Name) - - self:PreconfigNazaraProject() - end - - location(_ACTION .. "/modules") - - includedirs({ - "../include", - "../src/", - "../thirdparty/include" - }) - - if (os.ishost("macosx")) then - includedirs({ - "../include", - "../src/", - "../thirdparty/include", - "/usr/local/include/" --brew - }) - end - - files(moduleTable.Files) - excludes(moduleTable.FilesExcluded) - - defines(moduleTable.Defines) - flags(moduleTable.Flags) - includedirs(moduleTable.Includes) - links(moduleTable.Libraries) - - libdirs({ - "../thirdparty/lib/common", - "../lib" - }) - - if (os.ishost("macosx")) then - libdirs({ - "../thirdparty/lib/common", - "../lib", - "/usr/local/lib" --brew - }) - end - - -- Output to lib/conf/arch - self:FilterLibDirectory("../lib/", targetdir) - - -- Copy the module binaries to the example folder - self:MakeInstallCommands(moduleTable) - - filter("architecture:x86") - libdirs(moduleTable.LibraryPaths.x86) - - filter("architecture:x86_64") - libdirs(moduleTable.LibraryPaths.x64) - - for k,v in pairs(moduleTable.ConfigurationLibraries) do - filter(k) - links(v) - end - - filter({}) - - if (moduleTable.Custom) then - moduleTable.Custom() - end - - if (not _OPTIONS["united"]) then - self:PostconfigNazaraProject() - end - end - - if (_OPTIONS["united"]) then - self:PostconfigNazaraProject() - end - - -- Tools - group("Engine SDK - Tools") - - for k, toolTable in ipairs(self.OrderedTools) do - local prefix = "Nazara" - if (toolTable.Kind == "plugin") then - prefix = "Plugin" - end - - project(prefix .. toolTable.Name) - - self:PreconfigNazaraProject() - - location(_ACTION .. "/tools") - - if (toolTable.Kind == "plugin" or toolTable.Kind == "library") then - kind("SharedLib") - - -- Copy the tool binaries to the example folder - self:MakeInstallCommands(toolTable) - elseif (toolTable.Kind == "application") then - debugdir(toolTable.TargetDirectory) - targetdir(toolTable.TargetDirectory) - if (toolTable.EnableConsole) then - kind("ConsoleApp") - else - kind("WindowedApp") - end - else - assert(false, "Invalid tool kind") - end - - includedirs({ - "../include", - "../thirdparty/include" - }) - - libdirs({ - "../thirdparty/lib/common", - "../lib" - }) - - files(toolTable.Files) - excludes(toolTable.FilesExcluded) - - defines(toolTable.Defines) - flags(toolTable.Flags) - includedirs(toolTable.Includes) - links(toolTable.Libraries) - - -- Output to lib/conf/arch - if (toolTable.Kind == "library") then - self:FilterLibDirectory(toolTable.TargetDirectory .. "/", targetdir) - elseif (toolTable.Kind == "plugin") then - self:FilterLibDirectory("../plugins/lib/", targetdir) - end - - filter("architecture:x86") - libdirs(toolTable.LibraryPaths.x86) - - filter("architecture:x86_64") - libdirs(toolTable.LibraryPaths.x64) - - for k,v in pairs(toolTable.ConfigurationLibraries) do - filter(k) - links(v) - end - - filter({}) - - self:PostconfigNazaraProject() - - if (toolTable.Custom) then - toolTable.Custom() - end - end - - group("Examples") - - for k, exampleTable in ipairs(self.OrderedExamples) do - local destPath = "../examples/bin" - - project("Demo" .. exampleTable.Name) - - self:PreconfigNazaraProject() - - location(_ACTION .. "/examples") - - if (exampleTable.Kind == "plugin" or exampleTable.Kind == "library") then - kind("SharedLib") - - self:MakeInstallCommands(toolTable) - elseif (exampleTable.Kind == "application") then - debugdir(exampleTable.TargetDirectory) - if (exampleTable.EnableConsole) then - kind("ConsoleApp") - else - kind("WindowedApp") - end - else - assert(false, "Invalid tool Kind") - end - - debugdir(destPath) - includedirs({ - "../include", - "../thirdparty/include", - exampleTable.Includes - }) - libdirs({ - "../lib", - exampleTable.LibDir - }) - - files(exampleTable.Files) - excludes(exampleTable.FilesExcluded) - - defines(exampleTable.Defines) - flags(exampleTable.Flags) - links(exampleTable.Libraries) - targetdir(destPath) - - for k,v in pairs(exampleTable.ConfigurationLibraries) do - filter(k) - links(v) - end - - filter({}) - - if (exampleTable.Custom) then - exampleTable.Custom() - end - - self:PostconfigNazaraProject() - end - end -end - -function NazaraBuild:GetConfig() - return self.Config -end - -function NazaraBuild:GetDependency(infoTable, name) - local projectName = name:match("Nazara(%w+)") - if (projectName) then - -- tool or module - local moduleTable = self.Modules[projectName:lower()] - if (moduleTable) then - return moduleTable - else - local toolTable = self.Tools[projectName:lower()] - if (toolTable) then - return toolTable - end - end - else - return self.ExtLibs[name:lower()] - end -end - -function NazaraBuild:Initialize() - self.Actions = {} - self.Examples = {} - self.ExecutableDir = {} - self.ExtLibs = {} - self.InstallDir = {} - self.Modules = {} - self.Tools = {} - - self.Config = {} - self:LoadConfig() - - -- Actions - modules = os.matchfiles("scripts/actions/*.lua") - for k,v in pairs(modules) do - local f, err = loadfile(v) - if (f) then - ACTION = {} - - f() - - local succeed, err = self:RegisterAction(ACTION) - if (not succeed) then - print("Unable to register action: " .. err) - end - else - print("Unable to load action file: " .. err) - end - end - ACTION = nil - - -- Extern libraries - local extlibs = os.matchfiles("../thirdparty/build/*.lua") - for k,v in pairs(extlibs) do - local f, err = loadfile(v) - if (f) then - LIBRARY = {} - self:SetupExtlibTable(LIBRARY) - - f() - - local succeed, err = self:RegisterExternLibrary(LIBRARY) - if (not succeed) then - print("Unable to register extern library: " .. err) - end - else - print("Unable to load extern library file: " .. err) - end - end - LIBRARY = nil - - -- Then the modules - local modules = os.matchfiles("scripts/modules/*.lua") - for k,v in pairs(modules) do - local moduleName = v:match(".*/(.*).lua") - local moduleNameLower = moduleName:lower() - - local f, err = loadfile(v) - if (f) then - MODULE = {} - self:SetupModuleTable(MODULE) - Config = self.Config - - f() - - local succeed, err = self:RegisterModule(MODULE) - if (not succeed) then - print("Unable to register module: " .. err) - end - else - print("Unable to load module file: " .. err) - end - end - MODULE = nil - - -- Continue with the tools (ex: SDK) - local tools = os.matchfiles("scripts/tools/*.lua") - for k,v in pairs(tools) do - local toolName = v:match(".*/(.*).lua") - local toolNameLower = toolName:lower() - - local f, err = loadfile(v) - if (f) then - TOOL = {} - self:SetupToolTable(TOOL) - - f() - - local succeed, err = self:RegisterTool(TOOL) - if (not succeed) then - print("Unable to register tool " .. tostring(TOOL.Name) .. ": " .. err) - end - else - print("Unable to load tool file " .. v .. ": " .. err) - end - end - TOOL = nil - - -- Examples - if (self.Config["BuildExamples"]) then - local examples = os.matchdirs("../examples/*") - for k,v in pairs(examples) do - local dirName = v:match(".*/(.*)") - if (dirName ~= "bin" and dirName ~= "build") then - local f, err = loadfile(v .. "/build.lua") - if (f) then - EXAMPLE = {} - EXAMPLE.Directory = dirName - self:SetupExampleTable(EXAMPLE) - - f() - - local succeed, err = self:RegisterExample(EXAMPLE) - if (not succeed) then - print("Unable to register example: " .. err) - end - else - print("Unable to load example file: " .. err) - end - end - end - EXAMPLE = nil - end - - -- Once everything is registred, let's process all the tables - self.OrderedExamples = {} - self.OrderedExtLibs = {} - self.OrderedModules = {} - self.OrderedTools = {} - local tables = {self.ExtLibs, self.Modules, self.Tools, self.Examples} - local orderedTables = {self.OrderedExtLibs, self.OrderedModules, self.OrderedTools, self.OrderedExamples} - for k,projects in ipairs(tables) do - -- Begin by resolving every project (because of dependencies in the same category) - for projectId,projectTable in pairs(projects) do - self:Resolve(projectTable) - end - - for projectId,projectTable in pairs(projects) do - if (self:Process(projectTable)) then - table.insert(orderedTables[k], projectTable) - else - print("Rejected " .. projectTable.Name .. " " .. string.lower(projectTable.Category) .. ": " .. projectTable.ExcludeReason) - end - end - - table.sort(orderedTables[k], function (a, b) return a.Name < b.Name end) - end -end - -function NazaraBuild:LoadConfigFile(path, configTable) - local f = io.open(path, "r") - if (f) then - local content = f:read("*a") - f:close() - - local func, err = load(content, "Config file", "t", configTable) - if (func) then - local status, err = pcall(func) - if (status) then - return true - else - print("Failed to load " .. path .. ": " .. err) - end - else - print("Failed to parse " .. path .. ": " .. err) - end - else - print("Failed to open " .. path) - end - - return false -end - -function NazaraBuild:LoadConfig() - if (not self:LoadConfigFile("config.lua", self.Config) and not self:LoadConfigFile("config.lua.default", self.Config)) then - error("Failed to load config file") - end - - local configTable = self.Config - local AddBoolOption = function (option, name, description) - newoption({ - trigger = name, - description = description - }) - - local str = _OPTIONS[name] - if (str) then - if (#str == 0 or str == "1" or str == "yes" or str == "true") then - configTable[option] = true - elseif (str == "0" or str == "no" or str == "false") then - configTable[option] = false - else - error("Invalid entry for " .. name .. " option: \"" .. str .. "\"") - end - end - end - - local AddStringOption = function (option, name, description) - newoption({ - trigger = name, - description = description - }) - - local str = _OPTIONS[name] - if (str) then - configTable[option] = str - end - end - - AddBoolOption("BuildDependencies", "with-extlibs", "Builds the extern libraries") - AddBoolOption("BuildExamples", "with-examples", "Builds the examples") - AddBoolOption("PremakeProject", "premakeproject", "Add a PremakeProject as a shortcut to call Premake") - AddBoolOption("ServerMode", "server", "Excludes client-only modules/tools/examples") - AddBoolOption("UniteModules", "united", "Builds all the modules as one united library") - AddBoolOption("PlatformSDL2", "platform-sdl2", "Use SDL2 instead of native APIs") - - -- AdditionalCompilationOptions - do - newoption({ - trigger = "compile-options", - description = "Specify additionnal compilation options to be added to every generated project." - }) - - configTable["AdditionalCompilationOptions"] = configTable["AdditionalCompilationOptions"] or "" - if (_OPTIONS["compile-options"] ~= nil) then - configTable["AdditionalCompilationOptions"] = configTable["AdditionalCompilationOptions"] .. ";" .. _OPTIONS["compile-options"] - end - - local configs = {} - local paths = string.explode(configTable["AdditionalCompilationOptions"], ";") - for k,v in pairs(paths) do - if (#v > 0) then - table.insert(configs, v) - end - end - - configTable["AdditionalCompilationOptions"] = configs - end - - -- Configurations - do - newoption({ - trigger = "configurations", - description = "Override configurations target by a new set, separated by commas." - }) - - configTable["Configurations"] = configTable["Configurations"] or "" - if (_OPTIONS["configurations"] ~= nil) then - configTable["Configurations"] = _OPTIONS["configurations"] - end - - local configs = {} - local validConfigs = {"Debug", "Release", "ReleaseWithDebug"} - local paths = string.explode(configTable["Configurations"], ",") - for k,v in pairs(paths) do - v = v:match("^%s*(.-)%s*$") -- Trim - if (#v > 0) then - if (table.contains(validConfigs, v)) then - table.insert(configs, v) - else - error("Invalid entry for configurations option: \"" .. v .. "\"") - end - end - end - - if (#configs == 0) then - error("Invalid entry for configurations option: no option") - end - - configTable["Configurations"] = configs - end - - -- InstallDir - do - newoption({ - trigger = "install-path", - description = "Setup additionnals install directories (library binaries will be copied there), separated by commas" - }) - - configTable["InstallDir"] = configTable["InstallDir"] or "" - if (_OPTIONS["install-path"] ~= nil) then - configTable["InstallDir"] = configTable["InstallDir"] .. ";" .. _OPTIONS["install-path"] - end - - local paths = string.explode(configTable["InstallDir"], ";") - for k,v in pairs(paths) do - if (#v > 0) then - self:AddInstallPath(v) - end - end - end -end - -function NazaraBuild:MakeInstallCommands(infoTable) - if (os.ishost("windows")) then - filter("kind:SharedLib") - - postbuildmessage("Copying " .. infoTable.Name .. " library and its dependencies to install/executable directories...") - - -- Copy built file to install directory - local installCommands = {} - for installPath,_ in pairs(self.InstallDir) do - local destPath = path.translate(path.isabsolute(installPath) and installPath or "../../" .. installPath) - table.insert(installCommands, [[xcopy "%{path.translate(cfg.buildtarget.relpath)}" "]] .. destPath .. [[\" /E /Y]]) - end - table.sort(installCommands) - - for k,command in pairs(installCommands) do - postbuildcommands({command}) - end - - -- Copy additional dependencies to executable directories too - for k,fileName in pairs(table.join(infoTable.Libraries, infoTable.DynLib)) do - local paths = {} - for k,v in pairs(infoTable.BinaryPaths.x86) do - table.insert(paths, {"x86", v .. "/" .. fileName .. ".dll"}) - table.insert(paths, {"x86", v .. "/lib" .. fileName .. ".dll"}) - end - - for k,v in pairs(infoTable.BinaryPaths.x64) do - table.insert(paths, {"x86_64", v .. "/" .. fileName .. ".dll"}) - table.insert(paths, {"x86_64", v .. "/lib" .. fileName .. ".dll"}) - end - - for k,v in pairs(paths) do - local arch = v[1] - local srcPath = v[2] - if (os.isfile(srcPath)) then - if (infoTable.Kind == "plugin") then - srcPath = "../../" .. srcPath - end - - filter("architecture:" .. arch) - - local executableCommands = {} - for execPath,_ in pairs(self.ExecutableDir) do - local srcPath = path.isabsolute(srcPath) and path.translate(srcPath) or [[%{path.translate(cfg.linktarget.relpath:sub(1, -#cfg.linktarget.name - 1) .. "../../]] .. srcPath .. [[")}]] - local destPath = path.translate(path.isabsolute(execPath) and execPath or "../../" .. execPath) - table.insert(executableCommands, [[xcopy "]] .. srcPath .. [[" "]] .. destPath .. [[\" /E /Y]]) - end - - table.sort(executableCommands) - - for k,command in pairs(executableCommands) do - postbuildcommands({command}) - end - end - end - end - - filter({}) - end -end - -local PosixOSes = { - ["bsd"] = true, - ["linux"] = true, - ["macosx"] = true, - ["solaris"] = true -} - -local function ProcessOption(libName, option, enable) - return libName:gsub("%%" .. option .. "%((.+)%)", enable and "%1" or "") -end - -local function HandleLib(infoTable, libName) - local debugDynamic = ProcessOption(ProcessOption(libName, "d", true), "s", false) - local debugStatic = ProcessOption(ProcessOption(libName, "d", true), "s", true) - local releaseStatic = ProcessOption(ProcessOption(libName, "d", false), "s", true) - local releaseDynamic = ProcessOption(ProcessOption(libName, "d", false), "s", false) - - table.insert(infoTable.ConfigurationLibraries.DebugStatic, debugStatic) - table.insert(infoTable.ConfigurationLibraries.ReleaseStatic, releaseStatic) - table.insert(infoTable.ConfigurationLibraries.ReleaseWithDebugStatic, releaseStatic) - table.insert(infoTable.ConfigurationLibraries.DebugDynamic, debugDynamic) - table.insert(infoTable.ConfigurationLibraries.ReleaseDynamic, releaseDynamic) - table.insert(infoTable.ConfigurationLibraries.ReleaseWithDebugDynamic, releaseDynamic) -end - -function NazaraBuild:Process(infoTable) - if (infoTable.Excluded) then - return false - end - - local libraries = {} - for k, library in pairs(infoTable.Libraries) do - local libraryTable = self:GetDependency(infoTable, library) - if (libraryTable) then - if (libraryTable.Excluded) then - infoTable.Excluded = true - infoTable.ExcludeReason = "depends on excluded " .. library .. " " .. libraryTable.Category:lower() - return false - end - - if (libraryTable.Type == "Module") then - if (_OPTIONS["united"]) then - library = "NazaraEngine" - else - library = "Nazara" .. libraryTable.Name .. "%s(-s)%d(-d)" - end - - if (not self.Config["UniteModules"] or infoTable.Type ~= "Module") then - HandleLib(infoTable, library) - end - elseif (libraryTable.Type == "ExternLib") then - library = libraryTable.Name - - if (self.Config["BuildDependencies"]) then - table.insert(libraries, library) - else - HandleLib(infoTable, library) - end - elseif (libraryTable.Type == "Tool") then - library = "Nazara" .. libraryTable.Name .. "%s(-s)%d(-d)" - - -- Import tools includes - for k,v in ipairs(libraryTable.Includes) do - table.insert(infoTable.Includes, v) - end - - -- And libraries - for k, v in pairs(libraryTable.Libraries) do - table.insert(infoTable.Libraries, v) - end - - for config, libs in pairs(libraryTable.ConfigurationLibraries) do - for k,v in pairs(libs) do - table.insert(infoTable.ConfigurationLibraries[config], v) - end - end - - HandleLib(infoTable, library) - else - infoTable.Excluded = true - infoTable.ExcludeReason = "dependency " .. library .. " has invalid type \"" .. libraryTable.Type .. "\"" - return false - end - else - HandleLib(infoTable, library) - end - end - infoTable.Libraries = libraries - - for k,v in pairs(infoTable) do - local target = k:match("Os(%w+)") - if (target) then - local targetTable = infoTable[target] - if (targetTable) then - local excludeTargetTable = infoTable[target .. "Excluded"] - for platform, defineTable in pairs(v) do - platform = string.lower(platform) - if (platform == "posix") then - local osname = os.target() - if (PosixOSes[osname]) then - platform = osname - end - end - - if (os.istarget(platform)) then - for k,v in ipairs(defineTable) do - table.insert(targetTable, v) - end - elseif (excludeTargetTable) then - for k,v in ipairs(defineTable) do - table.insert(excludeTargetTable, v) - end - end - end - - infoTable[k] = nil - end - end - end - - if (infoTable.Kind == "application") then - self:AddExecutablePath(infoTable.TargetDirectory) - end - - if (infoTable.Validate) then - local ret, err = infoTable:Validate() - if (not ret) then - infoTable.Excluded = true - infoTable.ExcludeReason = "validation failed: " .. err - return false - end - end - - return true -end - -function NazaraBuild:PreconfigGenericProject() - flags({ - "MultiProcessorCompile", - "NoMinimalRebuild", - "RelativeLinks", - "ShadowedVariables", - "UndefinedIdentifiers" - }) - - cppdialect("C++17") - warnings("Extra") - - self:FilterLibDirectory("../thirdparty/genlib/", libdirs) - self:FilterLibDirectory("../thirdparty/lib/", libdirs) - - -- Fixes Premake stuff - filter({"kind:SharedLib", clangGccActions}) - implibprefix("lib") - filter({"kind:*Lib", clangGccActions, "system:Windows"}) - implibextension(".a") - filter({"kind:StaticLib", clangGccActions}) - targetextension(".a") - targetprefix("lib") - - -- General configuration - filter("kind:*Lib") - pic("On") - - filter({"kind:StaticLib", "configurations:Debug*"}) - targetsuffix("-s-d") - - filter({"kind:StaticLib", "configurations:Release*"}) - targetsuffix("-s") - - filter({"kind:SharedLib", "configurations:Debug*"}) - targetsuffix("-d") - - filter("configurations:*Debug*") - optimize("Debug") - symbols("On") - - filter("configurations:not *Debug*") - omitframepointer("On") - - -- Setup some optimizations for release - filter("configurations:Release*") - defines("NDEBUG") - optimize("Speed") - vectorextensions("SSE2") - - filter("configurations:*Static") - kind("StaticLib") - - filter("configurations:*Dynamic") - kind("SharedLib") - - -- Enable MSVC conformance (not required but better) and some extra warnings - filter("action:vs*") - buildoptions({"/permissive-", "/Zc:__cplusplus", "/Zc:referenceBinding", "/Zc:throwingNew"}) - --enablewarnings("4062") -- switch case not handled - buildoptions("/w44062") -- looks like enablewarnings is broken currently for msvc - - -- Enable SSE math and vectorization optimizations - filter({"configurations:Release*", clangGccActions}) - buildoptions("-mfpmath=sse") - buildoptions("-ftree-vectorize") - - filter({}) - - buildoptions(self.Config["AdditionalCompilationOptions"]) -end - -function NazaraBuild:PostconfigGenericProject() - -- Add options required for C++17 thread and filesystem (have to be linked last) - filter({"action:gmake*", "system:macosx"}) - links("pthread") - - filter({"action:gmake*", "system:not macosx"}) - links("stdc++fs") - links("pthread") - - filter({}) -end - -function NazaraBuild:PreconfigNazaraProject() - self:PreconfigGenericProject() - - language("C++") - - -- Add lib/conf/arch to library search path - self:FilterLibDirectory("../lib/", libdirs) - self:FilterLibDirectory("../lib/", runpathdirs) - - filter("action:vs*") - buildoptions({"/MP", "/bigobj"}) -- Multiprocessus build and big .obj - defines("_CRT_SECURE_NO_WARNINGS") - defines("_SCL_SECURE_NO_WARNINGS") - - filter("architecture:x86_64") - defines("NAZARA_PLATFORM_x64") - - filter("configurations:Debug*") - defines("NAZARA_DEBUG") - - filter("configurations:*Static") - defines("NAZARA_STATIC") - - filter("kind:*Lib") - defines("NAZARA_BUILD") - - filter({"system:Windows", clangGccActions}) - buildoptions("-Wa,-mbig-obj") -- big object - - filter({"system:not Windows", clangGccActions}) - buildoptions("-fvisibility=hidden") - - filter({}) -end - -function NazaraBuild:PostconfigNazaraProject() - self:PostconfigGenericProject() -end - -function NazaraBuild:RegisterAction(actionTable) - if (not actionTable.Manual) then - if (actionTable.Name == nil or type(actionTable.Name) ~= "string" or string.len(actionTable.Name) == 0) then - return false, "Invalid action name" - end - - local lowerCaseName = string.lower(actionTable.Name) - if (self.Actions[lowerCaseName] ~= nil) then - return false, "This action name is already in use" - end - - if (actionTable.Description == nil or type(actionTable.Description) ~= "string") then - return false, "Action description is invalid" - end - - if (string.len(actionTable.Description) == 0) then - return false, "Action description is empty" - end - - if (actionTable.Function == nil or type(actionTable.Function) ~= "function") then - return false, "Action function is invalid" - end - - self.Actions[lowerCaseName] = actionTable - - newaction - { - trigger = lowerCaseName, - description = actionTable.Description, - execute = function () actionTable:Function() end - } - end - - return true -end - -function NazaraBuild:RegisterExample(exampleTable) - if (exampleTable.Name == nil or type(exampleTable.Name) ~= "string" or string.len(exampleTable.Name) == 0) then - return false, "Invalid example name" - end - - local lowerCaseName = exampleTable.Name:lower() - if (self.Examples[lowerCaseName] ~= nil) then - return false, "This library name is already in use" - end - - if (exampleTable.Files == nil or type(exampleTable.Files) ~= "table") then - return false, "Example files table is invalid" - end - - if (#exampleTable.Files == 0) then - return false, "This example has no files" - end - - local files = {} - for k, file in ipairs(exampleTable.Files) do - table.insert(files, "../examples/" .. exampleTable.Directory .. "/" .. file) - end - exampleTable.Files = files - - exampleTable.Type = "Example" - exampleTable.Category = exampleTable.Category or exampleTable.Type - - self.Examples[lowerCaseName] = exampleTable - return true -end - -function NazaraBuild:RegisterExternLibrary(libTable) - if (libTable.Name == nil or type(libTable.Name) ~= "string" or string.len(libTable.Name) == 0) then - return false, "Invalid library name" - end - - local lowerCaseName = libTable.Name:lower() - if (self.ExtLibs[lowerCaseName] ~= nil) then - return false, "This library name is already in use" - end - - if (libTable.Files == nil or type(libTable.Files) ~= "table") then - return false, "Invalid file table" - end - - if (#libTable.Files == 0) then - return false, "This library has no files" - end - - libTable.Type = "ExternLib" - libTable.Category = libTable.Category or libTable.Type - - self.ExtLibs[lowerCaseName] = libTable - return true -end - -function NazaraBuild:RegisterModule(moduleTable) - if (moduleTable.Name == nil or type(moduleTable.Name) ~= "string" or string.len(moduleTable.Name) == 0) then - return false, "Invalid module name" - end - - local lowerCaseName = moduleTable.Name:lower() - if (self.Modules[lowerCaseName] ~= nil) then - return false, "This module name is already in use" - end - - table.insert(moduleTable.Defines, "NAZARA_" .. moduleTable.Name:upper() .. "_BUILD") - table.insert(moduleTable.Files, "../include/Nazara/" .. moduleTable.Name .. "/**.hpp") - table.insert(moduleTable.Files, "../include/Nazara/" .. moduleTable.Name .. "/**.inl") - table.insert(moduleTable.Files, "../src/Nazara/" .. moduleTable.Name .. "/**.hpp") - table.insert(moduleTable.Files, "../src/Nazara/" .. moduleTable.Name .. "/**.inl") - table.insert(moduleTable.Files, "../src/Nazara/" .. moduleTable.Name .. "/**.cpp") - - if (self.Config["UniteModules"] and lowerCaseName ~= "core") then - table.insert(moduleTable.FilesExcluded, "../src/Nazara/" .. moduleTable.Name .. "/Debug/NewOverload.cpp") - end - - moduleTable.Type = "Module" - moduleTable.Category = moduleTable.Category or moduleTable.Type - - self.Modules[lowerCaseName] = moduleTable - return true -end - -function NazaraBuild:RegisterTool(toolTable) - if (toolTable.Name == nil or type(toolTable.Name) ~= "string" or string.len(toolTable.Name) == 0) then - return false, "Invalid tool name" - end - - local lowerCaseName = toolTable.Name:lower() - if (self.Tools[lowerCaseName] ~= nil) then - return false, "This tool name is already in use" - end - - if (toolTable.Kind == nil or type(toolTable.Kind) ~= "string" or string.len(toolTable.Kind) == 0) then - return false, "Invalid tool type" - end - - local lowerCaseKind = toolTable.Kind:lower() - if (lowerCaseKind == "library" or lowerCaseKind == "plugin" or lowerCaseKind == "application") then - toolTable.Kind = lowerCaseKind - else - return false, "Invalid tool type" - end - - if (lowerCaseKind ~= "plugin" and (toolTable.TargetDirectory == nil or type(toolTable.TargetDirectory) ~= "string" or string.len(toolTable.TargetDirectory) == 0)) then - return false, "Invalid tool directory" - end - - toolTable.Type = "Tool" - toolTable.Category = toolTable.Category or toolTable.Type - - self.Tools[lowerCaseName] = toolTable - return true -end - -local globalExcludes = {} -function NazaraBuild:Resolve(infoTable) - if (infoTable.ClientOnly and self.Config["ServerMode"]) then - infoTable.Excluded = true - infoTable.ExcludeReason = "excluded by command-line options (client-only)" - end - - if (infoTable.Excludable) then - local globalExcludeOption = "excludes-" .. infoTable.Category:lower() .. "s" - if (not globalExcludes[infoTable.Category]) then - newoption({ - trigger = globalExcludeOption, - description = "Excludes all " .. string.lower(infoTable.Category) .. "s and projects relying on it" - }) - - globalExcludes[infoTable.Category] = true - end - - local specificExcludeOption = "excludes-" .. string.lower(infoTable.Category .. "-" .. infoTable.Name) - newoption({ - trigger = specificExcludeOption, - description = "Excludes the " .. infoTable.Name .. " " .. string.lower(infoTable.Category) .. " and projects relying on it" - }) - - if (_OPTIONS[globalExcludeOption]) then - infoTable.Excluded = true - infoTable.ExcludeReason = "excluded by global command-line options" - elseif (_OPTIONS[specificExcludeOption]) then - infoTable.Excluded = true - infoTable.ExcludeReason = "excluded by specific command-line options" - end - end - - if (type(infoTable.Libraries) == "function") then - infoTable.Libraries = infoTable.Libraries() - end -end - -function NazaraBuild:SetupInfoTable(infoTable) - infoTable.BinaryPaths = {} - infoTable.BinaryPaths.x86 = {} - infoTable.BinaryPaths.x64 = {} - infoTable.ConfigurationLibraries = {} - infoTable.ConfigurationLibraries.DebugStatic = {} - infoTable.ConfigurationLibraries.ReleaseStatic = {} - infoTable.ConfigurationLibraries.ReleaseWithDebugStatic = {} - infoTable.ConfigurationLibraries.DebugDynamic = {} - infoTable.ConfigurationLibraries.ReleaseDynamic = {} - infoTable.ConfigurationLibraries.ReleaseWithDebugDynamic = {} - infoTable.Excludable = true - infoTable.LibraryPaths = {} - infoTable.LibraryPaths.x86 = {} - infoTable.LibraryPaths.x64 = {} - - local infos = {"Defines", "DynLib", "Files", "FilesExcluded", "Flags", "Includes", "Libraries"} - for k,v in ipairs(infos) do - infoTable[v] = {} - infoTable["Os" .. v] = {} - end -end - -function NazaraBuild:SetupExampleTable(infoTable) - self:SetupInfoTable(infoTable) - - infoTable.Kind = "application" - infoTable.TargetDirectory = "../examples/bin" -end - -function NazaraBuild:SetupExtlibTable(infoTable) - self:SetupInfoTable(infoTable) - - infoTable.Kind = "library" - - table.insert(infoTable.BinaryPaths.x86, "../thirdparty/lib/common/x86") - table.insert(infoTable.BinaryPaths.x64, "../thirdparty/lib/common/x64") - table.insert(infoTable.LibraryPaths.x86, "../thirdparty/lib/common/x86") - table.insert(infoTable.LibraryPaths.x64, "../thirdparty/lib/common/x64") -end - -function NazaraBuild:SetupModuleTable(infoTable) - self:SetupInfoTable(infoTable) - - infoTable.Kind = "library" - - table.insert(infoTable.BinaryPaths.x86, "../thirdparty/lib/common/x86") - table.insert(infoTable.BinaryPaths.x64, "../thirdparty/lib/common/x64") - table.insert(infoTable.LibraryPaths.x86, "../thirdparty/lib/common/x86") - table.insert(infoTable.LibraryPaths.x64, "../thirdparty/lib/common/x64") -end - -NazaraBuild.SetupToolTable = NazaraBuild.SetupInfoTable diff --git a/build/scripts/features/audio.lua b/build/scripts/features/audio.lua deleted file mode 100644 index 3c6a7dea7..000000000 --- a/build/scripts/features/audio.lua +++ /dev/null @@ -1,89 +0,0 @@ -return { - Title = "Module audio", - LibName = "NazaraAudio", - Description = "Module permettant de charger et jouer des sons, ainsi que d'accéder au microphone", - RequiredPortability = Feature.Windows + Feature.POSIX, - - Features = - { - { - Title = "Gestion des émetteurs de sons (SoundEmitter)", - Description = "Classe de base dont héritent les sources sonores (Music, Sound)", - Features = - { - "Positionnement 3D (spatialisation) si désiré", - "Configuration de l'atténuation", - "Prise en charge de l'effet Doppler (vitesse du son)", - "Altération du ton (pitch)" - } - }, - { - Title = "Gestion des tampons sonores (SoundBuffer)", - Description = "Tampon (buffer) stockant les échantillons (samples) décompressés, chargés à partir de fichiers sonores.", - Features = - { - { - Title = "Mixage mono", - Description = "Permet de mixer les différents canaux en un seul (mono), permettant la spatialisation.", - Note = "Le mixage mono n'est actuellement possible qu'au chargement du tampon depuis un fichier", - Progress = 90 - } - } - }, - { - Title = "Gestion des flux sonores (SoundStream)", - Description = "Interface permettant de définir un flux sonore de source indéfinie (fichier, réseau, etc.)" - }, - { - Title = "Sons (Sound)", - Description = "Classe permettant de jouer un tampon sonore", - Features = - { - "Bouclage", - "Mise en pause", - "Récupération/positionnement de l'indice de lecture (offset)" - } - }, - { - Title = "Sons streamés (Music)", - Description = "Classe permettant de jouer un son depuis un flux quelconque (SoundStream)", - Features = - { - "Streaming depuis un fichier sonore (+ mixage mono si demandé)", - "Bouclage", - "Mise en pause", - {Title = "Mixage mono", Note = "Le mixage mono devrait être possible au niveau du son lui-même plutôt qu'au niveau du loader", Progress = 0}, - {Title = "Récupération/positionnement de l'indice de lecture (offset)", Progress = 0} - } - }, - { - Title = "Configuration globale (Audio)", - Description = "Classe permettant de régler les différents paramètres généraux de l'environnement sonore", - Features = - { - "Positionnement/Orientation du listener", - "Réglage du volume général", - "Réglage de la vitesse du son/facteur Doppler" - } - }, - { - Title = "Microphone", - Description = "Classe permettant l'accès aux microphones connectés à l'ordinateur", - Progress = 0 - }, - { - Title = "Environnement (EFX)", - Description = "Prise en charge de l'environnement", - Progress = 0 - }, - { - Title = "Formats supportés (chargement/streaming)", - Description = "Liste des formats de fichiers supportés par le loader inclus par le module (libsndfile)", - Note = "Le populaire format MP3 n'est pas supporté pour des raisons de royalties (mais la flexibilité du moteur vous permet de rajouter votre propre loader MP3)", - Features = - { - "aiff", "au", "avr", "caf", "flac", "htk", "ircam", "mat4", "mat5", "mpc2k", "nist","ogg", "pvf", "raw", "rf64", "sd2", "sds", "svx", "voc", "w64", "wav", "wve" - } - } - } -} \ No newline at end of file diff --git a/build/scripts/features/core.lua b/build/scripts/features/core.lua deleted file mode 100644 index 0c71af179..000000000 --- a/build/scripts/features/core.lua +++ /dev/null @@ -1,203 +0,0 @@ -return { - Title = "Noyau", - LibName = "NazaraCore", - Description = "Noyau du moteur, possède les fonctionnalités utilisées partout ailleurs dans le moteur.", - RequiredPortability = Feature.Windows + Feature.POSIX, - - Features = - { - { - Title = "Classes utilitaires de base", - Description = "Classes assurant certaines fonctionnalités de base destinées à aider le programmeur.", - Features = - { - { - Title = "Chaînes de caractère unicode (String)", - Description = "Classe supplantant std::string, rajoutant le support de l'UTF-8 et quelques opérations utiles (rechercher/remplacer, correspondance par motif, ..)." - }, - { - Title = "Exécution de code lors de la destruction (CallOnExit)", - Description = "Permet l'appel d'une fonction/lambda à la destruction de cet objet, en accordance avec le RAII/RRID." - }, - { - Title = "Gestion de l'initialisation/libération statique de classes, en accordance avec le RAII/RRID", - Description = "Permet d'initialiser et de libérer automatiquement des classes possédant des fonctions membres statiques Initialize/Uninitialize, selon un ordre de dépendance, comme par exemple les classes des modules du moteur lui-même." - }, - { - Title = "Gestion des couleurs (Color)", - Description = "Classe permettant de stocker et effectuer des opérations sur des couleurs (conversion, mélange, etc.)." - }, - { - Title = "Gestion de primitives, au sens géométrique (Primitive, PrimitiveList)", - Description = "Structures définissant certaines primitives géométriques (boite, cône, plan, sphère), utiles pour la génération de meshs (de rendu ou physiques)." - }, - { - Title = "OffsetOf", - Description = "Fonction permettant de récupérer à la compilation l'adresse locale (décalage d'octets) d'un membre de n'importe quelle structure/classe." - }, - { - Title = "Pointeurs à écart (stride) indépendant (SparsePtr)", - Description = "Classe se comportant comme un pointeur, à l'exception de l'écart entre deux éléments (opérations d'accès, d'addition et de soustraction) qui est indépendant du type pointé." - }, - { - Title = "Stockage et gestion de champs de bits dynamiques (Bitset)", - Description = "Classe permettant le stockage et la manipulation optimisée d'un nombre élevé et dynamique de bits (=booléens, opérations de comptage, recherche de bits activés, opérations entre champs de bits, etc.)", - Note = "Il manque une spécialisation de la fonction de hachage", - Progress = 95 - } - } - }, - { - Title = "Gestion de fichiers et dossiers (File/Directory)", - Description = "Classes supportant les chemins unicodes et les tailles 64 bits, ainsi que quelques opérations sur les chemins (normalisation, transformation d'un chemin relatif en chemin absolu).", - Portability = Feature.Windows + Feature.POSIX - }, - { - Title = "Gestion de l'endianness", - Description = "Boutisme, récupération à la compilation ou à l'exécution, possibilité de lire des fichiers en corrigeant le boutisme des objets lors de la lecture." - }, - { - Title = "Gestion de bibliothèques dynamiques (DynLib)", - Description = "Classe permettant de charger à l'exécution des bibliothèques dynamiques (selon la plateforme: .dll/.so/.dynlib) et d'en extraire des fonctions.", - Portability = Feature.Windows + Feature.POSIX - }, - { - Title = "Fonctions de hachage", - Description = "Possibilité de hacher (calculer une somme de contrôle) de n'importe quelles données, chaîne de caractère ou fichier.", - Features = - { - {Title = "CRC16", Progress = 0}, - "CRC32", - "Fletcher16", - {Title = "Fletcher32", Progress = 0}, - "MD5", - "SHA-1", - "SHA-224", - "SHA-256", - "SHA-384", - "SHA-512", - "Whirlpool" - } - }, - { - Title = "Gestion de la mémoire", - Description = "Set de fonctionnalités permettant d'aider le programmeur à gérer la mémoire de son programme.", - Features = - { - { - Title = "MemoryManager", - Description = "Classe permettant de suivre les allocations de mémoire et éventuels leaks, peut suivre automatiquement chaque allocation du programme." - }, - { - Title = "MemoryPool", - Description = "Classe permettant d'allouer/libérer des blocs de mémoire de taille prédéfinie à coût constant." - } - } - }, - { - Title = "Gestion de l'exécution concurrentielle", - Description = "Set de fonctionnalités liées à l'exécution et la synchronisation entre processus légers (threads) sans dépendance sur la bibliothèque standard.", - Features = - { - { - Title = "Thread", - Description = "Classe permettant d'appeler une fonction (avec passage d'arguments) dans un thread, supporte une interface similaire à std::thread.", - Note = "Il n'est pas encore possible de récupérer le Thread::Id courant", - Progress = 95, - Portability = Feature.Windows + Feature.POSIX - }, - { - Title = "Mutex", - Description = "Primitive de synchronisation binaire (exclusion mutuelle).", - Portability = Feature.Windows + Feature.POSIX - }, - { - Title = "Semaphore", - Description = "Primitive de synchronisation à N concurrents simultanés.", - Portability = Feature.Windows + Feature.POSIX - }, - { - Title = "ConditionVariable", - Description = "Primitive de synchronisation à signaux.", - Portability = Feature.Windows + Feature.POSIX - }, - { - Title = "LockGuard", - Description = "Classe utilitaire permettant de verrouiller/déverrouiller une mutex en accordance avec le RAII/RRID." - }, - { - Title = "TaskScheduler", - Description = "Classe permettant de répartir X tâches sur Y workers de façon efficace.", - Portability = Feature.Windows + Feature.POSIX - } - } - }, - { - Title = "Gestion du temps", - Description = "Classes/fonctions permettant de gérer le temps dans un programme.", - Features = - { - { - Title = "Récupération du temps en millisecondes ou en microsecondes", - Description = "Permet de récupérer le nombre de millisecondes ou de microsecondes (si supporté par le système) écoulées depuis un référentiel constant (référentiel indéterminé).", - Portability = Feature.Windows + Feature.POSIX - }, - { - Title = "Clock", - Description = "Classe chronomètre permettant de mesurer le temps écoulé depuis un évènement précis, supporte la mise en pause." - } - } - }, - { - Title = "Gestion de compteurs de référence", - Description = "Set de classes permettant de gérer des pointeurs intelligents partagés intrusifs.", - }, - { - Title = "Gestion de liste de paramètres", - Description = "Classe gérant une liste de paramètres nommées à type variable.", - }, - { - Title = "Gestion de ressources (chargement/gestion)", - Description = "Set de classes s'occupant du chargement et de la gestion de certaines classes spéciales, appartenant au groupe des ressources (ex: chargée depuis un fichier).", - Features = - { - { - Title = "ResourceLibrary", - Description = "Classe template chargée du stockage de ressources de façon nommée." - }, - { - Title = "ResourceLoader", - Description = "Classe template chargée de stocker et gérer des loaders (fonctions s'occupant de transformer un flux de données en ressource)." - }, - { - Title = "ResourceManager", - Description = "Classe template chargée de charger et mettre en cache des ressources depuis un chemin de fichier." - } - } - }, - { - Title = "Gestion des plugins", - Description = "Capacité d'extension du moteur à l'aide de bibliothèques dynamiques conçues dans cette optique.", - Note = "Nécessite une révision, permettant aux plugins de se signaler (nom, version)", - Progress = 80 - }, - { - Title = "Gestion de l'empaquetage bidimensionnel", - Description = "Algorithmes permettant de placer des rectangles 2D arbitraires dans un espace prédéfini de façon à minimiser la perte d'espace.", - Note = "Algorithme Guillotine terminé, algorithme Skyline manquant", - Progress = 60 - }, - { - Title = "Gestion de l'Unicode", - Description = "Récupération d'informations sur les caractères Unicode (si les données Unicode sont incorporées au programme).", - Note = "Il manque l'intégration des UnicodeData dans le moteur", - Progress = 20 - }, - { - Title = "Récupération d'informations sur le hardware", - Description = "Classe permettant, si la plateforme le supporte, de récupérer des informations utiles sur le matériel: nom et fabricant du processeur, nombre de coeurs, support d'un set d'extension (exemple: SSE), quantité de mémoire vive, exécution de l'instruction CPUID.", - Progress = 100, - Portability = Feature.Windows + Feature.POSIX - } - } -} \ No newline at end of file diff --git a/build/scripts/features/index_template.html b/build/scripts/features/index_template.html deleted file mode 100644 index 43bf5aea9..000000000 --- a/build/scripts/features/index_template.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - Avancement de Nazara - - -
- Nazara Engine - -
- - Retrouvez le moteur sur GitHub !
- Dépôt GitHub

- Venez vous renseigner sur les topics dédiés à Nazara présents sur plusieurs sites web :
- OpenClassrooms, Progdupeupl ou ZesteDeSavoir -

- ... ou pourquoi ne pas venir faire un tour sur le forum dédié au moteur ? - -
- -

Fonctionnalités de Nazara

- -
Dernière mise à jour : - %DATE% -
- -

Important:

-

Afin de faciliter la mise à jour, la page que vous voyez ici a été générée automatiquement par un script Lua, ce qui m'oblige néanmoins à encoder les fonctionnalités de chaque module dans un premier temps. - C'est un travail assez long (pour vous donner une idée, les données du noyau représentent un fichier de 200 lignes), et il n'est pas encore complet, c'est pourquoi des modules manquent sur cette page.
- Gardez donc à l'esprit que le moteur possède plus de fonctionnalités que ce qui est décrit actuellement sur cette page.

- -

Oh et bien sûr je ne suis pas concepteur de site web, c'est pourquoi cette page est moche (j'ai essayé de minimiser les dégâts).
- Si vous sentez en vous l'irrésistible envie d'améliorer cette page, sachez que votre aide serait grandement appréciée (vous pouvez me contacter via le lien de votre choix plus haut).

- -

Le pourcentage indiqué est calculé automatiquement en fonction des fonctionnalités, cela signifie qu'une fonctionnalité présente sera comptée à 100% à partir du moment où son implémentation de base est considérée fonctionnelle, cela n'est donc pas une assurance qu'aucun bug n'existe concernant cette fonctionnalité (cependant cela signifie que la fonctionnalité est utilisable).
- Et bien entendu, un module ou une fonctionnalité ayant atteint les 100% peut toujours évoluer par la suite.

- -
- - - - - - - - - - - %MODULELIST% - -
Sommaire
ModuleAvancement
- - %MODULEDESCRIPTION% -
- - - - - - - - - - %MODULELIST% - -
Sommaire
ModulePourcentage
-
- - \ No newline at end of file diff --git a/build/scripts/features/style.css b/build/scripts/features/style.css deleted file mode 100644 index ff83f706c..000000000 --- a/build/scripts/features/style.css +++ /dev/null @@ -1,121 +0,0 @@ -/* Je ne suis pas développeur HTML/CSS, je dois y toucher une fois l'an, désolé pour les quelques atrocités que vous pourrez trouver ici */ - -body -{ - font-family: sans-serif; - text-align: center; - margin: 0; - background-color: #f1f1f1; -} - -#englob { - display: block; - margin-left: auto; - margin-right: auto; - background-color: white; - width: 50%; - min-width: 765px; - padding: 0 20px; -} - -hr { - height: 0; - border: 0; - border-top: 1px solid #eee; -} - -a -{ - color: #007ACC; -} - -a:hover -{ - color: lightblue; -} - -h1 -{ - display: inline; -} - -h2 -{ - display: inline; - text-decoration: underline; -} - -h4 -{ - text-decoration: underline; -} - -p { - text-align: justify; -} - -ol -{ - list-style-type: none; -} - -table -{ - border-collapse: collapse; - text-align: center; - display: inline-block; - border: white groove; - border-radius: 10px; - box-shadow: 0px 0px 10px lightblue; -} - -th -{ - text-shadow: 2px 2px 4px black; -} - -tr -{ - border: 1px solid white; -} - -tbody tr:hover -{ - text-shadow: 0px 0px 4px white; -} - -.description -{ - margin-left: 20px; -} - -.lastupdate -{ - font-size: x-large; - font-weight: bold; - color: #f1c40f; -} - -.modulename -{ - font-size: x-large; - font-weight: bold; - text-shadow: 2px 2px 10px #007ACC; -} - -.note -{ - margin-left: 20px; - color: #007ACC; -} - -.notedesc -{ - color: rgb(200, 200, 255); -} - -.portability -{ - margin-left: 20px; - color: red; -} \ No newline at end of file diff --git a/build/scripts/modules/audio.lua b/build/scripts/modules/audio.lua deleted file mode 100644 index 2919b6fe0..000000000 --- a/build/scripts/modules/audio.lua +++ /dev/null @@ -1,37 +0,0 @@ -MODULE.Name = "Audio" - -MODULE.ClientOnly = true - -MODULE.Defines = { - "NAZARA_AUDIO_OPENAL" -} - -MODULE.Libraries = { - "NazaraCore" -} - -MODULE.OsLibraries.Windows = { - "sndfile-1" -} - -MODULE.OsLibraries.Posix = { - "sndfile" -} - -MODULE.OsDynLib.Windows = { - "soft_oal" -} - -MODULE.OsFiles.Windows = { - "../src/Nazara/Audio/Win32/**.hpp", - "../src/Nazara/Audio/Win32/**.cpp" -} - -MODULE.OsFiles.Posix = { - "../src/Nazara/Audio/Posix/**.hpp", - "../src/Nazara/Audio/Posix/**.cpp" -} - -MODULE.DynLib = { - "soft_oal" -} diff --git a/build/scripts/modules/core.lua b/build/scripts/modules/core.lua deleted file mode 100644 index e998080f8..000000000 --- a/build/scripts/modules/core.lua +++ /dev/null @@ -1,24 +0,0 @@ -MODULE.Name = "Core" -MODULE.Excludable = false -- Excluding the core makes no sense as everything relies on it - -MODULE.Files = { -- Other files will be automatically added - "../include/Nazara/Prerequisites.hpp", - "../include/Nazara/Math/**.hpp", - "../include/Nazara/Math/**.inl", -} - -MODULE.OsFiles.Windows = { - "../src/Nazara/Core/Win32/**.hpp", - "../src/Nazara/Core/Win32/**.cpp" -} - -MODULE.OsFiles.Posix = { - "../src/Nazara/Core/Posix/**.hpp", - "../src/Nazara/Core/Posix/**.cpp" -} - -MODULE.OsLibraries.Posix = { - "dl", - "m", -- Math library (for sincos()) - "pthread" -} diff --git a/build/scripts/modules/graphics.lua b/build/scripts/modules/graphics.lua deleted file mode 100644 index 71b2738ce..000000000 --- a/build/scripts/modules/graphics.lua +++ /dev/null @@ -1,9 +0,0 @@ -MODULE.Name = "Graphics" - -MODULE.ClientOnly = true - -MODULE.Libraries = { - "NazaraCore", - "NazaraRenderer", - "NazaraUtility" -} diff --git a/build/scripts/modules/network.lua b/build/scripts/modules/network.lua deleted file mode 100644 index 9245d72f3..000000000 --- a/build/scripts/modules/network.lua +++ /dev/null @@ -1,29 +0,0 @@ -MODULE.Name = "Network" - -MODULE.Libraries = { - "NazaraCore" -} - -MODULE.OsFiles.Windows = { - "../src/Nazara/Network/Win32/**.hpp", - "../src/Nazara/Network/Win32/**.cpp" -} - -MODULE.OsFiles.Posix = { - "../src/Nazara/Network/Posix/**.hpp", - "../src/Nazara/Network/Posix/**.cpp" -} - -MODULE.OsFiles.Linux = { - "../src/Nazara/Network/Linux/**.hpp", - "../src/Nazara/Network/Linux/**.cpp" -} - -MODULE.OsFilesExcluded.Linux = { - "../src/Nazara/Network/Posix/SocketPollerImpl.hpp", - "../src/Nazara/Network/Posix/SocketPollerImpl.cpp" -} - -MODULE.OsLibraries.Windows = { - "ws2_32" -} diff --git a/build/scripts/modules/physics2d.lua b/build/scripts/modules/physics2d.lua deleted file mode 100644 index 58d0a08f5..000000000 --- a/build/scripts/modules/physics2d.lua +++ /dev/null @@ -1,12 +0,0 @@ -MODULE.Name = "Physics2D" - -MODULE.Defines = {"CP_USE_CGTYPES=0", "TARGET_OS_IPHONE=0", "TARGET_OS_MAC=0"} - -MODULE.Libraries = { - "NazaraCore", - "chipmunk" -} - -MODULE.DynLib = { - "chipmunk" -} diff --git a/build/scripts/modules/physics3d.lua b/build/scripts/modules/physics3d.lua deleted file mode 100644 index 893948e76..000000000 --- a/build/scripts/modules/physics3d.lua +++ /dev/null @@ -1,30 +0,0 @@ -MODULE.Name = "Physics3D" - -MODULE.Defines = { - "_NEWTON_STATIC_LIB" -} - -MODULE.OsDefines.Windows = { - "_WINDOWS" -} - -MODULE.Libraries = { - "NazaraCore", - "newton" -- Newton Game Dynamics -} - -MODULE.Custom = function() - vectorextensions("SSE3") - - filter({"architecture:x86_64", "system:linux"}) - defines("_POSIX_VER_64") - - filter({"architecture:x86", "system:linux"}) - defines("_POSIX_VER") - - filter({"architecture:x86_64", "system:macosx"}) - defines("_POSIX_VER_64") - - filter({"architecture:x86", "system:macosx"}) - defines("_POSIX_VER") -end diff --git a/build/scripts/modules/platform.lua b/build/scripts/modules/platform.lua deleted file mode 100644 index fbf1b94af..000000000 --- a/build/scripts/modules/platform.lua +++ /dev/null @@ -1,35 +0,0 @@ -MODULE.Name = "Platform" - -MODULE.ClientOnly = true - -MODULE.Defines = { - "NAZARA_PLATFORM_SDL2" -} - -MODULE.Libraries = { - "NazaraCore", - "NazaraUtility", - "SDL2" -} - -MODULE.Files = { - "../src/Nazara/Platform/SDL2/**.hpp", - "../src/Nazara/Platform/SDL2/**.cpp" -} - -MODULE.OsDefines.Windows = { - "SDL_VIDEO_DRIVER_WINDOWS=1" -} - -MODULE.DynLib = { - "SDL2" -} - -MODULE.Custom = function() - filter("system:linux") - defines("SDL_VIDEO_DRIVER_X11=1") - defines("SDL_VIDEO_DRIVER_WAYLAND=1") - - filter("system:macosx") - defines("SDL_VIDEO_DRIVER_COCOA=1") -end diff --git a/build/scripts/modules/renderer.lua b/build/scripts/modules/renderer.lua deleted file mode 100644 index f371bc5d1..000000000 --- a/build/scripts/modules/renderer.lua +++ /dev/null @@ -1,20 +0,0 @@ -MODULE.Name = "Renderer" - -MODULE.ClientOnly = true - -MODULE.Libraries = { - "NazaraCore", - "NazaraShader", - "NazaraUtility", - "NazaraPlatform" -} - -MODULE.OsFiles.Windows = { - "../src/Nazara/Renderer/Win32/**.hpp", - "../src/Nazara/Renderer/Win32/**.cpp" -} - -MODULE.OsFiles.Posix = { - "../src/Nazara/Renderer/GLX/**.hpp", - "../src/Nazara/Renderer/GLX/**.cpp" -} diff --git a/build/scripts/modules/shader.lua b/build/scripts/modules/shader.lua deleted file mode 100644 index a0a22a663..000000000 --- a/build/scripts/modules/shader.lua +++ /dev/null @@ -1,6 +0,0 @@ -MODULE.Name = "Shader" - -MODULE.Libraries = { - "NazaraCore", - "NazaraUtility" -} diff --git a/build/scripts/modules/utility.lua b/build/scripts/modules/utility.lua deleted file mode 100644 index fc4c989d8..000000000 --- a/build/scripts/modules/utility.lua +++ /dev/null @@ -1,15 +0,0 @@ -MODULE.Name = "Utility" - -MODULE.Libraries = { - "NazaraCore", - "stb_image" -} - -MODULE.OsLibraries.Windows = { - "freetype-s" -} - -MODULE.OsLibraries.Posix = { - "freetype" -} - diff --git a/build/scripts/tools/assimp.lua b/build/scripts/tools/assimp.lua deleted file mode 100644 index 09374bca1..000000000 --- a/build/scripts/tools/assimp.lua +++ /dev/null @@ -1,22 +0,0 @@ -TOOL.Name = "Assimp" - -TOOL.Directory = "../plugins/Assimp" -TOOL.Kind = "Plugin" - -TOOL.Includes = { - "../thirdparty/include", - "../include", - "../plugins/Assimp" -} - -TOOL.Files = { - "../plugins/Assimp/**.hpp", - "../plugins/Assimp/**.inl", - "../plugins/Assimp/**.cpp" -} - -TOOL.Libraries = { - "NazaraCore", - "NazaraUtility", - "assimp" -} diff --git a/build/scripts/tools/ndk.lua b/build/scripts/tools/ndk.lua deleted file mode 100644 index 49d7ee94d..000000000 --- a/build/scripts/tools/ndk.lua +++ /dev/null @@ -1,34 +0,0 @@ -TOOL.Name = "SDK" - -TOOL.Directory = "../SDK" -TOOL.Kind = "Library" -TOOL.TargetDirectory = "../lib" - -TOOL.Defines = { - "NDK_BUILD" -} - -TOOL.Includes = { - "../include", - "../src" -} - -TOOL.Files = { - "../include/NazaraSDK/**.hpp", - "../include/NazaraSDK/**.inl", - "../src/NazaraSDK/**.hpp", - "../src/NazaraSDK/**.inl", - "../src/NazaraSDK/**.cpp" -} - -TOOL.Libraries = function() - local libraries = {} - for k,v in pairs(NazaraBuild.Modules) do - table.insert(libraries, "Nazara" .. v.Name) - end - - -- Keep libraries in the same order to prevent useless premake regeneration - table.sort(libraries) - - return libraries -end \ No newline at end of file diff --git a/build/scripts/tools/ndk_server.lua b/build/scripts/tools/ndk_server.lua deleted file mode 100644 index e50d8c802..000000000 --- a/build/scripts/tools/ndk_server.lua +++ /dev/null @@ -1,51 +0,0 @@ -TOOL.Name = "SDKServer" - -TOOL.Directory = "../SDK" -TOOL.Kind = "Library" -TOOL.TargetDirectory = "../lib" - -TOOL.Defines = { - "NDK_BUILD", - "NDK_SERVER" -} - -TOOL.Includes = { - "../include", - "../src" -} - -TOOL.Files = { - "../include/NazaraSDK/**.hpp", - "../include/NazaraSDK/**.inl", - "../src/NazaraSDK/**.hpp", - "../src/NazaraSDK/**.inl", - "../src/NazaraSDK/**.cpp" -} - --- Excludes client-only files -TOOL.FilesExcluded = { - "../*/NazaraSDK/BaseWidget.*", - "../*/NazaraSDK/Canvas.*", - "../*/NazaraSDK/Console.*", - "../*/NazaraSDK/**/CameraComponent.*", - "../*/NazaraSDK/**/DebugComponent.*", - "../*/NazaraSDK/**/DebugSystem.*", - "../*/NazaraSDK/**/GraphicsComponent.*", - "../*/NazaraSDK/**/LightComponent.*", - "../*/NazaraSDK/**/ListenerComponent.*", - "../*/NazaraSDK/**/ListenerSystem.*", - "../*/NazaraSDK/**/Particle*Component.*", - "../*/NazaraSDK/**/ParticleSystem.*", - "../*/NazaraSDK/**/RenderSystem.*", - "../*/NazaraSDK/**/*Layout*.*", - "../*/NazaraSDK/**/*Widget*.*" -} - -TOOL.Libraries = { - "NazaraCore", - "NazaraNetwork", - "NazaraPhysics2D", - "NazaraPhysics3D", - "NazaraShader", - "NazaraUtility" -} diff --git a/build/scripts/tools/openglrenderer.lua b/build/scripts/tools/openglrenderer.lua deleted file mode 100644 index 48219fe80..000000000 --- a/build/scripts/tools/openglrenderer.lua +++ /dev/null @@ -1,54 +0,0 @@ -TOOL.Name = "OpenGLRenderer" - -TOOL.ClientOnly = true - -TOOL.Kind = "Library" -TOOL.TargetDirectory = "../lib" - -TOOL.Defines = { - "NAZARA_BUILD", - "NAZARA_OPENGLRENDERER_BUILD" -} - -TOOL.Includes = { - "../include", - "../src/", - "../extlibs/include" -} - -TOOL.Files = { - "../include/Nazara/OpenGLRenderer/**.hpp", - "../include/Nazara/OpenGLRenderer/**.inl", - "../src/Nazara/OpenGLRenderer/**.hpp", - "../src/Nazara/OpenGLRenderer/**.inl", - "../src/Nazara/OpenGLRenderer/**.cpp" -} - -TOOL.Libraries = { - "NazaraCore", - "NazaraPlatform", - "NazaraRenderer", - "NazaraShader", - "NazaraUtility" -} - -TOOL.OsFiles.Windows = { - "../include/Nazara/OpenGLRenderer/Wrapper/Win32/**.hpp", - "../include/Nazara/OpenGLRenderer/Wrapper/Win32/**.inl", - "../include/Nazara/OpenGLRenderer/Wrapper/WGL/**.hpp", - "../include/Nazara/OpenGLRenderer/Wrapper/WGL/**.inl", - "../src/Nazara/OpenGLRenderer/Wrapper/Win32/**.hpp", - "../src/Nazara/OpenGLRenderer/Wrapper/Win32/**.inl", - "../src/Nazara/OpenGLRenderer/Wrapper/Win32/**.cpp", - "../src/Nazara/OpenGLRenderer/Wrapper/WGL/**.hpp", - "../src/Nazara/OpenGLRenderer/Wrapper/WGL/**.inl", - "../src/Nazara/OpenGLRenderer/Wrapper/WGL/**.cpp" -} - -TOOL.OsFiles.Linux = { - "../include/Nazara/OpenGLRenderer/Wrapper/Linux/**.hpp", - "../include/Nazara/OpenGLRenderer/Wrapper/Linux/**.inl", - "../src/Nazara/OpenGLRenderer/Wrapper/Linux/**.hpp", - "../src/Nazara/OpenGLRenderer/Wrapper/Linux/**.inl", - "../src/Nazara/OpenGLRenderer/Wrapper/Linux/**.cpp" -} diff --git a/build/scripts/tools/shadernodes.lua b/build/scripts/tools/shadernodes.lua deleted file mode 100644 index cc0b63cb3..000000000 --- a/build/scripts/tools/shadernodes.lua +++ /dev/null @@ -1,92 +0,0 @@ -TOOL.Name = "ShaderNodes" - -TOOL.ClientOnly = true -TOOL.EnableConsole = true -TOOL.Kind = "Application" -TOOL.TargetDirectory = "../bin" - -TOOL.Defines = { - "NODE_EDITOR_SHARED" -} - -TOOL.Includes = { - "../include", - "../extlibs/include", - "../src" -} - -TOOL.Files = { - "../src/ShaderNode/**.hpp", - "../src/ShaderNode/**.inl", - "../src/ShaderNode/**.cpp" -} - -TOOL.Libraries = { - "NazaraCore%s(-s)%d(-d)", - "NazaraShader%s(-s)%d(-d)", - "NazaraUtility%s(-s)%d(-d)", - "Qt5Core%d(d)", - "Qt5Gui%d(d)", - "Qt5Widgets%d(d)", - "nodes%d(d)" -} - -local function AppendValues(tab, value) - if (type(value) == "table") then - for _, v in pairs(value) do - AppendValues(tab, v) - end - else - table.insert(tab, value) - end -end - -function TOOL:ValidateLib(libName) - local config = NazaraBuild:GetConfig() - local includes = config[libName .. "IncludeDir"] - local binDir32 = config[libName .. "BinDir_x86"] - local binDir64 = config[libName .. "BinDir_x64"] - local libDir32 = config[libName .. "LibDir_x86"] - local libDir64 = config[libName .. "LibDir_x64"] - if (not includes) then - return false, "missing " .. libName .. " includes directories in config.lua" - end - - if (not libDir32 and not libDir64) then - return false, "missing " .. libName .. " library search directories in config.lua" - end - - AppendValues(self.Includes, includes) - - if (binDir32) then - AppendValues(self.BinaryPaths.x86, binDir32) - end - - if (binDir64) then - AppendValues(self.BinaryPaths.x64, binDir64) - end - - if (libDir32) then - AppendValues(self.LibraryPaths.x86, libDir32) - end - - if (libDir64) then - AppendValues(self.LibraryPaths.x64, libDir64) - end - - return true -end - -function TOOL:Validate() - local success, err = self:ValidateLib("Qt5") - if (not success) then - return false, err - end - - local success, err = self:ValidateLib("QtNodes") - if (not success) then - return false, err - end - - return true -end \ No newline at end of file diff --git a/build/scripts/tools/unittests.lua b/build/scripts/tools/unittests.lua deleted file mode 100644 index adf06a97a..000000000 --- a/build/scripts/tools/unittests.lua +++ /dev/null @@ -1,27 +0,0 @@ -TOOL.Name = "UnitTests" - -TOOL.Category = "Test" -TOOL.Directory = "../tests" -TOOL.EnableConsole = true -TOOL.Kind = "Application" -TOOL.TargetDirectory = TOOL.Directory - -TOOL.Defines = { -} - -TOOL.Includes = { - "../include" -} - -TOOL.Files = { - "../tests/main.cpp", - "../tests/Engine/**.hpp", - "../tests/Engine/**.cpp", - "../tests/SDK/**.hpp", - "../tests/SDK/**.cpp" -} - -TOOL.Libraries = { - "NazaraNetwork", - "NazaraSDK" -} diff --git a/build/scripts/tools/unittests_server.lua b/build/scripts/tools/unittests_server.lua deleted file mode 100644 index b42c62185..000000000 --- a/build/scripts/tools/unittests_server.lua +++ /dev/null @@ -1,38 +0,0 @@ -TOOL.Name = "UnitTestsServer" - -TOOL.Category = "Test" -TOOL.Directory = "../tests" -TOOL.EnableConsole = true -TOOL.Kind = "Application" -TOOL.TargetDirectory = TOOL.Directory - -TOOL.Defines = { - "NDK_SERVER" -} - -TOOL.Includes = { - "../include" -} - -TOOL.Files = { - "../tests/main.cpp", - "../tests/Engine/**.hpp", - "../tests/Engine/**.cpp", - "../tests/SDK/**.hpp", - "../tests/SDK/**.cpp" -} - --- Excludes client-only files -TOOL.FilesExcluded = { - "../tests/Engine/Audio/**", - "../tests/Engine/Graphics/**", - "../tests/Engine/Platform/**", - "../tests/SDK/NDK/Application.cpp", - "../tests/SDK/NDK/Systems/ListenerSystem.cpp", - "../tests/SDK/NDK/Systems/RenderSystem.cpp" -} - -TOOL.Libraries = { - "NazaraNetwork", - "NazaraSDKServer" -} diff --git a/build/scripts/tools/vulkanrenderer.lua b/build/scripts/tools/vulkanrenderer.lua deleted file mode 100644 index 4f4440899..000000000 --- a/build/scripts/tools/vulkanrenderer.lua +++ /dev/null @@ -1,53 +0,0 @@ -TOOL.Name = "VulkanRenderer" - -TOOL.ClientOnly = true - -TOOL.Kind = "Library" -TOOL.TargetDirectory = "../lib" - -TOOL.Defines = { - "NAZARA_BUILD", - "NAZARA_VULKANRENDERER_BUILD", - "VK_NO_PROTOTYPES" -} - -TOOL.Includes = { - "../include", - "../src/", - "../extlibs/include" -} - -TOOL.Files = { - "../include/Nazara/VulkanRenderer/**.hpp", - "../include/Nazara/VulkanRenderer/**.inl", - "../src/Nazara/VulkanRenderer/**.hpp", - "../src/Nazara/VulkanRenderer/**.inl", - "../src/Nazara/VulkanRenderer/**.cpp" -} - -TOOL.Libraries = { - "NazaraCore", - "NazaraPlatform", - "NazaraRenderer", - "NazaraShader", - "NazaraUtility" -} - -TOOL.OsDefines.Linux = { --- "VK_USE_PLATFORM_MIR_KHR", --- "VK_USE_PLATFORM_XCB_KHR" - "VK_USE_PLATFORM_XLIB_KHR", - "VK_USE_PLATFORM_WAYLAND_KHR" -} - -TOOL.OsDefines.BSD = TOOL.OsDefines.Linux -TOOL.OsDefines.Solaris = TOOL.OsDefines.Linux - -TOOL.OsDefines.Windows = { - "VK_USE_PLATFORM_WIN32_KHR" -} - -TOOL.OsFiles.Windows = { - "../src/Nazara/VulkanRenderer/Win32/**.hpp", - "../src/Nazara/VulkanRenderer/Win32/**.cpp" -} diff --git a/examples/DeferredShading/main.cpp b/examples/DeferredShading/main.cpp new file mode 100644 index 000000000..642cc6816 --- /dev/null +++ b/examples/DeferredShading/main.cpp @@ -0,0 +1,1197 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* +[layout(std140)] +struct PointLight +{ + color: vec3, + position: vec3, + + constant: f32, + linear: f32, + quadratic: f32, +} + +[layout(std140)] +struct SpotLight +{ + color: vec3, + position: vec3, + direction: vec3, + + constant: f32, + linear: f32, + quadratic: f32, + + innerAngle: f32, + outerAngle: f32, +} +*/ + +struct PointLight +{ + Nz::Color color = Nz::Color::White; + Nz::Vector3f position = Nz::Vector3f::Zero(); + + float radius = 1.f; +}; + +struct SpotLight +{ + Nz::Color color = Nz::Color::White; + Nz::Matrix4f transformMatrix; + Nz::Vector3f position = Nz::Vector3f::Zero(); + Nz::Vector3f direction = Nz::Vector3f::Forward(); + + float radius = 1.f; + + Nz::RadianAnglef innerAngle = Nz::DegreeAnglef(15.f); + Nz::RadianAnglef outerAngle = Nz::DegreeAnglef(20.f); +}; + +int main() +{ + std::filesystem::path resourceDir = "resources"; + if (!std::filesystem::is_directory(resourceDir) && std::filesystem::is_directory(".." / resourceDir)) + resourceDir = ".." / resourceDir; + + Nz::Renderer::Config rendererConfig; + std::cout << "Run using Vulkan? (y/n)" << std::endl; + if (std::getchar() == 'y') + rendererConfig.preferredAPI = Nz::RenderAPI::Vulkan; + else + rendererConfig.preferredAPI = Nz::RenderAPI::OpenGL; + + Nz::Modules nazara(rendererConfig); + + Nz::RenderWindow window; + + Nz::MeshParams meshParams; + meshParams.storage = Nz::DataStorage::Software; + meshParams.matrix = Nz::Matrix4f::Rotate(Nz::EulerAnglesf(0.f, 90.f, 180.f)) * Nz::Matrix4f::Scale(Nz::Vector3f(0.002f)); + meshParams.vertexDeclaration = Nz::VertexDeclaration::Get(Nz::VertexLayout::XYZ_Normal_UV); + + std::shared_ptr device = Nz::Graphics::Instance()->GetRenderDevice(); + const Nz::RenderDeviceInfo& deviceInfo = device->GetDeviceInfo(); + + std::string windowTitle = "Graphics Test"; + if (!window.Create(device, Nz::VideoMode(1920, 1080, 32), windowTitle)) + { + std::cout << "Failed to create Window" << std::endl; + return __LINE__; + } + + std::shared_ptr spaceship = Nz::Mesh::LoadFromFile(resourceDir / "Spaceship/spaceship.obj", meshParams); + if (!spaceship) + { + NazaraError("Failed to load model"); + return __LINE__; + } + + std::shared_ptr gfxMesh = std::make_shared(*spaceship); + + Nz::TextureParams texParams; + texParams.renderDevice = device; + texParams.loadFormat = Nz::PixelFormat::RGBA8_SRGB; + + // Plane + Nz::MeshParams meshPrimitiveParams; + meshPrimitiveParams.storage = Nz::DataStorage::Software; + + std::shared_ptr planeMesh = std::make_shared(); + planeMesh->CreateStatic(); + planeMesh->BuildSubMesh(Nz::Primitive::Plane(Nz::Vector2f(25.f, 25.f), Nz::Vector2ui(0u), Nz::Matrix4f::Rotate(Nz::EulerAnglesf(180.f, 0.f, 0.f)), Nz::Rectf(0.f, 0.f, 10.f, 10.f)), meshPrimitiveParams); + //planeMesh->BuildSubMesh(Nz::Primitive::Cone(1.f, 1.f, 16, Nz::Matrix4f::Rotate(Nz::EulerAnglesf(90.f, 0.f, 0.f))), planeParams); + planeMesh->SetMaterialCount(1); + + std::shared_ptr planeMeshGfx = std::make_shared(*planeMesh); + + // Skybox + meshPrimitiveParams.vertexDeclaration = Nz::VertexDeclaration::Get(Nz::VertexLayout::XYZ); + + std::shared_ptr cubeMesh = std::make_shared(); + cubeMesh->CreateStatic(); + cubeMesh->BuildSubMesh(Nz::Primitive::Box(Nz::Vector3f::Unit(), Nz::Vector3ui(0), Nz::Matrix4f::Scale({ 1.f, -1.f, 1.f })), meshPrimitiveParams); + cubeMesh->SetMaterialCount(1); + + std::shared_ptr cubeMeshGfx = std::make_shared(*cubeMesh); + + Nz::RenderPipelineLayoutInfo pipelineLayoutInfo; + auto& uboBinding = pipelineLayoutInfo.bindings.emplace_back(); + uboBinding.index = 0; + uboBinding.shaderStageFlags = Nz::ShaderStageType::Vertex; + uboBinding.type = Nz::ShaderBindingType::UniformBuffer; + + auto& textureBinding = pipelineLayoutInfo.bindings.emplace_back(); + textureBinding.index = 1; + textureBinding.shaderStageFlags = Nz::ShaderStageType::Fragment; + textureBinding.type = Nz::ShaderBindingType::Texture; + + std::shared_ptr skyboxPipelineLayout = device->InstantiateRenderPipelineLayout(std::move(pipelineLayoutInfo)); + + Nz::RenderPipelineInfo skyboxPipelineInfo; + skyboxPipelineInfo.depthBuffer = true; + skyboxPipelineInfo.depthCompare = Nz::RendererComparison::Equal; + skyboxPipelineInfo.faceCulling = true; + skyboxPipelineInfo.cullingSide = Nz::FaceSide::Front; + skyboxPipelineInfo.pipelineLayout = skyboxPipelineLayout; + skyboxPipelineInfo.shaderModules.push_back(device->InstantiateShaderModule(Nz::ShaderStageType::Fragment | Nz::ShaderStageType::Vertex, Nz::ShaderLanguage::NazaraShader, resourceDir / "skybox.nzsl", {})); + skyboxPipelineInfo.vertexBuffers.push_back({ + 0, + meshPrimitiveParams.vertexDeclaration + }); + + std::shared_ptr skyboxPipeline = device->InstantiateRenderPipeline(std::move(skyboxPipelineInfo)); + + Nz::TextureParams skyboxTexParams; + skyboxTexParams.renderDevice = device; + + std::shared_ptr skyboxTexture = Nz::Texture::LoadCubemapFromFile(resourceDir / "skybox-space.png", skyboxTexParams); + + // Cone mesh + std::shared_ptr coneMesh = std::make_shared(); + coneMesh->CreateStatic(); + coneMesh->BuildSubMesh(Nz::Primitive::Cone(1.f, 1.f, 16, Nz::Matrix4f::Rotate(Nz::EulerAnglesf(90.f, 0.f, 0.f))), meshPrimitiveParams); + coneMesh->SetMaterialCount(1); + + std::shared_ptr coneMeshGfx = std::make_shared(*coneMesh); + + auto customSettings = Nz::BasicMaterial::GetSettings()->GetBuilderData(); + customSettings.shaders[UnderlyingCast(Nz::ShaderStageType::Fragment)] = std::make_shared(Nz::ShaderStageType::Fragment, Nz::ShaderLang::Parse(resourceDir / "deferred_frag.nzsl")); + customSettings.shaders[UnderlyingCast(Nz::ShaderStageType::Vertex)] = std::make_shared(Nz::ShaderStageType::Vertex, Nz::ShaderLang::Parse(resourceDir / "deferred_vert.nzsl")); + + auto customMatSettings = std::make_shared(std::move(customSettings)); + + std::shared_ptr spaceshipMat = std::make_shared(customMatSettings); + spaceshipMat->EnableDepthBuffer(true); + { + Nz::BasicMaterial basicMat(*spaceshipMat); + basicMat.EnableAlphaTest(false); + basicMat.SetAlphaMap(Nz::Texture::LoadFromFile(resourceDir / "alphatile.png", texParams)); + basicMat.SetDiffuseMap(Nz::Texture::LoadFromFile(resourceDir / "Spaceship/Texture/diffuse.png", texParams)); + } + + std::shared_ptr planeMat = std::make_shared(customMatSettings); + planeMat->EnableDepthBuffer(true); + { + Nz::BasicMaterial basicMat(*planeMat); + basicMat.SetDiffuseMap(Nz::Texture::LoadFromFile(resourceDir / "dev_grey.png", texParams)); + + Nz::TextureSamplerInfo planeSampler; + planeSampler.anisotropyLevel = 16; + planeSampler.wrapModeU = Nz::SamplerWrap::Repeat; + planeSampler.wrapModeV = Nz::SamplerWrap::Repeat; + basicMat.SetDiffuseSampler(planeSampler); + } + + Nz::Model spaceshipModel(std::move(gfxMesh)); + for (std::size_t i = 0; i < spaceshipModel.GetSubMeshCount(); ++i) + spaceshipModel.SetMaterial(i, spaceshipMat); + + Nz::Model planeModel(std::move(planeMeshGfx)); + for (std::size_t i = 0; i < planeModel.GetSubMeshCount(); ++i) + planeModel.SetMaterial(i, planeMat); + + Nz::PredefinedInstanceData instanceUboOffsets = Nz::PredefinedInstanceData::GetOffsets(); + Nz::PredefinedViewerData viewerUboOffsets = Nz::PredefinedViewerData::GetOffsets(); + + std::vector viewerDataBuffer(viewerUboOffsets.totalSize); + + Nz::Vector2ui windowSize = window.GetSize(); + + Nz::AccessByOffset(viewerDataBuffer.data(), viewerUboOffsets.viewMatrixOffset) = Nz::Matrix4f::Translate(Nz::Vector3f::Backward() * 1); + Nz::AccessByOffset(viewerDataBuffer.data(), viewerUboOffsets.projMatrixOffset) = Nz::Matrix4f::Perspective(Nz::DegreeAnglef(70.f), float(windowSize.x) / windowSize.y, 0.1f, 1000.f); + Nz::AccessByOffset(viewerDataBuffer.data(), viewerUboOffsets.invTargetSizeOffset) = 1.f / Nz::Vector2f(window.GetSize().x, window.GetSize().y); + + std::vector instanceDataBuffer(instanceUboOffsets.totalSize); + + Nz::ModelInstance modelInstance1(spaceshipMat->GetSettings()); + { + spaceshipMat->UpdateShaderBinding(modelInstance1.GetShaderBinding()); + + Nz::AccessByOffset(instanceDataBuffer.data(), instanceUboOffsets.worldMatrixOffset) = Nz::Matrix4f::Translate(Nz::Vector3f::Forward() * 2 + Nz::Vector3f::Right()); + + std::shared_ptr& instanceDataUBO = modelInstance1.GetInstanceBuffer(); + instanceDataUBO->Fill(instanceDataBuffer.data(), 0, instanceDataBuffer.size()); + } + + Nz::ModelInstance modelInstance2(spaceshipMat->GetSettings()); + { + spaceshipMat->UpdateShaderBinding(modelInstance2.GetShaderBinding()); + + Nz::AccessByOffset(instanceDataBuffer.data(), instanceUboOffsets.worldMatrixOffset) = Nz::Matrix4f::Translate(Nz::Vector3f::Forward() * 2 + Nz::Vector3f::Right() * 3.f); + + std::shared_ptr& instanceDataUBO = modelInstance2.GetInstanceBuffer(); + instanceDataUBO->Fill(instanceDataBuffer.data(), 0, instanceDataBuffer.size()); + } + + Nz::ModelInstance planeInstance(planeMat->GetSettings()); + { + planeMat->UpdateShaderBinding(planeInstance.GetShaderBinding()); + + Nz::AccessByOffset(instanceDataBuffer.data(), instanceUboOffsets.worldMatrixOffset) = Nz::Matrix4f::Translate(Nz::Vector3f::Up() * 2.f); + + std::shared_ptr& instanceDataUBO = planeInstance.GetInstanceBuffer(); + instanceDataUBO->Fill(instanceDataBuffer.data(), 0, instanceDataBuffer.size()); + } + + std::shared_ptr viewerDataUBO = Nz::Graphics::Instance()->GetViewerDataUBO(); + + Nz::RenderWindowImpl* windowImpl = window.GetImpl(); + std::shared_ptr commandPool = windowImpl->CreateCommandPool(Nz::QueueType::Graphics); + + Nz::RenderPipelineLayoutInfo fullscreenPipelineLayoutInfo; + fullscreenPipelineLayoutInfo.bindings.push_back({ + Nz::ShaderBindingType::Texture, + Nz::ShaderStageType::Fragment, + 0 + }); + + Nz::RenderPipelineLayoutInfo lightingPipelineLayoutInfo; + for (unsigned int i = 0; i < 3; ++i) + { + lightingPipelineLayoutInfo.bindings.push_back({ + Nz::ShaderBindingType::Texture, + Nz::ShaderStageType::Fragment, + i + }); + } + + lightingPipelineLayoutInfo.bindings.push_back({ + Nz::ShaderBindingType::UniformBuffer, + Nz::ShaderStageType::Fragment | Nz::ShaderStageType::Vertex, + 3 + }); + + lightingPipelineLayoutInfo.bindings.push_back({ + Nz::ShaderBindingType::UniformBuffer, + Nz::ShaderStageType::Fragment | Nz::ShaderStageType::Vertex, + 4 + }); + + /*Nz::FieldOffsets pointLightOffsets(Nz::StructLayout::Std140); + std::size_t colorOffset = pointLightOffsets.AddField(Nz::StructFieldType::Float3); + std::size_t positionOffset = pointLightOffsets.AddField(Nz::StructFieldType::Float3); + std::size_t constantOffset = pointLightOffsets.AddField(Nz::StructFieldType::Float1); + std::size_t linearOffset = pointLightOffsets.AddField(Nz::StructFieldType::Float1); + std::size_t quadraticOffset = pointLightOffsets.AddField(Nz::StructFieldType::Float1); + + std::size_t alignedPointLightSize = Nz::Align(pointLightOffsets.GetSize(), static_cast(deviceInfo.limits.minUniformBufferOffsetAlignment));*/ + + /* + [layout(std140)] + struct SpotLight + { + color: vec3, + position: vec3, + direction: vec3, + + constant: f32, + linear: f32, + quadratic: f32, + + innerAngle: f32, + outerAngle: f32, + } + */ + + Nz::FieldOffsets spotLightOffsets(Nz::StructLayout::Std140); + std::size_t transformMatrixOffset = spotLightOffsets.AddMatrix(Nz::StructFieldType::Float1, 4, 4, true); + std::size_t colorOffset = spotLightOffsets.AddField(Nz::StructFieldType::Float3); + std::size_t positionOffset = spotLightOffsets.AddField(Nz::StructFieldType::Float3); + std::size_t directionOffset = spotLightOffsets.AddField(Nz::StructFieldType::Float3); + std::size_t radiusOffset = spotLightOffsets.AddField(Nz::StructFieldType::Float1); + std::size_t invRadiusOffset = spotLightOffsets.AddField(Nz::StructFieldType::Float1); + std::size_t innerAngleOffset = spotLightOffsets.AddField(Nz::StructFieldType::Float1); + std::size_t outerAngleOffset = spotLightOffsets.AddField(Nz::StructFieldType::Float1); + + std::size_t alignedSpotLightSize = Nz::Align(spotLightOffsets.GetAlignedSize(), static_cast(deviceInfo.limits.minUniformBufferOffsetAlignment)); + + constexpr std::size_t MaxPointLight = 2000; + + std::shared_ptr lightUbo = device->InstantiateBuffer(Nz::BufferType::Uniform); + if (!lightUbo->Initialize(MaxPointLight * alignedSpotLightSize, Nz::BufferUsage::DeviceLocal | Nz::BufferUsage::Dynamic)) + return __LINE__; + + std::vector spotLights; + /*auto& firstSpot = spotLights.emplace_back(); + firstSpot.position = Nz::Vector3f::Right() + Nz::Vector3f::Forward(); + firstSpot.direction = Nz::Vector3f::Up();*/ + + std::random_device rng; + std::mt19937 randomEngine(rng()); + std::uniform_int_distribution colorDis(0, 255); + std::uniform_real_distribution heightDis(1.5f, 1.95f); + std::uniform_real_distribution posDis(-10.f, 10.f); + std::uniform_real_distribution dirDis(-1.f, 1.f); + std::uniform_real_distribution dirYDis(0.0f, 0.33f); + std::uniform_real_distribution radiusDis(1.f, 5.f); + + for (std::size_t i = 0; i < 1000; ++i) + { + auto& light = spotLights.emplace_back(); + light.color = Nz::Color(colorDis(randomEngine), colorDis(randomEngine), colorDis(randomEngine)); + light.position = Nz::Vector3f(posDis(randomEngine), heightDis(randomEngine), posDis(randomEngine)); + light.direction = Nz::Vector3f(dirDis(randomEngine), dirYDis(randomEngine), dirDis(randomEngine)).GetNormal(); + light.radius = radiusDis(randomEngine); + } + + + const std::shared_ptr& fullscreenVertexDeclaration = Nz::VertexDeclaration::Get(Nz::VertexLayout::XYZ_UV); + + + unsigned int offscreenWidth = window.GetSize().x; + unsigned int offscreenHeight = window.GetSize().y; + + // Bloom data + + Nz::RenderPipelineLayoutInfo bloomPipelineLayoutInfo; + bloomPipelineLayoutInfo.bindings.push_back({ + Nz::ShaderBindingType::Texture, + Nz::ShaderStageType::Fragment, + 0 + }); + + bloomPipelineLayoutInfo.bindings.push_back({ + Nz::ShaderBindingType::UniformBuffer, + Nz::ShaderStageType::Fragment, + 1 + }); + + Nz::RenderPipelineLayoutInfo bloomBlendPipelineLayoutInfo; + bloomBlendPipelineLayoutInfo.bindings.push_back({ + Nz::ShaderBindingType::Texture, + Nz::ShaderStageType::Fragment, + 0 + }); + + bloomBlendPipelineLayoutInfo.bindings.push_back({ + Nz::ShaderBindingType::Texture, + Nz::ShaderStageType::Fragment, + 1 + }); + + bloomBlendPipelineLayoutInfo.bindings.push_back({ + Nz::ShaderBindingType::UniformBuffer, + Nz::ShaderStageType::Fragment, + 2 + }); + + Nz::RenderPipelineInfo bloomPipelineInfo; + bloomPipelineInfo.primitiveMode = Nz::PrimitiveMode::TriangleList; + bloomPipelineInfo.pipelineLayout = device->InstantiateRenderPipelineLayout(bloomPipelineLayoutInfo); + bloomPipelineInfo.vertexBuffers.push_back({ + 0, + fullscreenVertexDeclaration + }); + + bloomPipelineInfo.shaderModules.push_back(device->InstantiateShaderModule(Nz::ShaderStageType::Fragment | Nz::ShaderStageType::Vertex, Nz::ShaderLanguage::NazaraShader, resourceDir / "bloom_bright.nzsl", {})); + + std::shared_ptr bloomBrightShaderBinding = bloomPipelineInfo.pipelineLayout->AllocateShaderBinding(); + std::shared_ptr gaussianBlurShaderBinding = bloomPipelineInfo.pipelineLayout->AllocateShaderBinding(); + + std::shared_ptr bloomBrightPipeline = device->InstantiateRenderPipeline(bloomPipelineInfo); + + bloomPipelineInfo.shaderModules.clear(); + bloomPipelineInfo.shaderModules.push_back(device->InstantiateShaderModule(Nz::ShaderStageType::Fragment | Nz::ShaderStageType::Vertex, Nz::ShaderLanguage::NazaraShader, resourceDir / "gaussian_blur.nzsl", {})); + + std::shared_ptr gaussianBlurPipeline = device->InstantiateRenderPipeline(bloomPipelineInfo); + + Nz::RenderPipelineInfo bloomBlendPipelineInfo; + bloomBlendPipelineInfo.primitiveMode = Nz::PrimitiveMode::TriangleList; + bloomBlendPipelineInfo.pipelineLayout = device->InstantiateRenderPipelineLayout(bloomBlendPipelineLayoutInfo); + bloomBlendPipelineInfo.vertexBuffers.push_back({ + 0, + fullscreenVertexDeclaration + }); + + bloomBlendPipelineInfo.shaderModules.push_back(device->InstantiateShaderModule(Nz::ShaderStageType::Fragment | Nz::ShaderStageType::Vertex, Nz::ShaderLanguage::NazaraShader, resourceDir / "bloom_final.nzsl", {})); + + std::shared_ptr bloomBlendPipeline = device->InstantiateRenderPipeline(bloomBlendPipelineInfo); + + std::shared_ptr bloomBlendShaderBinding = bloomBlendPipelineInfo.pipelineLayout->AllocateShaderBinding(); + + // Fullscreen data + + Nz::RenderPipelineInfo fullscreenPipelineInfo; + fullscreenPipelineInfo.primitiveMode = Nz::PrimitiveMode::TriangleList; + fullscreenPipelineInfo.pipelineLayout = device->InstantiateRenderPipelineLayout(fullscreenPipelineLayoutInfo); + fullscreenPipelineInfo.vertexBuffers.push_back({ + 0, + fullscreenVertexDeclaration + }); + + fullscreenPipelineInfo.shaderModules.push_back(device->InstantiateShaderModule(Nz::ShaderStageType::Fragment, Nz::ShaderLanguage::NazaraBinary, resourceDir / "fullscreen.frag.shader", {})); + fullscreenPipelineInfo.shaderModules.push_back(device->InstantiateShaderModule(Nz::ShaderStageType::Vertex, Nz::ShaderLanguage::NazaraBinary, resourceDir / "fullscreen.vert.shader", {})); + + + const std::shared_ptr& lightingVertexDeclaration = Nz::VertexDeclaration::Get(Nz::VertexLayout::XYZ_UV); + + std::shared_ptr fullscreenPipeline = device->InstantiateRenderPipeline(fullscreenPipelineInfo); + + Nz::RenderPipelineInfo lightingPipelineInfo; + lightingPipelineInfo.blending = true; + lightingPipelineInfo.blend.dstColor = Nz::BlendFunc::One; + lightingPipelineInfo.blend.srcColor = Nz::BlendFunc::One; + lightingPipelineInfo.primitiveMode = Nz::PrimitiveMode::TriangleList; + lightingPipelineInfo.pipelineLayout = device->InstantiateRenderPipelineLayout(lightingPipelineLayoutInfo); + lightingPipelineInfo.vertexBuffers.push_back({ + 0, + meshPrimitiveParams.vertexDeclaration + }); + lightingPipelineInfo.depthBuffer = false; + lightingPipelineInfo.faceCulling = true; + lightingPipelineInfo.cullingSide = Nz::FaceSide::Front; + lightingPipelineInfo.stencilTest = true; + lightingPipelineInfo.stencilBack.compare = Nz::RendererComparison::NotEqual; + lightingPipelineInfo.stencilBack.fail = Nz::StencilOperation::Zero; + lightingPipelineInfo.stencilBack.depthFail = Nz::StencilOperation::Zero; + lightingPipelineInfo.stencilBack.pass = Nz::StencilOperation::Zero; + + lightingPipelineInfo.shaderModules.push_back(device->InstantiateShaderModule(Nz::ShaderStageType::Fragment | Nz::ShaderStageType::Vertex, Nz::ShaderLanguage::NazaraShader, resourceDir / "lighting.nzsl", {})); + + std::shared_ptr lightingPipeline = device->InstantiateRenderPipeline(lightingPipelineInfo); + + Nz::RenderPipelineInfo stencilPipelineInfo; + stencilPipelineInfo.primitiveMode = Nz::PrimitiveMode::TriangleList; + stencilPipelineInfo.pipelineLayout = device->InstantiateRenderPipelineLayout(lightingPipelineLayoutInfo); + stencilPipelineInfo.vertexBuffers.push_back({ + 0, + meshPrimitiveParams.vertexDeclaration + }); + + stencilPipelineInfo.colorWrite = false; + stencilPipelineInfo.depthBuffer = true; + stencilPipelineInfo.depthWrite = false; + stencilPipelineInfo.faceCulling = false; + stencilPipelineInfo.stencilTest = true; + stencilPipelineInfo.stencilFront.compare = Nz::RendererComparison::Always; + stencilPipelineInfo.stencilFront.depthFail = Nz::StencilOperation::Invert; + stencilPipelineInfo.stencilBack.compare = Nz::RendererComparison::Always; + stencilPipelineInfo.stencilBack.depthFail = Nz::StencilOperation::Invert; + + stencilPipelineInfo.shaderModules.push_back(device->InstantiateShaderModule(Nz::ShaderStageType::Vertex, Nz::ShaderLanguage::NazaraShader, resourceDir / "lighting.nzsl", {})); + + std::shared_ptr stencilPipeline = device->InstantiateRenderPipeline(stencilPipelineInfo); + + + std::vector> lightingShaderBindings; + + std::array vertexData = { + { + { + Nz::Vector3f(-1.f, 1.f, 0.0f), + Nz::Vector2f(0.0f, 1.0f), + }, + { + Nz::Vector3f(-1.f, -3.f, 0.0f), + Nz::Vector2f(0.0f, -1.0f), + }, + { + Nz::Vector3f(3.f, 1.f, 0.0f), + Nz::Vector2f(2.0f, 1.0f), + } + } + }; + + /*std::array vertexData = { + { + { + Nz::Vector3f(-1.f, -1.f, 0.0f), + Nz::Vector2f(0.0f, 0.0f), + }, + { + Nz::Vector3f(1.f, -1.f, 0.0f), + Nz::Vector2f(1.0f, 0.0f), + }, + { + Nz::Vector3f(-1.f, 1.f, 0.0f), + Nz::Vector2f(0.0f, 1.0f), + }, + { + Nz::Vector3f(1.f, 1.f, 0.0f), + Nz::Vector2f(1.0f, 1.0f), + }, + } + };*/ + + std::shared_ptr fullscreenVertexBuffer = device->InstantiateBuffer(Nz::BufferType::Vertex); + if (!fullscreenVertexBuffer->Initialize(fullscreenVertexDeclaration->GetStride() * vertexData.size(), Nz::BufferUsage::DeviceLocal)) + return __LINE__; + + if (!fullscreenVertexBuffer->Fill(vertexData.data(), 0, fullscreenVertexBuffer->GetSize())) + return __LINE__; + + std::shared_ptr finalBlitBinding = fullscreenPipelineInfo.pipelineLayout->AllocateShaderBinding(); + + bool viewerUboUpdate = true; + bool lightUpdate = true; + + std::shared_ptr textureSampler = device->InstantiateTextureSampler({}); + + std::shared_ptr skyboxShaderBinding = skyboxPipelineLayout->AllocateShaderBinding(); + skyboxShaderBinding->Update({ + { + 0, + Nz::ShaderBinding::UniformBufferBinding { + viewerDataUBO.get(), + 0, viewerDataUBO->GetSize() + } + }, + { + 1, + Nz::ShaderBinding::TextureBinding { + skyboxTexture.get(), + textureSampler.get() + } + } + }); + + bool bloomEnabled = true; + bool forwardEnabled = true; + bool lightAnimation = true; + + std::size_t colorTexture; + std::size_t normalTexture; + std::size_t positionTexture; + std::size_t depthBuffer; + std::size_t backbuffer; + std::size_t bloomTextureA; + std::size_t bloomTextureB; + std::size_t lightOutput; + + Nz::BakedFrameGraph bakedGraph = [&] + { + Nz::PixelFormat depthStencilFormat = Nz::PixelFormat::Undefined; + for (Nz::PixelFormat candidate : { Nz::PixelFormat::Depth24Stencil8, Nz::PixelFormat::Depth32FStencil8, Nz::PixelFormat::Depth16Stencil8 }) + { + if (device->IsTextureFormatSupported(candidate, Nz::TextureUsage::DepthStencilAttachment)) + { + depthStencilFormat = candidate; + break; + } + } + + if (depthStencilFormat == Nz::PixelFormat::Undefined) + { + std::cerr << "no depth-stencil format found" << std::endl; + std::exit(__LINE__); + } + + Nz::FrameGraph graph; + + colorTexture = graph.AddAttachment({ + "Color", + Nz::PixelFormat::RGBA8 + }); + + normalTexture = graph.AddAttachment({ + "Normal", + Nz::PixelFormat::RGBA8 + }); + + positionTexture = graph.AddAttachment({ + "Position", + Nz::PixelFormat::RGBA32F + }); + + depthBuffer = graph.AddAttachment({ + "Depth buffer", + depthStencilFormat + }); + + lightOutput = graph.AddAttachment({ + "Light output", + Nz::PixelFormat::RGBA8 + }); + + backbuffer = graph.AddAttachment({ + "Backbuffer", + Nz::PixelFormat::RGBA8 + }); + + bloomTextureA = graph.AddAttachment({ + "Bloom texture A", + Nz::PixelFormat::RGBA8, + 10'000, + 10'000 + }); + + bloomTextureB = graph.AddAttachment({ + "Bloom texture B", + Nz::PixelFormat::RGBA8, + 10'000, + 10'000 + }); + + Nz::FramePass& gbufferPass = graph.AddPass("GBuffer"); + + std::size_t geometryAlbedo = gbufferPass.AddOutput(colorTexture); + gbufferPass.SetClearColor(geometryAlbedo, Nz::Color::Black); + + std::size_t geometryNormal = gbufferPass.AddOutput(normalTexture); + gbufferPass.SetClearColor(geometryNormal, Nz::Color::Black); + + std::size_t positionAttachment = gbufferPass.AddOutput(positionTexture); + gbufferPass.SetClearColor(positionAttachment, Nz::Color::Black); + + gbufferPass.SetDepthStencilClear(1.f, 0); + + gbufferPass.SetDepthStencilOutput(depthBuffer); + + gbufferPass.SetCommandCallback([&](Nz::CommandBufferBuilder& builder) + { + builder.SetScissor(Nz::Recti{ 0, 0, int(offscreenWidth), int(offscreenHeight) }); + builder.SetViewport(Nz::Recti{ 0, 0, int(offscreenWidth), int(offscreenHeight) }); + + for (Nz::ModelInstance& modelInstance : { std::ref(modelInstance1), std::ref(modelInstance2) }) + { + builder.BindShaderBinding(modelInstance.GetShaderBinding()); + + for (std::size_t i = 0; i < spaceshipModel.GetSubMeshCount(); ++i) + { + builder.BindIndexBuffer(spaceshipModel.GetIndexBuffer(i).get()); + builder.BindVertexBuffer(0, spaceshipModel.GetVertexBuffer(i).get()); + builder.BindPipeline(*spaceshipModel.GetRenderPipeline(i)); + + builder.DrawIndexed(static_cast(spaceshipModel.GetIndexCount(i))); + } + } + + // Plane + builder.BindShaderBinding(planeInstance.GetShaderBinding()); + + for (std::size_t i = 0; i < planeModel.GetSubMeshCount(); ++i) + { + builder.BindIndexBuffer(planeModel.GetIndexBuffer(i).get()); + builder.BindVertexBuffer(0, planeModel.GetVertexBuffer(i).get()); + builder.BindPipeline(*planeModel.GetRenderPipeline(i)); + + builder.DrawIndexed(static_cast(planeModel.GetIndexCount(i))); + } + }); + + Nz::FramePass& lightingPass = graph.AddPass("Lighting pass"); + lightingPass.SetExecutionCallback([&] + { + return (viewerUboUpdate) ? Nz::FramePassExecution::UpdateAndExecute : Nz::FramePassExecution::Execute; + }); + + lightingPass.SetCommandCallback([&](Nz::CommandBufferBuilder& builder) + { + builder.SetScissor(Nz::Recti{ 0, 0, int(offscreenWidth), int(offscreenHeight) }); + builder.SetViewport(Nz::Recti{ 0, 0, int(offscreenWidth), int(offscreenHeight) }); + + //builder.BindVertexBuffer(0, vertexBuffer.get()); + builder.BindIndexBuffer(coneMeshGfx->GetIndexBuffer(0).get()); + builder.BindVertexBuffer(0, coneMeshGfx->GetVertexBuffer(0).get()); + + for (std::size_t i = 0; i < spotLights.size(); ++i) + { + builder.BindShaderBinding(*lightingShaderBindings[i]); + + builder.BindPipeline(*stencilPipeline); + builder.DrawIndexed(coneMeshGfx->GetIndexCount(0)); + + builder.BindPipeline(*lightingPipeline); + builder.DrawIndexed(coneMeshGfx->GetIndexCount(0)); + } + }); + + lightingPass.AddInput(colorTexture); + lightingPass.AddInput(normalTexture); + lightingPass.AddInput(positionTexture); + lightingPass.SetClearColor(lightingPass.AddOutput(lightOutput), Nz::Color::Black); + lightingPass.SetDepthStencilInput(depthBuffer); + lightingPass.SetDepthStencilOutput(depthBuffer); + + Nz::FramePass& forwardPass = graph.AddPass("Forward pass"); + forwardPass.SetCommandCallback([&](Nz::CommandBufferBuilder& builder) + { + builder.SetScissor(Nz::Recti{ 0, 0, int(offscreenWidth), int(offscreenHeight) }); + builder.SetViewport(Nz::Recti{ 0, 0, int(offscreenWidth), int(offscreenHeight) }); + + builder.BindShaderBinding(*skyboxShaderBinding); + + builder.BindIndexBuffer(cubeMeshGfx->GetIndexBuffer(0).get()); + builder.BindVertexBuffer(0, cubeMeshGfx->GetVertexBuffer(0).get()); + builder.BindPipeline(*skyboxPipeline); + + builder.DrawIndexed(static_cast(cubeMeshGfx->GetIndexCount(0))); + }); + forwardPass.SetExecutionCallback([&] + { + return (forwardEnabled) ? Nz::FramePassExecution::Execute : Nz::FramePassExecution::Skip; + }); + + forwardPass.AddInput(lightOutput); + forwardPass.AddOutput(lightOutput); + forwardPass.SetDepthStencilInput(depthBuffer); + forwardPass.SetDepthStencilOutput(depthBuffer); + + + Nz::FramePass& bloomBrightPass = graph.AddPass("Bloom pass - extract bright pixels"); + bloomBrightPass.SetCommandCallback([&](Nz::CommandBufferBuilder& builder) + { + builder.SetScissor(Nz::Recti{ 0, 0, int(offscreenWidth) / 10, int(offscreenHeight) / 10 }); + builder.SetViewport(Nz::Recti{ 0, 0, int(offscreenWidth) / 10, int(offscreenHeight) / 10 }); + + builder.BindShaderBinding(*bloomBrightShaderBinding); + builder.BindPipeline(*bloomBrightPipeline); + builder.BindVertexBuffer(0, fullscreenVertexBuffer.get()); + + builder.Draw(3); + }); + bloomBrightPass.SetExecutionCallback([&] + { + return (bloomEnabled) ? Nz::FramePassExecution::Execute : Nz::FramePassExecution::Skip; + }); + + bloomBrightPass.AddInput(lightOutput); + bloomBrightPass.AddOutput(bloomTextureA); + + Nz::FramePass& bloomBlurPass = graph.AddPass("Bloom pass - gaussian blur"); + bloomBlurPass.SetCommandCallback([&](Nz::CommandBufferBuilder& builder) + { + builder.SetScissor(Nz::Recti{ 0, 0, int(offscreenWidth) / 10, int(offscreenHeight) / 10 }); + builder.SetViewport(Nz::Recti{ 0, 0, int(offscreenWidth) / 10, int(offscreenHeight) / 10 }); + + builder.BindShaderBinding(*gaussianBlurShaderBinding); + builder.BindPipeline(*gaussianBlurPipeline); + builder.BindVertexBuffer(0, fullscreenVertexBuffer.get()); + + builder.Draw(3); + }); + bloomBlurPass.SetExecutionCallback([&] + { + return (bloomEnabled) ? Nz::FramePassExecution::Execute : Nz::FramePassExecution::Skip; + }); + + bloomBlurPass.AddInput(bloomTextureA); + bloomBlurPass.AddOutput(bloomTextureB); + + Nz::FramePass& bloomBlendPass = graph.AddPass("Bloom pass - blend"); + bloomBlendPass.SetCommandCallback([&](Nz::CommandBufferBuilder& builder) + { + builder.SetScissor(Nz::Recti{ 0, 0, int(offscreenWidth), int(offscreenHeight) }); + builder.SetViewport(Nz::Recti{ 0, 0, int(offscreenWidth), int(offscreenHeight) }); + + builder.BindShaderBinding(*bloomBlendShaderBinding); + builder.BindPipeline(*bloomBlendPipeline); + builder.BindVertexBuffer(0, fullscreenVertexBuffer.get()); + + builder.Draw(3); + }); + bloomBlendPass.SetExecutionCallback([&] + { + return (bloomEnabled) ? Nz::FramePassExecution::Execute : Nz::FramePassExecution::Skip; + }); + + bloomBlendPass.AddInput(lightOutput); + bloomBlendPass.AddInput(bloomTextureB); + bloomBlendPass.AddOutput(backbuffer); + + graph.SetBackbufferOutput(backbuffer); + + return graph.Bake(); + }(); + + bakedGraph.Resize(offscreenWidth, offscreenHeight); + + + for (std::size_t i = 0; i < MaxPointLight; ++i) + { + std::shared_ptr lightingShaderBinding = lightingPipelineInfo.pipelineLayout->AllocateShaderBinding(); + lightingShaderBinding->Update({ + { + 0, + Nz::ShaderBinding::TextureBinding { + bakedGraph.GetAttachmentTexture(colorTexture).get(), + textureSampler.get() + } + }, + { + 1, + Nz::ShaderBinding::TextureBinding { + bakedGraph.GetAttachmentTexture(normalTexture).get(), + textureSampler.get() + } + }, + { + 2, + Nz::ShaderBinding::TextureBinding { + bakedGraph.GetAttachmentTexture(positionTexture).get(), + textureSampler.get() + } + }, + { + 3, + Nz::ShaderBinding::UniformBufferBinding { + lightUbo.get(), + i * alignedSpotLightSize, spotLightOffsets.GetAlignedSize() + } + }, + { + 4, + Nz::ShaderBinding::UniformBufferBinding { + viewerDataUBO.get(), + 0, viewerDataUBO->GetSize() + } + } + }); + + lightingShaderBindings.emplace_back(std::move(lightingShaderBinding)); + } + + bloomBrightShaderBinding->Update({ + { + 0, + Nz::ShaderBinding::TextureBinding { + bakedGraph.GetAttachmentTexture(lightOutput).get(), + textureSampler.get() + } + }, + { + 1, + Nz::ShaderBinding::UniformBufferBinding { + viewerDataUBO.get(), + 0, viewerDataUBO->GetSize() + } + } + }); + + gaussianBlurShaderBinding->Update({ + { + 0, + Nz::ShaderBinding::TextureBinding { + bakedGraph.GetAttachmentTexture(bloomTextureA).get(), + textureSampler.get() + } + }, + { + 1, + Nz::ShaderBinding::UniformBufferBinding { + viewerDataUBO.get(), + 0, viewerDataUBO->GetSize() + } + } + }); + + bloomBlendShaderBinding->Update({ + { + 0, + Nz::ShaderBinding::TextureBinding { + bakedGraph.GetAttachmentTexture(lightOutput).get(), + textureSampler.get() + } + }, + { + 1, + Nz::ShaderBinding::TextureBinding { + bakedGraph.GetAttachmentTexture(bloomTextureB).get(), + textureSampler.get() + } + }, + { + 2, + Nz::ShaderBinding::UniformBufferBinding { + viewerDataUBO.get(), + 0, viewerDataUBO->GetSize() + } + } + }); + + finalBlitBinding->Update({ + { + 0, + Nz::ShaderBinding::TextureBinding { + bakedGraph.GetAttachmentTexture(backbuffer).get(), + textureSampler.get() + } + } + }); + + + Nz::CommandBufferPtr drawCommandBuffer; + auto RebuildCommandBuffer = [&] + { + Nz::Vector2ui windowSize = window.GetSize(); + + drawCommandBuffer = commandPool->BuildCommandBuffer([&](Nz::CommandBufferBuilder& builder) + { + Nz::Recti windowRenderRect(0, 0, window.GetSize().x, window.GetSize().y); + + builder.TextureBarrier(Nz::PipelineStage::ColorOutput, Nz::PipelineStage::FragmentShader, Nz::MemoryAccess::ColorWrite, Nz::MemoryAccess::ShaderRead, Nz::TextureLayout::ColorOutput, Nz::TextureLayout::ColorInput, *bakedGraph.GetAttachmentTexture(backbuffer)); + + builder.BeginDebugRegion("Main window rendering", Nz::Color::Green); + { + builder.BeginRenderPass(windowImpl->GetFramebuffer(), windowImpl->GetRenderPass(), windowRenderRect); + { + builder.SetScissor(Nz::Recti{ 0, 0, int(windowSize.x), int(windowSize.y) }); + builder.SetViewport(Nz::Recti{ 0, 0, int(windowSize.x), int(windowSize.y) }); + + builder.BindShaderBinding(*finalBlitBinding); + builder.BindPipeline(*fullscreenPipeline); + builder.BindVertexBuffer(0, fullscreenVertexBuffer.get()); + builder.Draw(3); + } + builder.EndRenderPass(); + } + builder.EndDebugRegion(); + }); + }; + RebuildCommandBuffer(); + + + Nz::Vector3f viewerPos = Nz::Vector3f::Backward() * 10.f + Nz::Vector3f::Up() * -3.f; + + Nz::EulerAnglesf camAngles(30.f, 0.f, 0.f); + Nz::Quaternionf camQuat(camAngles); + + window.EnableEventPolling(true); + + Nz::Clock updateClock; + Nz::Clock secondClock; + unsigned int fps = 0; + + std::size_t totalFrameCount = 0; + + Nz::Mouse::SetRelativeMouseMode(true); + + float elapsedTime = 0.f; + Nz::UInt64 time = Nz::GetElapsedMicroseconds(); + + auto ComputeLightAnimationSpeed = [](const Nz::Vector3f& position) + { + return position.GetLength() / 15.f; + }; + + auto AnimateLightPosition = [](const Nz::Vector3f& position, float rotationSpeed, float elapsedTime) + { + rotationSpeed *= 45.f; + + return Nz::Matrix4f::Rotate(Nz::EulerAnglesf(0.f, elapsedTime * rotationSpeed, 0.f)) * position; + }; + + auto AnimateLightDirection = [](const Nz::Vector3f& direction, float rotationSpeed, float elapsedTime) + { + rotationSpeed *= 90.f; + + return Nz::Matrix4f::Rotate(Nz::EulerAnglesf(0.f, elapsedTime * rotationSpeed, 0.f)) * direction; + }; + + while (window.IsOpen()) + { + Nz::UInt64 now = Nz::GetElapsedMicroseconds(); + if (lightAnimation) + elapsedTime += (now - time) / 1'000'000.f; + time = now; + + Nz::WindowEvent event; + while (window.PollEvent(&event)) + { + switch (event.type) + { + case Nz::WindowEventType::Quit: + window.Close(); + break; + + case Nz::WindowEventType::MouseMoved: // La souris a bougé + { + // Gestion de la caméra free-fly (Rotation) + float sensitivity = 0.3f; // Sensibilité de la souris + + // On modifie l'angle de la caméra grâce au déplacement relatif sur X de la souris + camAngles.yaw = camAngles.yaw - event.mouseMove.deltaX*sensitivity; + camAngles.yaw.Normalize(); + + // Idem, mais pour éviter les problèmes de calcul de la matrice de vue, on restreint les angles + camAngles.pitch = Nz::Clamp(camAngles.pitch + event.mouseMove.deltaY*sensitivity, -89.f, 89.f); + + camQuat = camAngles; + + viewerUboUpdate = true; + break; + } + + case Nz::WindowEventType::KeyPressed: + { + if (event.key.scancode == Nz::Keyboard::Scancode::Space) + { + float rotationSpeed = ComputeLightAnimationSpeed(viewerPos); + + auto& whiteLight = spotLights.emplace_back(); + whiteLight.radius = 5.f; + whiteLight.position = AnimateLightPosition(viewerPos, rotationSpeed, -elapsedTime); + whiteLight.direction = AnimateLightDirection(camQuat * Nz::Vector3f::Forward(), rotationSpeed, -elapsedTime); + + lightUpdate = true; + } + else if (event.key.virtualKey == Nz::Keyboard::VKey::F) + forwardEnabled = !forwardEnabled; + else if (event.key.virtualKey == Nz::Keyboard::VKey::A) + lightAnimation = !lightAnimation; + break; + } + + case Nz::WindowEventType::Resized: + { + Nz::Vector2ui windowSize = window.GetSize(); + Nz::AccessByOffset(viewerDataBuffer.data(), viewerUboOffsets.projMatrixOffset) = Nz::Matrix4f::Perspective(Nz::DegreeAnglef(70.f), float(windowSize.x) / windowSize.y, 0.1f, 1000.f); + viewerUboUpdate = true; + break; + } + + default: + break; + } + } + + if (updateClock.GetMilliseconds() > 1000 / 60) + { + float cameraSpeed = 2.f * updateClock.GetSeconds(); + updateClock.Restart(); + + if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Up) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Z)) + viewerPos += camQuat * Nz::Vector3f::Forward() * cameraSpeed; + + // Si la flèche du bas ou la touche S est pressée, on recule + if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Down) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::S)) + viewerPos += camQuat * Nz::Vector3f::Backward() * cameraSpeed; + + // Etc... + if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Left) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Q)) + viewerPos += camQuat * Nz::Vector3f::Left() * cameraSpeed; + + // Etc... + if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Right) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::D)) + viewerPos += camQuat * Nz::Vector3f::Right() * cameraSpeed; + + // Majuscule pour monter, notez l'utilisation d'une direction globale (Non-affectée par la rotation) + if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::LShift) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::RShift)) + viewerPos += Nz::Vector3f::Up() * cameraSpeed; + + // Contrôle (Gauche ou droite) pour descendre dans l'espace global, etc... + if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::LControl) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::RControl)) + viewerPos += Nz::Vector3f::Down() * cameraSpeed; + + viewerUboUpdate = true; + } + + Nz::RenderFrame frame = windowImpl->Acquire(); + if (!frame) + continue; + + if (frame.IsFramebufferInvalidated()) + RebuildCommandBuffer(); + + if (viewerUboUpdate || lightAnimation || lightUpdate) + { + Nz::AccessByOffset(viewerDataBuffer.data(), viewerUboOffsets.viewMatrixOffset) = Nz::Matrix4f::ViewMatrix(viewerPos, camAngles); + + //Nz::AccessByOffset(lightData.data(), colorOffset) = Nz::Vector3f(std::sin(totalFrameCount / 10000.f) * 0.5f + 0.5f, std::cos(totalFrameCount / 1000.f) * 0.5f + 0.5f, std::sin(totalFrameCount / 100.f) * 0.5f + 0.5f); + + Nz::UploadPool& uploadPool = frame.GetUploadPool(); + + frame.Execute([&](Nz::CommandBufferBuilder& builder) + { + builder.BeginDebugRegion("UBO Update", Nz::Color::Yellow); + { + builder.PreTransferBarrier(); + + if (viewerUboUpdate) + { + auto& viewerDataAllocation = uploadPool.Allocate(viewerDataBuffer.size()); + std::memcpy(viewerDataAllocation.mappedPtr, viewerDataBuffer.data(), viewerDataBuffer.size()); + builder.CopyBuffer(viewerDataAllocation, viewerDataUBO.get()); + } + + if (!spotLights.empty() && (lightUpdate || lightAnimation)) + { + auto& lightDataAllocation = uploadPool.Allocate(alignedSpotLightSize * spotLights.size()); + Nz::UInt8* lightDataPtr = static_cast(lightDataAllocation.mappedPtr); + + for (const SpotLight& spotLight : spotLights) + { + float rotationSpeed = ComputeLightAnimationSpeed(spotLight.position); + + Nz::Vector3f position = AnimateLightPosition(spotLight.position, rotationSpeed, elapsedTime); + Nz::Vector3f direction = AnimateLightDirection(spotLight.direction, rotationSpeed, elapsedTime); + + Nz::AccessByOffset(lightDataPtr, colorOffset) = Nz::Vector3f(spotLight.color.r / 255.f, spotLight.color.g / 255.f, spotLight.color.b / 255.f); + Nz::AccessByOffset(lightDataPtr, positionOffset) = position; + Nz::AccessByOffset(lightDataPtr, directionOffset) = direction; + Nz::AccessByOffset(lightDataPtr, radiusOffset) = spotLight.radius; + Nz::AccessByOffset(lightDataPtr, invRadiusOffset) = 1.f / spotLight.radius; + Nz::AccessByOffset(lightDataPtr, innerAngleOffset) = spotLight.innerAngle.GetCos(); + Nz::AccessByOffset(lightDataPtr, outerAngleOffset) = spotLight.outerAngle.GetCos(); + + float baseRadius = spotLight.radius * spotLight.outerAngle.GetTan() * 1.1f; + Nz::Matrix4f transformMatrix = Nz::Matrix4f::Transform(position, Nz::Quaternionf::RotationBetween(Nz::Vector3f::Forward(), direction), Nz::Vector3f(baseRadius, baseRadius, spotLight.radius)); + Nz::AccessByOffset(lightDataPtr, transformMatrixOffset) = transformMatrix; + + lightDataPtr += alignedSpotLightSize; + } + + builder.CopyBuffer(lightDataAllocation, lightUbo.get()); + + lightUpdate = false; + } + + spaceshipMat->UpdateBuffers(uploadPool, builder); + + builder.PostTransferBarrier(); + } + builder.EndDebugRegion(); + }, Nz::QueueType::Transfer); + } + + bakedGraph.Execute(frame); + frame.SubmitCommandBuffer(drawCommandBuffer.get(), Nz::QueueType::Graphics); + + frame.Present(); + + window.Display(); + + viewerUboUpdate = false; + + // On incrémente le compteur de FPS improvisé + fps++; + totalFrameCount++; + + if (secondClock.GetMilliseconds() >= 1000) // Toutes les secondes + { + // Et on insère ces données dans le titre de la fenêtre + window.SetTitle(windowTitle + " - " + Nz::NumberToString(fps) + " FPS"); + + /* + Note: En C++11 il est possible d'insérer de l'Unicode de façon standard, quel que soit l'encodage du fichier, + via quelque chose de similaire à u8"Cha\u00CEne de caract\u00E8res". + Cependant, si le code source est encodé en UTF-8 (Comme c'est le cas dans ce fichier), + cela fonctionnera aussi comme ceci : "Chaîne de caractères". + */ + + // Et on réinitialise le compteur de FPS + fps = 0; + + // Et on relance l'horloge pour refaire ça dans une seconde + secondClock.Restart(); + } + } + + return EXIT_SUCCESS; +} diff --git a/examples/DeferredShading/xmake.lua b/examples/DeferredShading/xmake.lua new file mode 100644 index 000000000..5a2d9461b --- /dev/null +++ b/examples/DeferredShading/xmake.lua @@ -0,0 +1,5 @@ +target("DeferredShading") + set_group("Examples") + set_kind("binary") + add_deps("NazaraGraphics") + add_files("main.cpp") diff --git a/examples/DopplerEffect/build.lua b/examples/DopplerEffect/build.lua deleted file mode 100644 index 837f62af4..000000000 --- a/examples/DopplerEffect/build.lua +++ /dev/null @@ -1,14 +0,0 @@ -EXAMPLE.Name = "DopplerEffect" - -EXAMPLE.EnableConsole = true - -EXAMPLE.Files = { - "main.cpp" -} - -EXAMPLE.Libraries = { - "NazaraAudio", - "NazaraCore", - "NazaraPlatform", - "NazaraUtility" -} diff --git a/examples/DopplerEffect/main.cpp b/examples/DopplerEffect/main.cpp index dcb760bb6..8dfe7a4de 100644 --- a/examples/DopplerEffect/main.cpp +++ b/examples/DopplerEffect/main.cpp @@ -20,17 +20,14 @@ int main() { - // NzKeyboard nécessite l'initialisation du module Utilitaire + std::filesystem::path resourceDir = "resources"; + if (!std::filesystem::is_directory(resourceDir) && std::filesystem::is_directory(".." / resourceDir)) + resourceDir = ".." / resourceDir; + Nz::Modules audio; - /*if (!audio) - { - std::cout << "Failed to initialize audio module" << std::endl; - std::getchar(); - return 1; - }*/ Nz::Sound sound; - if (!sound.LoadFromFile("resources/siren.wav")) + if (!sound.LoadFromFile(resourceDir / "siren.wav")) { std::cout << "Failed to load sound" << std::endl; std::getchar(); @@ -57,7 +54,7 @@ int main() // La boucle du programme (Pour déplacer le son) Nz::Clock clock; - while (sound.GetStatus() == Nz::SoundStatus_Playing) + while (sound.GetStatus() == Nz::SoundStatus::Playing) { // Comme le son se joue dans un thread séparé, on peut mettre en pause le principal régulièrement int sleepTime = int(1000/60 - clock.GetMilliseconds()); // 60 FPS diff --git a/examples/DopplerEffect/xmake.lua b/examples/DopplerEffect/xmake.lua new file mode 100644 index 000000000..42fd66ae2 --- /dev/null +++ b/examples/DopplerEffect/xmake.lua @@ -0,0 +1,5 @@ +target("DopplerEffect") + set_group("Examples") + set_kind("binary") + add_deps("NazaraAudio", "NazaraPlatform") + add_files("main.cpp") \ No newline at end of file diff --git a/examples/GraphicsTest/main.cpp b/examples/GraphicsTest/main.cpp new file mode 100644 index 000000000..cbdee4428 --- /dev/null +++ b/examples/GraphicsTest/main.cpp @@ -0,0 +1,308 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main() +{ + std::filesystem::path resourceDir = "resources"; + if (!std::filesystem::is_directory(resourceDir) && std::filesystem::is_directory(".." / resourceDir)) + resourceDir = ".." / resourceDir; + + Nz::Renderer::Config rendererConfig; + std::cout << "Run using Vulkan? (y/n)" << std::endl; + if (std::getchar() == 'y') + rendererConfig.preferredAPI = Nz::RenderAPI::Vulkan; + else + rendererConfig.preferredAPI = Nz::RenderAPI::OpenGL; + + Nz::Modules nazara(rendererConfig); + + Nz::RenderWindow window; + + Nz::MeshParams meshParams; + meshParams.storage = Nz::DataStorage::Software; + meshParams.matrix = Nz::Matrix4f::Rotate(Nz::EulerAnglesf(0.f, 90.f, 180.f)) * Nz::Matrix4f::Scale(Nz::Vector3f(0.002f)); + meshParams.vertexDeclaration = Nz::VertexDeclaration::Get(Nz::VertexLayout::XYZ_Normal_UV); + + std::shared_ptr device = Nz::Graphics::Instance()->GetRenderDevice(); + + std::string windowTitle = "Graphics Test"; + if (!window.Create(device, Nz::VideoMode(800, 600, 32), windowTitle)) + { + std::cout << "Failed to create Window" << std::endl; + return __LINE__; + } + + std::shared_ptr spaceshipMesh = Nz::Mesh::LoadFromFile(resourceDir / "Spaceship/spaceship.obj", meshParams); + if (!spaceshipMesh) + { + NazaraError("Failed to load model"); + return __LINE__; + } + + std::shared_ptr gfxMesh = std::make_shared(*spaceshipMesh); + + // Texture + std::shared_ptr diffuseImage = Nz::Image::LoadFromFile(resourceDir / "Spaceship/Texture/diffuse.png"); + if (!diffuseImage || !diffuseImage->Convert(Nz::PixelFormat::RGBA8_SRGB)) + { + NazaraError("Failed to load image"); + return __LINE__; + } + + Nz::TextureParams texParams; + texParams.renderDevice = device; + texParams.loadFormat = Nz::PixelFormat::RGBA8_SRGB; + + std::shared_ptr material = std::make_shared(Nz::BasicMaterial::GetSettings()); + material->EnableDepthBuffer(true); + material->EnableFaceCulling(true); + + Nz::BasicMaterial basicMat(*material); + basicMat.EnableAlphaTest(true); + basicMat.SetAlphaMap(Nz::Texture::LoadFromFile(resourceDir / "alphatile.png", texParams)); + basicMat.SetDiffuseMap(Nz::Texture::LoadFromFile(resourceDir / "Spaceship/Texture/diffuse.png", texParams)); + + Nz::Model model(std::move(gfxMesh)); + for (std::size_t i = 0; i < model.GetSubMeshCount(); ++i) + model.SetMaterial(i, material); + + Nz::PredefinedInstanceData instanceUboOffsets = Nz::PredefinedInstanceData::GetOffsets(); + Nz::PredefinedViewerData viewerUboOffsets = Nz::PredefinedViewerData::GetOffsets(); + const Nz::BasicMaterial::UniformOffsets& materialSettingOffsets = Nz::BasicMaterial::GetOffsets(); + + std::vector viewerDataBuffer(viewerUboOffsets.totalSize); + + Nz::Vector2ui windowSize = window.GetSize(); + + Nz::AccessByOffset(viewerDataBuffer.data(), viewerUboOffsets.viewMatrixOffset) = Nz::Matrix4f::Translate(Nz::Vector3f::Backward() * 1); + Nz::AccessByOffset(viewerDataBuffer.data(), viewerUboOffsets.projMatrixOffset) = Nz::Matrix4f::Perspective(Nz::DegreeAnglef(70.f), float(windowSize.x) / windowSize.y, 0.1f, 1000.f); + + std::vector instanceDataBuffer(instanceUboOffsets.totalSize); + + Nz::ModelInstance modelInstance(material->GetSettings()); + { + material->UpdateShaderBinding(modelInstance.GetShaderBinding()); + + Nz::AccessByOffset(instanceDataBuffer.data(), instanceUboOffsets.worldMatrixOffset) = Nz::Matrix4f::Translate(Nz::Vector3f::Forward() * 2 + Nz::Vector3f::Right()); + + std::shared_ptr& instanceDataUBO = modelInstance.GetInstanceBuffer(); + instanceDataUBO->Fill(instanceDataBuffer.data(), 0, instanceDataBuffer.size()); + } + + Nz::ModelInstance modelInstance2(material->GetSettings()); + { + material->UpdateShaderBinding(modelInstance2.GetShaderBinding()); + + Nz::AccessByOffset(instanceDataBuffer.data(), instanceUboOffsets.worldMatrixOffset) = Nz::Matrix4f::Translate(Nz::Vector3f::Forward() * 2 + Nz::Vector3f::Right() * 3.f); + + std::shared_ptr& instanceDataUBO = modelInstance2.GetInstanceBuffer(); + instanceDataUBO->Fill(instanceDataBuffer.data(), 0, instanceDataBuffer.size()); + } + + std::shared_ptr viewerDataUBO = Nz::Graphics::Instance()->GetViewerDataUBO(); + + Nz::RenderWindowImpl* windowImpl = window.GetImpl(); + std::shared_ptr commandPool = windowImpl->CreateCommandPool(Nz::QueueType::Graphics); + + Nz::CommandBufferPtr drawCommandBuffer; + auto RebuildCommandBuffer = [&] + { + Nz::Vector2ui windowSize = window.GetSize(); + + drawCommandBuffer = commandPool->BuildCommandBuffer([&](Nz::CommandBufferBuilder& builder) + { + Nz::Recti renderRect(0, 0, window.GetSize().x, window.GetSize().y); + + Nz::CommandBufferBuilder::ClearValues clearValues[2]; + clearValues[0].color = Nz::Color::Black; + clearValues[1].depth = 1.f; + clearValues[1].stencil = 0; + + builder.BeginDebugRegion("Main window rendering", Nz::Color::Green); + { + builder.BeginRenderPass(windowImpl->GetFramebuffer(), windowImpl->GetRenderPass(), renderRect, { clearValues[0], clearValues[1] }); + { + builder.SetScissor(Nz::Recti{ 0, 0, int(windowSize.x), int(windowSize.y) }); + builder.SetViewport(Nz::Recti{ 0, 0, int(windowSize.x), int(windowSize.y) }); + + for (Nz::ModelInstance& modelInstance : { std::ref(modelInstance), std::ref(modelInstance2) }) + { + builder.BindShaderBinding(modelInstance.GetShaderBinding()); + + for (std::size_t i = 0; i < model.GetSubMeshCount(); ++i) + { + builder.BindIndexBuffer(model.GetIndexBuffer(i).get()); + builder.BindVertexBuffer(0, model.GetVertexBuffer(i).get()); + builder.BindPipeline(*model.GetRenderPipeline(i)); + + builder.DrawIndexed(model.GetIndexCount(i)); + } + } + } + builder.EndRenderPass(); + } + builder.EndDebugRegion(); + }); + }; + RebuildCommandBuffer(); + + + Nz::Vector3f viewerPos = Nz::Vector3f::Zero(); + + Nz::EulerAnglesf camAngles(0.f, 0.f, 0.f); + Nz::Quaternionf camQuat(camAngles); + + window.EnableEventPolling(true); + + Nz::Clock updateClock; + Nz::Clock secondClock; + unsigned int fps = 0; + bool viewerUboUpdate = true; + + Nz::Mouse::SetRelativeMouseMode(true); + + while (window.IsOpen()) + { + Nz::WindowEvent event; + while (window.PollEvent(&event)) + { + switch (event.type) + { + case Nz::WindowEventType::Quit: + window.Close(); + break; + + case Nz::WindowEventType::MouseMoved: // La souris a bougé + { + // Gestion de la caméra free-fly (Rotation) + float sensitivity = 0.3f; // Sensibilité de la souris + + // On modifie l'angle de la caméra grâce au déplacement relatif sur X de la souris + camAngles.yaw = camAngles.yaw - event.mouseMove.deltaX * sensitivity; + camAngles.yaw.Normalize(); + + // Idem, mais pour éviter les problèmes de calcul de la matrice de vue, on restreint les angles + camAngles.pitch = Nz::Clamp(camAngles.pitch + event.mouseMove.deltaY*sensitivity, -89.f, 89.f); + + camQuat = camAngles; + + viewerUboUpdate = true; + break; + } + + case Nz::WindowEventType::Resized: + { + Nz::Vector2ui windowSize = window.GetSize(); + Nz::AccessByOffset(viewerDataBuffer.data(), viewerUboOffsets.projMatrixOffset) = Nz::Matrix4f::Perspective(Nz::DegreeAnglef(70.f), float(windowSize.x) / windowSize.y, 0.1f, 1000.f); + viewerUboUpdate = true; + break; + } + + default: + break; + } + } + + if (updateClock.GetMilliseconds() > 1000 / 60) + { + float cameraSpeed = 2.f * updateClock.GetSeconds(); + updateClock.Restart(); + + if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Up) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Z)) + viewerPos += camQuat * Nz::Vector3f::Forward() * cameraSpeed; + + // Si la flèche du bas ou la touche S est pressée, on recule + if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Down) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::S)) + viewerPos += camQuat * Nz::Vector3f::Backward() * cameraSpeed; + + // Etc... + if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Left) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Q)) + viewerPos += camQuat * Nz::Vector3f::Left() * cameraSpeed; + + // Etc... + if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Right) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::D)) + viewerPos += camQuat * Nz::Vector3f::Right() * cameraSpeed; + + // Majuscule pour monter, notez l'utilisation d'une direction globale (Non-affectée par la rotation) + if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::LShift) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::RShift)) + viewerPos += Nz::Vector3f::Up() * cameraSpeed; + + // Contrôle (Gauche ou droite) pour descendre dans l'espace global, etc... + if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::LControl) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::RControl)) + viewerPos += Nz::Vector3f::Down() * cameraSpeed; + + viewerUboUpdate = true; + } + + Nz::RenderFrame frame = windowImpl->Acquire(); + if (!frame) + continue; + + if (frame.IsFramebufferInvalidated()) + RebuildCommandBuffer(); + + Nz::AccessByOffset(viewerDataBuffer.data(), viewerUboOffsets.viewMatrixOffset) = Nz::Matrix4f::ViewMatrix(viewerPos, camAngles); + + if (viewerUboUpdate) + { + Nz::UploadPool& uploadPool = frame.GetUploadPool(); + auto& allocation = uploadPool.Allocate(viewerDataBuffer.size()); + + std::memcpy(allocation.mappedPtr, viewerDataBuffer.data(), viewerDataBuffer.size()); + + frame.Execute([&](Nz::CommandBufferBuilder& builder) + { + builder.BeginDebugRegion("UBO Update", Nz::Color::Yellow); + { + builder.PreTransferBarrier(); + builder.CopyBuffer(allocation, viewerDataUBO.get()); + + material->UpdateBuffers(uploadPool, builder); + + builder.PostTransferBarrier(); + } + builder.EndDebugRegion(); + }, Nz::QueueType::Transfer); + + viewerUboUpdate = false; + } + + frame.SubmitCommandBuffer(drawCommandBuffer.get(), Nz::QueueType::Graphics); + + frame.Present(); + + window.Display(); + + // On incrémente le compteur de FPS improvisé + fps++; + + if (secondClock.GetMilliseconds() >= 1000) // Toutes les secondes + { + // Et on insère ces données dans le titre de la fenêtre + window.SetTitle(windowTitle + " - " + Nz::NumberToString(fps) + " FPS"); + + /* + Note: En C++11 il est possible d'insérer de l'Unicode de façon standard, quel que soit l'encodage du fichier, + via quelque chose de similaire à u8"Cha\u00CEne de caract\u00E8res". + Cependant, si le code source est encodé en UTF-8 (Comme c'est le cas dans ce fichier), + cela fonctionnera aussi comme ceci : "Chaîne de caractères". + */ + + // Et on réinitialise le compteur de FPS + fps = 0; + + // Et on relance l'horloge pour refaire ça dans une seconde + secondClock.Restart(); + } + } + + return EXIT_SUCCESS; +} diff --git a/examples/GraphicsTest/xmake.lua b/examples/GraphicsTest/xmake.lua new file mode 100644 index 000000000..f2c4d0741 --- /dev/null +++ b/examples/GraphicsTest/xmake.lua @@ -0,0 +1,5 @@ +target("GraphicsTest") + set_group("Examples") + set_kind("binary") + add_deps("NazaraGraphics") + add_files("main.cpp") \ No newline at end of file diff --git a/examples/HardwareInfo/main.cpp b/examples/HardwareInfo/main.cpp index 0a328cfda..4173bf267 100644 --- a/examples/HardwareInfo/main.cpp +++ b/examples/HardwareInfo/main.cpp @@ -63,7 +63,7 @@ int main() std::cout << oss.str() << std::endl; Nz::File reportFile("HardwareInfo.txt"); - if (reportFile.Open(Nz::OpenMode_Text | Nz::OpenMode_Truncate | Nz::OpenMode_WriteOnly)) + if (reportFile.Open(Nz::OpenMode::Text | Nz::OpenMode::Truncate | Nz::OpenMode::WriteOnly)) { reportFile.Write(oss.str()); // Conversion implicite en std::string reportFile.Close(); diff --git a/examples/PlayMusic/main.cpp b/examples/PlayMusic/main.cpp new file mode 100644 index 000000000..97c1048a7 --- /dev/null +++ b/examples/PlayMusic/main.cpp @@ -0,0 +1,42 @@ +/* +** PlayMusic - Example on playing a sound using streaming (doesn't load all the file in memory, only the played part) with Nz::Music +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main() +{ + std::filesystem::path resourceDir = "resources"; + if (!std::filesystem::is_directory(resourceDir) && std::filesystem::is_directory(".." / resourceDir)) + resourceDir = ".." / resourceDir; + + Nz::Modules audio; + + Nz::SoundStreamParams streamParams; + streamParams.forceMono = false; + + Nz::Music music; + if (!music.OpenFromFile(resourceDir / "file_example_MP3_700KB.mp3", streamParams)) + { + std::cout << "Failed to load sound" << std::endl; + std::getchar(); + return EXIT_FAILURE; + } + + music.Play(); + + std::cout << "Playing sound..." << std::endl; + + while (music.IsPlaying()) + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + return EXIT_SUCCESS; +} diff --git a/examples/PlayMusic/xmake.lua b/examples/PlayMusic/xmake.lua new file mode 100644 index 000000000..32a81eb4c --- /dev/null +++ b/examples/PlayMusic/xmake.lua @@ -0,0 +1,5 @@ +target("PlayMusic") + set_group("Examples") + set_kind("binary") + add_deps("NazaraAudio") + add_files("main.cpp") diff --git a/examples/RenderTest/build.lua b/examples/RenderTest/build.lua deleted file mode 100644 index dc1eedcb4..000000000 --- a/examples/RenderTest/build.lua +++ /dev/null @@ -1,15 +0,0 @@ -EXAMPLE.Name = "RenderTest" - -EXAMPLE.EnableConsole = true - -EXAMPLE.Files = { - "main.cpp" -} - -EXAMPLE.Libraries = { - "NazaraCore", - "NazaraPlatform", - "NazaraRenderer", - "NazaraShader", - "NazaraUtility" -} diff --git a/examples/RenderTest/main.cpp b/examples/RenderTest/main.cpp index 129a95031..c0a82dc26 100644 --- a/examples/RenderTest/main.cpp +++ b/examples/RenderTest/main.cpp @@ -8,8 +8,73 @@ #include #include +const char shaderSource[] = R"( + +option red: bool; + +[layout(std140)] +struct Data +{ + projectionMatrix: mat4, + worldMatrix: mat4, + viewMatrix: mat4 +} + +external +{ + [binding(0)] viewerData: uniform, + [binding(1)] tex: sampler2D +} + +struct VertIn +{ + [location(0)] position: vec3, + [location(1)] normal: vec3, + [location(2)] uv: vec2 +} + +struct VertOut +{ + [builtin(position)] position: vec4, + [location(0)] normal: vec3, + [location(1)] uv: vec2 +} + +struct FragOut +{ + [location(0)] color: vec4 +} + +[entry(frag)] +fn main(fragIn: VertOut) -> FragOut +{ + let lightDir = vec3(0.0, -0.707, 0.707); + let lightFactor = dot(fragIn.normal, lightDir); + + let fragOut: FragOut; + fragOut.color = lightFactor * tex.Sample(fragIn.uv) * select_opt(red, vec4(1.0, 0.0, 0.0, 1.0), vec4(1.0, 1.0, 1.0, 1.0)); + + return fragOut; +} + +[entry(vert)] +fn main(vertIn: VertIn) -> VertOut +{ + let vertOut: VertOut; + vertOut.position = viewerData.projectionMatrix * viewerData.viewMatrix * viewerData.worldMatrix * vec4(vertIn.position, 1.0); + vertOut.normal = vertIn.normal; + vertOut.uv = vertIn.uv; + + return vertOut; +} +)"; + int main() { + std::filesystem::path resourceDir = "resources"; + if (!std::filesystem::is_directory(resourceDir) && std::filesystem::is_directory(".." / resourceDir)) + resourceDir = ".." / resourceDir; + Nz::Renderer::Config rendererConfig; std::cout << "Run using Vulkan? (y/n)" << std::endl; if (std::getchar() == 'y') @@ -23,71 +88,52 @@ int main() Nz::MeshParams meshParams; meshParams.matrix = Nz::Matrix4f::Rotate(Nz::EulerAnglesf(0.f, 90.f, 180.f)) * Nz::Matrix4f::Scale(Nz::Vector3f(0.002f)); - meshParams.vertexDeclaration = Nz::VertexDeclaration::Get(Nz::VertexLayout_XYZ_Normal_UV); + meshParams.vertexDeclaration = Nz::VertexDeclaration::Get(Nz::VertexLayout::XYZ_Normal_UV); + + std::shared_ptr device = Nz::Renderer::Instance()->InstanciateRenderDevice(0); std::string windowTitle = "Render Test"; - if (!window.Create(Nz::VideoMode(800, 600, 32), windowTitle)) + if (!window.Create(device, Nz::VideoMode(800, 600, 32), windowTitle)) { std::cout << "Failed to create Window" << std::endl; return __LINE__; } - std::shared_ptr device = window.GetRenderDevice(); + Nz::ShaderWriter::States states; + states.enabledOptions = 0; + states.optimize = true; - auto fragmentShader = device->InstantiateShaderStage(Nz::ShaderStageType::Fragment, Nz::ShaderLanguage::NazaraBinary, "frag.shader"); - if (!fragmentShader) + auto fragVertShader = device->InstantiateShaderModule(Nz::ShaderStageType::Fragment | Nz::ShaderStageType::Vertex, Nz::ShaderLanguage::NazaraShader, shaderSource, sizeof(shaderSource), states); + if (!fragVertShader) { - std::cout << "Failed to instantiate fragment shader" << std::endl; + std::cout << "Failed to instantiate shader" << std::endl; return __LINE__; } - auto vertexShader = device->InstantiateShaderStage(Nz::ShaderStageType::Vertex, Nz::ShaderLanguage::NazaraBinary, "vert.shader"); - if (!vertexShader) - { - std::cout << "Failed to instantiate fragment shader" << std::endl; - return __LINE__; - } - - Nz::MeshRef drfreak = Nz::Mesh::LoadFromFile("resources/Spaceship/spaceship.obj", meshParams); + std::shared_ptr drfreak = Nz::Mesh::LoadFromFile(resourceDir / "Spaceship/spaceship.obj", meshParams); if (!drfreak) { NazaraError("Failed to load model"); return __LINE__; } - Nz::StaticMesh* drfreakMesh = static_cast(drfreak->GetSubMesh(0)); + std::shared_ptr spaceshipMesh = std::static_pointer_cast(drfreak->GetSubMesh(0)); - const Nz::VertexBuffer* drfreakVB = drfreakMesh->GetVertexBuffer(); - const Nz::IndexBuffer* drfreakIB = drfreakMesh->GetIndexBuffer(); + const std::shared_ptr& meshVB = spaceshipMesh->GetVertexBuffer(); + const std::shared_ptr& meshIB = spaceshipMesh->GetIndexBuffer(); // Index buffer - std::cout << "Index count: " << drfreakIB->GetIndexCount() << std::endl; + std::cout << "Index count: " << meshIB->GetIndexCount() << std::endl; // Vertex buffer - std::cout << "Vertex count: " << drfreakVB->GetVertexCount() << std::endl; + std::cout << "Vertex count: " << meshVB->GetVertexCount() << std::endl; // Texture - Nz::ImageRef drfreakImage = Nz::Image::LoadFromFile("resources/Spaceship/Texture/diffuse.png"); - if (!drfreakImage || !drfreakImage->Convert(Nz::PixelFormat_RGBA8)) - { - NazaraError("Failed to load image"); - return __LINE__; - } - - Nz::TextureInfo texParams; - texParams.pixelFormat = drfreakImage->GetFormat(); - texParams.type = drfreakImage->GetType(); - texParams.width = drfreakImage->GetWidth(); - texParams.height = drfreakImage->GetHeight(); - texParams.depth = drfreakImage->GetDepth(); - - std::shared_ptr texture = device->InstantiateTexture(texParams); - if (!texture->Update(drfreakImage->GetConstPixels())) - { - NazaraError("Failed to update texture"); - return __LINE__; - } + Nz::TextureParams texParams; + texParams.renderDevice = device; + texParams.loadFormat = Nz::PixelFormat::RGBA8_SRGB; + std::shared_ptr texture = Nz::Texture::LoadFromFile(resourceDir / "Spaceship/Texture/diffuse.png", texParams); std::shared_ptr textureSampler = device->InstantiateTextureSampler({}); struct @@ -99,7 +145,7 @@ int main() ubo; Nz::Vector2ui windowSize = window.GetSize(); - ubo.projectionMatrix = Nz::Matrix4f::Perspective(70.f, float(windowSize.x) / windowSize.y, 0.1f, 1000.f); + ubo.projectionMatrix = Nz::Matrix4f::Perspective(Nz::DegreeAnglef(70.f), float(windowSize.x) / windowSize.y, 0.1f, 1000.f); ubo.viewMatrix = Nz::Matrix4f::Translate(Nz::Vector3f::Backward() * 1); ubo.modelMatrix = Nz::Matrix4f::Translate(Nz::Vector3f::Forward() * 2 + Nz::Vector3f::Right()); @@ -120,8 +166,8 @@ int main() Nz::ShaderBindingPtr shaderBinding = renderPipelineLayout->AllocateShaderBinding(); - std::shared_ptr uniformBuffer = device->InstantiateBuffer(Nz::BufferType_Uniform); - if (!uniformBuffer->Initialize(uniformSize, Nz::BufferUsage_DeviceLocal | Nz::BufferUsage_Dynamic)) + std::shared_ptr uniformBuffer = device->InstantiateBuffer(Nz::BufferType::Uniform); + if (!uniformBuffer->Initialize(uniformSize, Nz::BufferUsage::DeviceLocal | Nz::BufferUsage::Dynamic)) { NazaraError("Failed to create uniform buffer"); return __LINE__; @@ -144,14 +190,14 @@ int main() Nz::RenderPipelineInfo pipelineInfo; pipelineInfo.pipelineLayout = renderPipelineLayout; + pipelineInfo.faceCulling = true; pipelineInfo.depthBuffer = true; - pipelineInfo.shaderStages.emplace_back(fragmentShader); - pipelineInfo.shaderStages.emplace_back(vertexShader); + pipelineInfo.shaderModules.emplace_back(fragVertShader); auto& vertexBuffer = pipelineInfo.vertexBuffers.emplace_back(); vertexBuffer.binding = 0; - vertexBuffer.declaration = drfreakVB->GetVertexDeclaration(); + vertexBuffer.declaration = meshVB->GetVertexDeclaration(); std::shared_ptr pipeline = device->InstantiateRenderPipeline(pipelineInfo); @@ -160,8 +206,8 @@ int main() Nz::RenderWindowImpl* windowImpl = window.GetImpl(); std::shared_ptr commandPool = windowImpl->CreateCommandPool(Nz::QueueType::Graphics); - Nz::RenderBuffer* renderBufferIB = static_cast(drfreakIB->GetBuffer()->GetImpl()); - Nz::RenderBuffer* renderBufferVB = static_cast(drfreakVB->GetBuffer()->GetImpl()); + Nz::RenderBuffer* renderBufferIB = static_cast(meshIB->GetBuffer()->GetImpl()); + Nz::RenderBuffer* renderBufferVB = static_cast(meshVB->GetBuffer()->GetImpl()); if (!renderBufferIB->Synchronize(renderDevice)) { @@ -204,7 +250,7 @@ int main() builder.SetScissor(Nz::Recti{ 0, 0, int(windowSize.x), int(windowSize.y) }); builder.SetViewport(Nz::Recti{ 0, 0, int(windowSize.x), int(windowSize.y) }); - builder.DrawIndexed(drfreakIB->GetIndexCount()); + builder.DrawIndexed(meshIB->GetIndexCount()); } builder.EndRenderPass(); } @@ -235,17 +281,18 @@ int main() { switch (event.type) { - case Nz::WindowEventType_Quit: + case Nz::WindowEventType::Quit: window.Close(); break; - case Nz::WindowEventType_MouseMoved: // La souris a bougé + case Nz::WindowEventType::MouseMoved: // La souris a bougé { // Gestion de la caméra free-fly (Rotation) float sensitivity = 0.3f; // Sensibilité de la souris // On modifie l'angle de la caméra grâce au déplacement relatif sur X de la souris - camAngles.yaw = Nz::NormalizeAngle(camAngles.yaw - event.mouseMove.deltaX*sensitivity); + camAngles.yaw = camAngles.yaw - event.mouseMove.deltaX * sensitivity; + camAngles.yaw.Normalize(); // Idem, mais pour éviter les problèmes de calcul de la matrice de vue, on restreint les angles camAngles.pitch = Nz::Clamp(camAngles.pitch + event.mouseMove.deltaY*sensitivity, -89.f, 89.f); @@ -256,10 +303,10 @@ int main() break; } - case Nz::WindowEventType_Resized: + case Nz::WindowEventType::Resized: { Nz::Vector2ui windowSize = window.GetSize(); - ubo.projectionMatrix = Nz::Matrix4f::Perspective(70.f, float(windowSize.x) / windowSize.y, 0.1f, 1000.f); + ubo.projectionMatrix = Nz::Matrix4f::Perspective(Nz::DegreeAnglef(70.f), float(windowSize.x) / windowSize.y, 0.1f, 1000.f); uboUpdate = true; break; } diff --git a/examples/RenderTest/xmake.lua b/examples/RenderTest/xmake.lua new file mode 100644 index 000000000..0e11edc47 --- /dev/null +++ b/examples/RenderTest/xmake.lua @@ -0,0 +1,5 @@ +target("RenderTest") + set_group("Examples") + set_kind("binary") + add_deps("NazaraRenderer") + add_files("main.cpp") \ No newline at end of file diff --git a/examples/Std140Debug/main.cpp b/examples/Std140Debug/main.cpp new file mode 100644 index 000000000..4cbe0c1ed --- /dev/null +++ b/examples/Std140Debug/main.cpp @@ -0,0 +1,174 @@ +#include +#include +#include +#include +#include +#include +#include + +const char fragmentSource[] = R"( +#version 310 es + +#if GL_FRAGMENT_PRECISION_HIGH +precision highp float; +#else +precision mediump float; +#endif + +layout(binding = 3, std140) uniform LightParameters +{ + mat4 projectionMatrix; + mat4 invProjectionMatrix; + mat4 viewMatrix; + mat4 invViewMatrix; + mat4 viewProjMatrix; + mat4 invViewProjMatrix; + vec2 renderTargetSize; + vec2 invRenderTargetSize; + vec3 eyePosition; +}; + +void main() +{ +} +)"; + +const char vertexSource[] = R"( +#version 310 es + +void main() +{ + gl_Position = vec4(0.0, 0.0, 0.0, 1.0); +} +)"; + +template +std::vector SortIndexes(const std::vector& vec, Compare&& compare) +{ + std::vector p(vec.size()); + std::iota(p.begin(), p.end(), 0); + std::sort(p.begin(), p.end(), [&](std::size_t i, std::size_t j) { return compare(vec[i], vec[j]); }); + + return p; +} + +int main() +{ + Nz::Renderer::Config rendererConfig; + rendererConfig.preferredAPI = Nz::RenderAPI::OpenGL; + + Nz::Modules nazara(rendererConfig); + if (Nz::Renderer::Instance()->QueryAPI() != Nz::RenderAPI::OpenGL) + { + std::cout << "This program only works with OpenGL" << std::endl; + return EXIT_FAILURE; + } + + std::shared_ptr device = std::static_pointer_cast(Nz::Renderer::Instance()->InstanciateRenderDevice(0)); + + std::string err; + + // Fragment shader + Nz::GL::Shader fragmentShader; + if (!fragmentShader.Create(*device, GL_FRAGMENT_SHADER)) + { + std::cerr << "Failed to create fragment shader" << std::endl; + return EXIT_FAILURE; + } + + fragmentShader.SetSource(fragmentSource, sizeof(fragmentSource)); + fragmentShader.Compile(); + + if (!fragmentShader.GetCompilationStatus(&err)) + { + std::cerr << "Failed to compile fragment shader: " << err << std::endl; + return EXIT_FAILURE; + } + + // Vertex shader + Nz::GL::Shader vertexShader; + if (!vertexShader.Create(*device, GL_VERTEX_SHADER)) + { + std::cerr << "Failed to create vertex shader" << std::endl; + return EXIT_FAILURE; + } + + vertexShader.SetSource(vertexSource, sizeof(vertexSource)); + vertexShader.Compile(); + + if (!vertexShader.GetCompilationStatus(&err)) + { + std::cerr << "Failed to compile vertex shader: " << err << std::endl; + return EXIT_FAILURE; + } + + // Program + Nz::GL::Program program; + if (!program.Create(*device)) + { + std::cerr << "Failed to create program" << std::endl; + return EXIT_FAILURE; + } + + program.AttachShader(fragmentShader.GetObjectId()); + program.AttachShader(vertexShader.GetObjectId()); + program.Link(); + + if (!program.GetLinkStatus(&err)) + { + std::cerr << "Failed to link program: " << err << std::endl; + return EXIT_FAILURE; + } + + // Get infos + GLuint blockIndex = program.GetUniformBlockIndex("LightParameters"); + if (blockIndex == GL_INVALID_INDEX) + { + std::cerr << "Failed to find uniform block in program" << std::endl; + return EXIT_FAILURE; + } + + std::vector uniformIndices = program.GetActiveUniformBlockUniformIndices(blockIndex); + + std::vector offsets = program.GetActiveUniforms(uniformIndices.size(), reinterpret_cast(uniformIndices.data()), GL_UNIFORM_OFFSET); + + auto p = SortIndexes(offsets, std::less()); + + std::vector computedOffsets; + + Nz::FieldOffsets fieldOffsets(Nz::StructLayout::Std140); + computedOffsets.push_back(fieldOffsets.AddMatrix(Nz::StructFieldType::Float1, 4, 4, true)); + computedOffsets.push_back(fieldOffsets.AddMatrix(Nz::StructFieldType::Float1, 4, 4, true)); + computedOffsets.push_back(fieldOffsets.AddMatrix(Nz::StructFieldType::Float1, 4, 4, true)); + computedOffsets.push_back(fieldOffsets.AddMatrix(Nz::StructFieldType::Float1, 4, 4, true)); + computedOffsets.push_back(fieldOffsets.AddMatrix(Nz::StructFieldType::Float1, 4, 4, true)); + computedOffsets.push_back(fieldOffsets.AddMatrix(Nz::StructFieldType::Float1, 4, 4, true)); + computedOffsets.push_back(fieldOffsets.AddField(Nz::StructFieldType::Float2)); + computedOffsets.push_back(fieldOffsets.AddField(Nz::StructFieldType::Float2)); + computedOffsets.push_back(fieldOffsets.AddField(Nz::StructFieldType::Float3)); + + + GLint dataSize; + program.GetActiveUniformBlock(blockIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &dataSize); + + if (fieldOffsets.GetAlignedSize() != dataSize) + std::cout << "size mismatch (computed " << fieldOffsets.GetAlignedSize() << ", reference has " << dataSize << ")" << std::endl;; + + if (computedOffsets.size() != uniformIndices.size()) + { + std::cout << "member count mismatch" << std::endl; + return EXIT_FAILURE; + } + + for (std::size_t i = 0; i < uniformIndices.size(); ++i) + { + GLint realOffset = offsets[p[i]]; + std::cout << program.GetActiveUniformName(uniformIndices[p[i]]) << ": " << realOffset; + if (realOffset != computedOffsets[i]) + std::cout << " ERR"; + + std::cout << std::endl; + } + + return EXIT_SUCCESS; +} diff --git a/examples/Std140Debug/xmake.lua b/examples/Std140Debug/xmake.lua new file mode 100644 index 000000000..f72858562 --- /dev/null +++ b/examples/Std140Debug/xmake.lua @@ -0,0 +1,5 @@ +target("Std140Debug") + set_group("Examples") + set_kind("binary") + add_deps("NazaraOpenGLRenderer") + add_files("main.cpp") diff --git a/examples/bin/Shaders/PhongLighting/core.frag b/examples/bin/Shaders/PhongLighting/core.frag deleted file mode 100644 index f95d0eb04..000000000 --- a/examples/bin/Shaders/PhongLighting/core.frag +++ /dev/null @@ -1,488 +0,0 @@ -#if EARLY_FRAGMENT_TESTS && !ALPHA_TEST -layout(early_fragment_tests) in; -#endif - -// HACK UNTIL PROPER FIX -#if GLSL_VERSION < 400 - #undef SHADOW_MAPPING - #define SHADOW_MAPPING 0 -#endif -// HACK - -#define LIGHT_DIRECTIONAL 0 -#define LIGHT_POINT 1 -#define LIGHT_SPOT 2 - -/********************Entrant********************/ -in vec4 vColor; -in vec4 vLightSpacePos[3]; -in mat3 vLightToWorld; -in vec3 vNormal; -in vec2 vTexCoord; -in vec3 vViewDir; -in vec3 vWorldPos; - -/********************Sortant********************/ -out vec4 RenderTarget0; -out vec4 RenderTarget1; -out vec4 RenderTarget2; - -/********************Uniformes********************/ -struct Light -{ - int type; - vec4 color; - vec2 factors; - - vec4 parameters1; - vec4 parameters2; - vec2 parameters3; - bool shadowMapping; -}; - -// Lumières -uniform Light Lights[3]; -uniform samplerCube PointLightShadowMap[3]; -uniform sampler2D DirectionalSpotLightShadowMap[3]; - -// Matériau -uniform sampler2D MaterialAlphaMap; -uniform float MaterialAlphaThreshold; -uniform vec4 MaterialAmbient; -uniform vec4 MaterialDiffuse; -uniform sampler2D MaterialDiffuseMap; -uniform sampler2D MaterialEmissiveMap; -uniform sampler2D MaterialHeightMap; -uniform sampler2D MaterialNormalMap; -uniform float MaterialShininess; -uniform vec4 MaterialSpecular; -uniform sampler2D MaterialSpecularMap; - -// Autres -uniform float ParallaxBias = -0.03; -uniform float ParallaxScale = 0.02; -uniform vec2 InvTargetSize; -uniform vec3 EyePosition; -uniform samplerCube ReflectionMap; -uniform vec4 SceneAmbient; - -uniform mat4 WorldMatrix; - -uniform sampler2D TextureOverlay; - -/********************Fonctions********************/ - -#define kPI 3.1415926536 - -vec4 EncodeNormal(in vec3 normal) -{ - //return vec4(normal*0.5 + 0.5, 0.0); - return vec4(vec2(atan(normal.y, normal.x)/kPI, normal.z), 0.0, 0.0); -} - -float VectorToDepthValue(vec3 vec, float zNear, float zFar) -{ - vec3 absVec = abs(vec); - float localZ = max(absVec.x, max(absVec.y, absVec.z)); - - float normZ = ((zFar + zNear) * localZ - (2.0*zFar*zNear)) / ((zFar - zNear)*localZ); - return (normZ + 1.0) * 0.5; -} - -#if SHADOW_MAPPING -float CalculateDirectionalShadowFactor(int lightIndex) -{ - vec4 lightSpacePos = vLightSpacePos[lightIndex]; - return (texture(DirectionalSpotLightShadowMap[lightIndex], lightSpacePos.xy).x >= (lightSpacePos.z - 0.0005)) ? 1.0 : 0.0; -} - -float CalculatePointShadowFactor(int lightIndex, vec3 lightToWorld, float zNear, float zFar) -{ - return (texture(PointLightShadowMap[lightIndex], vec3(lightToWorld.x, -lightToWorld.y, -lightToWorld.z)).x >= VectorToDepthValue(lightToWorld, zNear, zFar)) ? 1.0 : 0.0; -} - -float CalculateSpotShadowFactor(int lightIndex, float lambert) -{ - vec4 lightSpacePos = vLightSpacePos[lightIndex]; - -#if 0 - float visibility = 1.0; - float bias = 0.005 * tan(acos(NoL)); - bias = clamp(bias, MinAllowedBias, MaxAllowedBias); - - float x,y; - for (y = -1.0; y <= 1.0; y+= 1.0) - for (x = -1.0; x <= 1.0; x+= 1.0) - visibility += (textureProj(DirectionalSpotLightShadowMap[lightIndex], lightSpacePos.xyw + vec3(x/1024.0 * lightSpacePos.w, y/1024.0 * lightSpacePos.w, 0.0)).x >= (lightSpacePos.z - 0.0005)/lightSpacePos.w) ? 1.0 : 0.0; - - visibility /= 9.0; - - return visibility; -#else - float bias = 0.005 * tan(acos(lambert)); - - return (textureProj(DirectionalSpotLightShadowMap[lightIndex], lightSpacePos.xyw).x >= (lightSpacePos.z - bias)/lightSpacePos.w) ? 1.0 : 0.0; -#endif -} -#endif - -void main() -{ - vec4 diffuseColor = MaterialDiffuse * vColor; - -#if AUTO_TEXCOORDS - vec2 texCoord = gl_FragCoord.xy * InvTargetSize; -#else - vec2 texCoord = vTexCoord; -#endif - -#if PARALLAX_MAPPING - float height = texture(MaterialHeightMap, texCoord).r; - float v = height*ParallaxScale + ParallaxBias; - - vec3 viewDir = normalize(vViewDir); - texCoord += v * viewDir.xy; -#endif - -#if DIFFUSE_MAPPING - diffuseColor *= texture(MaterialDiffuseMap, texCoord); -#endif - -#if FLAG_TEXTUREOVERLAY - diffuseColor *= texture(TextureOverlay, texCoord); -#endif - -#if FLAG_DEFERRED - #if ALPHA_TEST - // Inutile de faire de l'alpha-mapping sans alpha-test en Deferred (l'alpha n'est pas sauvegardé dans le G-Buffer) - #if ALPHA_MAPPING - diffuseColor.a *= texture(MaterialAlphaMap, texCoord).r; - #endif - - if (diffuseColor.a < MaterialAlphaThreshold) - discard; - #endif // ALPHA_TEST - - #if NORMAL_MAPPING - vec3 normal = normalize(vLightToWorld * (2.0 * vec3(texture(MaterialNormalMap, texCoord)) - 1.0)); - #else - vec3 normal = normalize(vNormal); - #endif // NORMAL_MAPPING - - vec3 specularColor = MaterialSpecular.rgb; - #if SPECULAR_MAPPING - specularColor *= texture(MaterialSpecularMap, texCoord).rgb; - #endif - - /* - Texture0: Diffuse Color + Specular - Texture1: Normal + Specular - Texture2: Encoded depth + Shininess - */ - RenderTarget0 = vec4(diffuseColor.rgb, dot(specularColor, vec3(0.3, 0.59, 0.11))); - RenderTarget1 = vec4(EncodeNormal(normal)); - RenderTarget2 = vec4(0.0, 0.0, 0.0, (MaterialShininess == 0.0) ? 0.0 : max(log2(MaterialShininess), 0.1)/10.5); // http://www.guerrilla-games.com/publications/dr_kz2_rsx_dev07.pdf -#else // FLAG_DEFERRED - #if ALPHA_MAPPING - diffuseColor.a *= texture(MaterialAlphaMap, texCoord).r; - #endif - - #if ALPHA_TEST - if (diffuseColor.a < MaterialAlphaThreshold) - discard; - #endif - - vec3 lightAmbient = vec3(0.0); - vec3 lightDiffuse = vec3(0.0); - vec3 lightSpecular = vec3(0.0); - - #if NORMAL_MAPPING - vec3 normal = normalize(vLightToWorld * (2.0 * vec3(texture(MaterialNormalMap, texCoord)) - 1.0)); - #else - vec3 normal = normalize(vNormal); - #endif - - if (MaterialShininess > 0.0) - { - vec3 eyeVec = normalize(EyePosition - vWorldPos); - - for (int i = 0; i < 3; ++i) - { - vec4 lightColor = Lights[i].color; - float lightAmbientFactor = Lights[i].factors.x; - float lightDiffuseFactor = Lights[i].factors.y; - - switch (Lights[i].type) - { - case LIGHT_DIRECTIONAL: - { - vec3 lightDir = -Lights[i].parameters1.xyz; - - // Ambient - lightAmbient += lightColor.rgb * lightAmbientFactor * (MaterialAmbient.rgb + SceneAmbient.rgb); - - float att = 1.0; - - float lambert = max(dot(normal, lightDir), 0.0); - - #if SHADOW_MAPPING - if (Lights[i].shadowMapping) - { - float shadowFactor = CalculateDirectionalShadowFactor(i); - if (shadowFactor == 0.0) - break; - - att *= shadowFactor; - } - #endif - - // Diffuse - lightDiffuse += att * lambert * lightColor.rgb * lightDiffuseFactor; - - // Specular - vec3 reflection = reflect(-lightDir, normal); - float specularFactor = max(dot(reflection, eyeVec), 0.0); - specularFactor = pow(specularFactor, MaterialShininess); - - lightSpecular += att * specularFactor * lightColor.rgb; - break; - } - - case LIGHT_POINT: - { - vec3 lightPos = Lights[i].parameters1.xyz; - float lightAttenuation = Lights[i].parameters1.w; - float lightInvRadius = Lights[i].parameters2.w; - - vec3 worldToLight = lightPos - vWorldPos; - float lightDirLength = length(worldToLight); - vec3 lightDir = worldToLight / lightDirLength; // Normalisation - - float att = max(lightAttenuation - lightInvRadius * lightDirLength, 0.0); - - // Ambient - lightAmbient += att * lightColor.rgb * lightAmbientFactor * (MaterialAmbient.rgb + SceneAmbient.rgb); - - #if SHADOW_MAPPING - if (Lights[i].shadowMapping) - { - float shadowFactor = CalculatePointShadowFactor(i, vWorldPos - lightPos, 0.1, 50.0); - if (shadowFactor == 0.0) - break; - - att *= shadowFactor; - } - #endif - - // Diffuse - float lambert = max(dot(normal, lightDir), 0.0); - - lightDiffuse += att * lambert * lightColor.rgb * lightDiffuseFactor; - - // Specular - vec3 reflection = reflect(-lightDir, normal); - float specularFactor = max(dot(reflection, eyeVec), 0.0); - specularFactor = pow(specularFactor, MaterialShininess); - - lightSpecular += att * specularFactor * lightColor.rgb; - break; - } - - case LIGHT_SPOT: - { - vec3 lightPos = Lights[i].parameters1.xyz; - vec3 lightDir = Lights[i].parameters2.xyz; - float lightAttenuation = Lights[i].parameters1.w; - float lightInvRadius = Lights[i].parameters2.w; - float lightInnerAngle = Lights[i].parameters3.x; - float lightOuterAngle = Lights[i].parameters3.y; - - vec3 worldToLight = lightPos - vWorldPos; - float lightDistance = length(worldToLight); - worldToLight /= lightDistance; // Normalisation - - float att = max(lightAttenuation - lightInvRadius * lightDistance, 0.0); - - // Ambient - lightAmbient += att * lightColor.rgb * lightAmbientFactor * (MaterialAmbient.rgb + SceneAmbient.rgb); - - float lambert = max(dot(normal, worldToLight), 0.0); - - #if SHADOW_MAPPING - if (Lights[i].shadowMapping) - { - float shadowFactor = CalculateSpotShadowFactor(i, lambert); - if (shadowFactor == 0.0) - break; - - att *= shadowFactor; - } - #endif - - // Modification de l'atténuation pour gérer le spot - float curAngle = dot(lightDir, -worldToLight); - float innerMinusOuterAngle = lightInnerAngle - lightOuterAngle; - att *= max((curAngle - lightOuterAngle) / innerMinusOuterAngle, 0.0); - - // Diffuse - lightDiffuse += att * lambert * lightColor.rgb * lightDiffuseFactor; - - // Specular - vec3 reflection = reflect(-worldToLight, normal); - float specularFactor = max(dot(reflection, eyeVec), 0.0); - specularFactor = pow(specularFactor, MaterialShininess); - - lightSpecular += att * specularFactor * lightColor.rgb; - break; - } - - default: - break; - } - } - } - else - { - for (int i = 0; i < 3; ++i) - { - vec4 lightColor = Lights[i].color; - float lightAmbientFactor = Lights[i].factors.x; - float lightDiffuseFactor = Lights[i].factors.y; - - switch (Lights[i].type) - { - case LIGHT_DIRECTIONAL: - { - vec3 lightDir = -Lights[i].parameters1.xyz; - - // Ambient - lightAmbient += lightColor.rgb * lightAmbientFactor * (MaterialAmbient.rgb + SceneAmbient.rgb); - - float att = 1.0; - - #if SHADOW_MAPPING - if (Lights[i].shadowMapping) - { - float shadowFactor = CalculateDirectionalShadowFactor(i); - if (shadowFactor == 0.0) - break; - - att *= shadowFactor; - } - #endif - - // Diffuse - float lambert = max(dot(normal, lightDir), 0.0); - - lightDiffuse += att * lambert * lightColor.rgb * lightDiffuseFactor; - break; - } - - case LIGHT_POINT: - { - vec3 lightPos = Lights[i].parameters1.xyz; - float lightAttenuation = Lights[i].parameters1.w; - float lightInvRadius = Lights[i].parameters2.w; - - vec3 worldToLight = lightPos - vWorldPos; - float lightDirLength = length(worldToLight); - vec3 lightDir = worldToLight / lightDirLength; // Normalisation - - float att = max(lightAttenuation - lightInvRadius * lightDirLength, 0.0); - - // Ambient - lightAmbient += att * lightColor.rgb * lightAmbientFactor * (MaterialAmbient.rgb + SceneAmbient.rgb); - - #if SHADOW_MAPPING - if (Lights[i].shadowMapping) - { - float shadowFactor = CalculatePointShadowFactor(i, vWorldPos - lightPos, 0.1, 50.0); - if (shadowFactor == 0.0) - break; - - att *= shadowFactor; - } - #endif - - // Diffuse - float lambert = max(dot(normal, lightDir), 0.0); - - lightDiffuse += att * lambert * lightColor.rgb * lightDiffuseFactor; - break; - } - - case LIGHT_SPOT: - { - vec3 lightPos = Lights[i].parameters1.xyz; - vec3 lightDir = Lights[i].parameters2.xyz; - float lightAttenuation = Lights[i].parameters1.w; - float lightInvRadius = Lights[i].parameters2.w; - float lightInnerAngle = Lights[i].parameters3.x; - float lightOuterAngle = Lights[i].parameters3.y; - - vec3 worldToLight = lightPos - vWorldPos; - float lightDistance = length(worldToLight); - worldToLight /= lightDistance; // Normalisation - - float att = max(lightAttenuation - lightInvRadius * lightDistance, 0.0); - - // Ambient - lightAmbient += att * lightColor.rgb * lightAmbientFactor * (MaterialAmbient.rgb + SceneAmbient.rgb); - - float lambert = max(dot(normal, worldToLight), 0.0); - - #if SHADOW_MAPPING - if (Lights[i].shadowMapping) - { - float shadowFactor = CalculateSpotShadowFactor(i, lambert); - if (shadowFactor == 0.0) - break; - - att *= shadowFactor; - } - #endif - - // Modification de l'atténuation pour gérer le spot - float curAngle = dot(lightDir, -worldToLight); - float innerMinusOuterAngle = lightInnerAngle - lightOuterAngle; - att *= max((curAngle - lightOuterAngle) / innerMinusOuterAngle, 0.0); - - // Diffuse - lightDiffuse += att * lambert * lightColor.rgb * lightDiffuseFactor; - } - - default: - break; - } - } - } - - lightSpecular *= MaterialSpecular.rgb; - #if SPECULAR_MAPPING - lightSpecular *= texture(MaterialSpecularMap, texCoord).rgb; // Utiliser l'alpha de MaterialSpecular n'aurait aucun sens - #endif - - vec3 lightColor = (lightAmbient + lightDiffuse + lightSpecular); - - #if REFLECTION_MAPPING - vec3 eyeVec = normalize(vWorldPos - EyePosition); - - vec3 reflected = normalize(reflect(eyeVec, normal)); - //reflected = vec3(inverse(WorldMatrix) * vec4(reflected, 0.0)); - - lightColor *= texture(ReflectionMap, reflected).rgb; - #endif - - vec4 fragmentColor = vec4(lightColor, 1.0) * diffuseColor; - - #if EMISSIVE_MAPPING - float lightIntensity = dot(lightColor, vec3(0.3, 0.59, 0.11)); - - vec3 emissionColor = MaterialDiffuse.rgb * texture(MaterialEmissiveMap, texCoord).rgb; - RenderTarget0 = vec4(mix(fragmentColor.rgb, emissionColor, clamp(1.0 - 3.0*lightIntensity, 0.0, 1.0)), fragmentColor.a); - #else - RenderTarget0 = fragmentColor; - #endif // EMISSIVE_MAPPING -#endif // FLAG_DEFERRED -} - diff --git a/examples/bin/Shaders/PhongLighting/core.vert b/examples/bin/Shaders/PhongLighting/core.vert deleted file mode 100644 index 8943c5935..000000000 --- a/examples/bin/Shaders/PhongLighting/core.vert +++ /dev/null @@ -1,148 +0,0 @@ -/********************Entrant********************/ -#if FLAG_BILLBOARD -in vec3 InstanceData0; // center -in vec4 InstanceData1; // size | sin cos -in vec4 InstanceData2; // color -#else -in mat4 InstanceData0; -#endif - -in vec4 VertexColor; -in vec3 VertexPosition; -in vec3 VertexNormal; -in vec3 VertexTangent; -in vec2 VertexTexCoord; -in vec4 VertexUserdata0; - -/********************Sortant********************/ -out vec4 vColor; -out vec4 vLightSpacePos[3]; -out mat3 vLightToWorld; -out vec3 vNormal; -out vec2 vTexCoord; -out vec3 vViewDir; -out vec3 vWorldPos; - -/********************Uniformes********************/ -uniform vec3 EyePosition; -uniform mat4 InvViewMatrix; -uniform mat4 LightViewProjMatrix[3]; -uniform float VertexDepth; -uniform mat4 ViewMatrix; -uniform mat4 ViewProjMatrix; -uniform mat4 WorldMatrix; -uniform mat4 WorldViewProjMatrix; - -/********************Fonctions********************/ -void main() -{ -#if FLAG_VERTEXCOLOR - vec4 color = VertexColor; -#else - vec4 color = vec4(1.0); -#endif - - vec2 texCoords; - -#if FLAG_BILLBOARD - #if FLAG_INSTANCING - vec3 billboardCenter = InstanceData0; - vec2 billboardSize = InstanceData1.xy; - vec2 billboardSinCos = InstanceData1.zw; - vec4 billboardColor = InstanceData2; - - vec2 rotatedPosition; - rotatedPosition.x = VertexPosition.x*billboardSinCos.y - VertexPosition.y*billboardSinCos.x; - rotatedPosition.y = VertexPosition.y*billboardSinCos.y + VertexPosition.x*billboardSinCos.x; - rotatedPosition *= billboardSize; - - vec3 cameraRight = vec3(ViewMatrix[0][0], ViewMatrix[1][0], ViewMatrix[2][0]); - vec3 cameraUp = vec3(ViewMatrix[0][1], ViewMatrix[1][1], ViewMatrix[2][1]); - vec3 vertexPos = billboardCenter + cameraRight*rotatedPosition.x + cameraUp*rotatedPosition.y; - - gl_Position = ViewProjMatrix * vec4(vertexPos, 1.0); - color = billboardColor; - texCoords = VertexPosition.xy + 0.5; - #else - vec2 billboardCorner = VertexTexCoord - 0.5; - vec2 billboardSize = VertexUserdata0.xy; - vec2 billboardSinCos = VertexUserdata0.zw; - - vec2 rotatedPosition; - rotatedPosition.x = billboardCorner.x*billboardSinCos.y - billboardCorner.y*billboardSinCos.x; - rotatedPosition.y = billboardCorner.y*billboardSinCos.y + billboardCorner.x*billboardSinCos.x; - rotatedPosition *= billboardSize; - - vec3 cameraRight = vec3(ViewMatrix[0][0], ViewMatrix[1][0], ViewMatrix[2][0]); - vec3 cameraUp = vec3(ViewMatrix[0][1], ViewMatrix[1][1], ViewMatrix[2][1]); - vec3 vertexPos = VertexPosition + cameraRight*rotatedPosition.x + cameraUp*rotatedPosition.y; - - gl_Position = ViewProjMatrix * vec4(vertexPos, 1.0); - texCoords = VertexTexCoord; - #endif - texCoords.y = 1.0 - texCoords.y; -#else - #if FLAG_INSTANCING - #if TRANSFORM - gl_Position = ViewProjMatrix * InstanceData0 * vec4(VertexPosition, 1.0); - #else - #if UNIFORM_VERTEX_DEPTH - gl_Position = InstanceData0 * vec4(VertexPosition.xy, VertexDepth, 1.0); - #else - gl_Position = InstanceData0 * vec4(VertexPosition, 1.0); - #endif - #endif - #else - #if TRANSFORM - gl_Position = WorldViewProjMatrix * vec4(VertexPosition, 1.0); - #else - #if UNIFORM_VERTEX_DEPTH - gl_Position = vec4(VertexPosition.xy, VertexDepth, 1.0); - #else - gl_Position = vec4(VertexPosition, 1.0); - #endif - #endif - #endif - - texCoords = VertexTexCoord; -#endif - - vColor = color; - -#if FLAG_INSTANCING - mat3 rotationMatrix = mat3(InstanceData0); -#else - mat3 rotationMatrix = mat3(WorldMatrix); -#endif - -#if COMPUTE_TBNMATRIX - vec3 binormal = cross(VertexNormal, VertexTangent); - vLightToWorld[0] = normalize(rotationMatrix * VertexTangent); - vLightToWorld[1] = normalize(rotationMatrix * binormal); - vLightToWorld[2] = normalize(rotationMatrix * VertexNormal); -#else - vNormal = normalize(rotationMatrix * VertexNormal); -#endif - -#if SHADOW_MAPPING - for (int i = 0; i < 3; ++i) - vLightSpacePos[i] = LightViewProjMatrix[i] * WorldMatrix * vec4(VertexPosition, 1.0); -#endif - -#if TEXTURE_MAPPING - vTexCoord = VertexTexCoord; -#endif - -#if PARALLAX_MAPPING - vViewDir = EyePosition - VertexPosition; - vViewDir *= vLightToWorld; -#endif - -#if !FLAG_DEFERRED - #if FLAG_INSTANCING - vWorldPos = vec3(InstanceData0 * vec4(VertexPosition, 1.0)); - #else - vWorldPos = vec3(WorldMatrix * vec4(VertexPosition, 1.0)); - #endif -#endif -} diff --git a/examples/bin/frag.shader b/examples/bin/frag.shader deleted file mode 100644 index 24bd3f959..000000000 Binary files a/examples/bin/frag.shader and /dev/null differ diff --git a/examples/bin/test.spirv b/examples/bin/test.spirv deleted file mode 100644 index b88584775..000000000 Binary files a/examples/bin/test.spirv and /dev/null differ diff --git a/examples/bin/vert.shader b/examples/bin/vert.shader deleted file mode 100644 index de4e4437b..000000000 Binary files a/examples/bin/vert.shader and /dev/null differ diff --git a/include/Nazara/Audio/Algorithm.hpp b/include/Nazara/Audio/Algorithm.hpp index 830e6ead6..27d1e5394 100644 --- a/include/Nazara/Audio/Algorithm.hpp +++ b/include/Nazara/Audio/Algorithm.hpp @@ -8,9 +8,11 @@ #define NAZARA_ALGORITHM_AUDIO_HPP #include +#include namespace Nz { + inline UInt32 GetChannelCount(AudioFormat format); template void MixToMono(T* input, T* output, UInt32 channelCount, UInt64 frameCount); } diff --git a/include/Nazara/Audio/Algorithm.inl b/include/Nazara/Audio/Algorithm.inl index f7db75e77..858195ef6 100644 --- a/include/Nazara/Audio/Algorithm.inl +++ b/include/Nazara/Audio/Algorithm.inl @@ -2,11 +2,52 @@ // This file is part of the "Nazara Engine - Audio module" // For conditions of distribution and use, see copyright notice in Config.hpp +#include #include #include namespace Nz { + /*! + * \ingroup audio + * \brief Get the number of channels occupied by an audio format + * \returns The number of channels occupied by an audio format (mono returns 1, stero returns 2, etc.) + * + * \param format A valid audio format + * + * \remark The format must be valid (using AudioFormat::Unknown will trigger an error) + */ + UInt32 GetChannelCount(AudioFormat format) + { + NazaraAssert(format != AudioFormat::Unknown, "invalid audio format"); + + switch (format) + { + case AudioFormat::Unknown: //< Just to make the compiler stop complaining + break; + + case AudioFormat::I16_Mono: + return 1; + + case AudioFormat::I16_Stereo: + return 2; + + case AudioFormat::I16_Quad: + return 4; + + case AudioFormat::I16_5_1: + return 6; + + case AudioFormat::I16_6_1: + return 7; + + case AudioFormat::I16_7_1: + return 8; + } + + return 0; + } + /*! * \ingroup audio * \brief Mixes channels in mono diff --git a/include/Nazara/Audio/Audio.hpp b/include/Nazara/Audio/Audio.hpp index cda4110e9..affab10a9 100644 --- a/include/Nazara/Audio/Audio.hpp +++ b/include/Nazara/Audio/Audio.hpp @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include #include @@ -26,18 +28,24 @@ namespace Nz struct Config {}; Audio(Config /*config*/); + Audio(const Audio&) = delete; + Audio(Audio&&) = delete; ~Audio(); - AudioFormat GetAudioFormat(unsigned int channelCount); - float GetDopplerFactor(); - float GetGlobalVolume(); - Vector3f GetListenerDirection(); - Vector3f GetListenerPosition(); - Quaternionf GetListenerRotation(); - Vector3f GetListenerVelocity(); - float GetSpeedOfSound(); + float GetDopplerFactor() const; + float GetGlobalVolume() const; + Vector3f GetListenerDirection() const; + Vector3f GetListenerPosition() const; + Quaternionf GetListenerRotation() const; + Vector3f GetListenerVelocity() const; + SoundBufferLoader& GetSoundBufferLoader(); + const SoundBufferLoader& GetSoundBufferLoader() const; + SoundStreamLoader& GetSoundStreamLoader(); + const SoundStreamLoader& GetSoundStreamLoader() const; + float GetSpeedOfSound() const; + + bool IsFormatSupported(AudioFormat format) const; - bool IsFormatSupported(AudioFormat format); void SetDopplerFactor(float dopplerFactor); void SetGlobalVolume(float volume); void SetListenerDirection(const Vector3f& direction); @@ -49,7 +57,13 @@ namespace Nz void SetListenerVelocity(float velX, float velY, float velZ); void SetSpeedOfSound(float speed); + Audio& operator=(const Audio&) = delete; + Audio& operator=(Audio&&) = delete; + private: + SoundBufferLoader m_soundBufferLoader; + SoundStreamLoader m_soundStreamLoader; + static Audio* s_instance; }; } diff --git a/include/Nazara/Audio/Enums.hpp b/include/Nazara/Audio/Enums.hpp index e3e12b41b..ce084c67a 100644 --- a/include/Nazara/Audio/Enums.hpp +++ b/include/Nazara/Audio/Enums.hpp @@ -9,27 +9,32 @@ namespace Nz { - enum AudioFormat + enum class AudioFormat { - AudioFormat_Unknown = -1, + Unknown = -1, - // The integer value is the number of channels used by the format - AudioFormat_Mono = 1, - AudioFormat_Stereo = 2, - AudioFormat_Quad = 4, - AudioFormat_5_1 = 6, - AudioFormat_6_1 = 7, - AudioFormat_7_1 = 8, + I16_Mono, + I16_Stereo, + I16_Quad, + I16_5_1, + I16_6_1, + I16_7_1, - AudioFormat_Max = AudioFormat_7_1 + Max = I16_7_1 }; - enum SoundStatus + constexpr std::size_t AudioFormatCount = static_cast(AudioFormat::Max) + 1; + + enum class SoundStatus { - SoundStatus_Playing, - SoundStatus_Paused, - SoundStatus_Stopped + Playing, + Paused, + Stopped, + + Max = Stopped }; + + constexpr std::size_t SoundStatusCount = static_cast(SoundStatus::Max) + 1; } #endif // NAZARA_ENUMS_AUDIO_HPP diff --git a/include/Nazara/Audio/Music.hpp b/include/Nazara/Audio/Music.hpp index dd7b00a10..2d951e2a0 100644 --- a/include/Nazara/Audio/Music.hpp +++ b/include/Nazara/Audio/Music.hpp @@ -11,7 +11,9 @@ #include #include #include -#include +#include +#include +#include namespace Nz { @@ -20,12 +22,12 @@ namespace Nz class NAZARA_AUDIO_API Music : public Resource, public SoundEmitter { public: - Music() = default; + Music(); Music(const Music&) = delete; - Music(Music&&) noexcept = default; + Music(Music&&) noexcept; ~Music(); - bool Create(SoundStream* soundStream); + bool Create(std::shared_ptr soundStream); void Destroy(); void EnableLooping(bool loop) override; @@ -51,13 +53,13 @@ namespace Nz void Stop() override; Music& operator=(const Music&) = delete; - Music& operator=(Music&&) noexcept = default; + Music& operator=(Music&&) noexcept; private: - MovablePtr m_impl; + std::unique_ptr m_impl; bool FillAndQueueBuffer(unsigned int buffer); - void MusicThread(); + void MusicThread(std::condition_variable& cv, std::mutex& m, std::exception_ptr& err); void StopThread(); }; } diff --git a/include/Nazara/Audio/OpenAL.hpp b/include/Nazara/Audio/OpenAL.hpp index d3a88974a..5f1bdf879 100644 --- a/include/Nazara/Audio/OpenAL.hpp +++ b/include/Nazara/Audio/OpenAL.hpp @@ -7,7 +7,7 @@ #ifndef NAZARA_OPENAL_HPP #define NAZARA_OPENAL_HPP -#ifdef NAZARA_AUDIO_OPENAL +#if defined(NAZARA_AUDIO_OPENAL) || defined(NAZARA_AUDIO_BUILD) #include #include @@ -80,7 +80,7 @@ namespace Nz static void Uninitialize(); - static ALenum AudioFormat[AudioFormat_Max + 1]; + static ALenum AudioFormat[AudioFormatCount]; private: static void CloseDevice(); diff --git a/include/Nazara/Audio/Sound.hpp b/include/Nazara/Audio/Sound.hpp index 535983bd8..3a24ca2cb 100644 --- a/include/Nazara/Audio/Sound.hpp +++ b/include/Nazara/Audio/Sound.hpp @@ -18,21 +18,20 @@ namespace Nz { public: Sound() = default; - Sound(const SoundBuffer* soundBuffer); - Sound(const Sound& sound); + Sound(std::shared_ptr soundBuffer); + Sound(const Sound&) = default; Sound(Sound&&) noexcept = default; ~Sound(); void EnableLooping(bool loop) override; - const SoundBuffer* GetBuffer() const; + const std::shared_ptr& GetBuffer() const; UInt32 GetDuration() const override; UInt32 GetPlayingOffset() const override; SoundStatus GetStatus() const override; bool IsLooping() const override; bool IsPlayable() const; - bool IsPlaying() const; bool LoadFromFile(const std::filesystem::path& filePath, const SoundBufferParams& params = SoundBufferParams()); bool LoadFromMemory(const void* data, std::size_t size, const SoundBufferParams& params = SoundBufferParams()); @@ -41,7 +40,7 @@ namespace Nz void Pause() override; void Play() override; - void SetBuffer(const SoundBuffer* buffer); + void SetBuffer(std::shared_ptr soundBuffer); void SetPlayingOffset(UInt32 offset); void Stop() override; @@ -50,7 +49,7 @@ namespace Nz Sound& operator=(Sound&&) noexcept = default; private: - SoundBufferConstRef m_buffer; + std::shared_ptr m_buffer; }; } diff --git a/include/Nazara/Audio/SoundBuffer.hpp b/include/Nazara/Audio/SoundBuffer.hpp index ca9ce0036..fdbd3bfac 100644 --- a/include/Nazara/Audio/SoundBuffer.hpp +++ b/include/Nazara/Audio/SoundBuffer.hpp @@ -10,10 +10,7 @@ #include #include #include -#include -#include #include -#include #include #include #include @@ -32,24 +29,18 @@ namespace Nz class Sound; class SoundBuffer; - using SoundBufferConstRef = ObjectRef; using SoundBufferLibrary = ObjectLibrary; using SoundBufferLoader = ResourceLoader; using SoundBufferManager = ResourceManager; - using SoundBufferRef = ObjectRef; struct SoundBufferImpl; - class NAZARA_AUDIO_API SoundBuffer : public RefCounted, public Resource + class NAZARA_AUDIO_API SoundBuffer : public Resource { friend Sound; - friend SoundBufferLibrary; - friend SoundBufferLoader; - friend SoundBufferManager; - friend class Audio; public: - SoundBuffer() = default; + SoundBuffer(); SoundBuffer(AudioFormat format, UInt64 sampleCount, UInt32 sampleRate, const Int16* samples); SoundBuffer(const SoundBuffer&) = delete; SoundBuffer(SoundBuffer&&) = delete; @@ -71,28 +62,14 @@ namespace Nz static bool IsFormatSupported(AudioFormat format); - static SoundBufferRef LoadFromFile(const std::filesystem::path& filePath, const SoundBufferParams& params = SoundBufferParams()); - static SoundBufferRef LoadFromMemory(const void* data, std::size_t size, const SoundBufferParams& params = SoundBufferParams()); - static SoundBufferRef LoadFromStream(Stream& stream, const SoundBufferParams& params = SoundBufferParams()); - - template static SoundBufferRef New(Args&&... args); - - // Signals: - NazaraSignal(OnSoundBufferDestroy, const SoundBuffer* /*soundBuffer*/); - NazaraSignal(OnSoundBufferRelease, const SoundBuffer* /*soundBuffer*/); + static std::shared_ptr LoadFromFile(const std::filesystem::path& filePath, const SoundBufferParams& params = SoundBufferParams()); + static std::shared_ptr LoadFromMemory(const void* data, std::size_t size, const SoundBufferParams& params = SoundBufferParams()); + static std::shared_ptr LoadFromStream(Stream& stream, const SoundBufferParams& params = SoundBufferParams()); private: unsigned int GetOpenALBuffer() const; - static bool Initialize(); - static void Uninitialize(); - - MovablePtr m_impl = nullptr; - - static SoundBufferLibrary::LibraryMap s_library; - static SoundBufferLoader::LoaderList s_loaders; - static SoundBufferManager::ManagerMap s_managerMap; - static SoundBufferManager::ManagerParams s_managerParameters; + std::unique_ptr m_impl; }; } diff --git a/include/Nazara/Audio/SoundBuffer.inl b/include/Nazara/Audio/SoundBuffer.inl index 5bc73396d..70c692e44 100644 --- a/include/Nazara/Audio/SoundBuffer.inl +++ b/include/Nazara/Audio/SoundBuffer.inl @@ -2,26 +2,12 @@ // This file is part of the "Nazara Engine - Audio module" // For conditions of distribution and use, see copyright notice in Config.hpp +#include #include #include namespace Nz { - /*! - * \brief Creates a new sound buffer from the arguments - * \return A reference to the newly created sound buffer - * - * \param args Arguments for the sound buffer - */ - - template - SoundBufferRef SoundBuffer::New(Args&&... args) - { - std::unique_ptr object(new SoundBuffer(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); - } } #include diff --git a/include/Nazara/Audio/SoundEmitter.hpp b/include/Nazara/Audio/SoundEmitter.hpp index 169567a0e..f6dcb676f 100644 --- a/include/Nazara/Audio/SoundEmitter.hpp +++ b/include/Nazara/Audio/SoundEmitter.hpp @@ -37,6 +37,7 @@ namespace Nz float GetVolume() const; virtual bool IsLooping() const = 0; + inline bool IsPlaying() const; bool IsSpatialized() const; virtual void Pause() = 0; @@ -67,4 +68,7 @@ namespace Nz unsigned int m_source; }; } + +#include + #endif // NAZARA_SOUNDEMITTER_HPP diff --git a/include/Nazara/Audio/SoundEmitter.inl b/include/Nazara/Audio/SoundEmitter.inl new file mode 100644 index 000000000..a125e8c20 --- /dev/null +++ b/include/Nazara/Audio/SoundEmitter.inl @@ -0,0 +1,20 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Audio module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + /*! + * \brief Checks whether the sound is playing + * \return true if it is the case + */ + bool SoundEmitter::IsPlaying() const + { + return GetStatus() == SoundStatus::Playing; + } +} + +#include diff --git a/include/Nazara/Audio/SoundStream.hpp b/include/Nazara/Audio/SoundStream.hpp index f1db5a98d..d080bf83f 100644 --- a/include/Nazara/Audio/SoundStream.hpp +++ b/include/Nazara/Audio/SoundStream.hpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -29,12 +28,9 @@ namespace Nz class SoundStream; using SoundStreamLoader = ResourceLoader; - using SoundStreamRef = Nz::ObjectRef; - class NAZARA_AUDIO_API SoundStream : public RefCounted, public Resource + class NAZARA_AUDIO_API SoundStream : public Resource { - friend SoundStreamLoader; - public: SoundStream() = default; virtual ~SoundStream(); @@ -49,12 +45,9 @@ namespace Nz virtual void Seek(UInt64 offset) = 0; virtual UInt64 Tell() = 0; - static SoundStreamRef OpenFromFile(const std::filesystem::path& filePath, const SoundStreamParams& params = SoundStreamParams()); - static SoundStreamRef OpenFromMemory(const void* data, std::size_t size, const SoundStreamParams& params = SoundStreamParams()); - static SoundStreamRef OpenFromStream(Stream& stream, const SoundStreamParams& params = SoundStreamParams()); - - private: - static SoundStreamLoader::LoaderList s_loaders; + static std::shared_ptr OpenFromFile(const std::filesystem::path& filePath, const SoundStreamParams& params = SoundStreamParams()); + static std::shared_ptr OpenFromMemory(const void* data, std::size_t size, const SoundStreamParams& params = SoundStreamParams()); + static std::shared_ptr OpenFromStream(Stream& stream, const SoundStreamParams& params = SoundStreamParams()); }; } diff --git a/include/Nazara/Core/Algorithm.hpp b/include/Nazara/Core/Algorithm.hpp index dec6312a4..6f0754c1b 100644 --- a/include/Nazara/Core/Algorithm.hpp +++ b/include/Nazara/Core/Algorithm.hpp @@ -21,6 +21,8 @@ namespace Nz { class ByteArray; + template decltype(auto) AccessByOffset(void* basePtr, std::size_t offset); + template decltype(auto) AccessByOffset(const void* basePtr, std::size_t offset); template constexpr T Align(T offset, T alignment); template constexpr T AlignPow2(T offset, T alignment); template decltype(auto) Apply(F&& fn, Tuple&& t); diff --git a/include/Nazara/Core/Algorithm.inl b/include/Nazara/Core/Algorithm.inl index 3560f775c..9b4e347fe 100644 --- a/include/Nazara/Core/Algorithm.inl +++ b/include/Nazara/Core/Algorithm.inl @@ -36,6 +36,44 @@ namespace Nz NAZARA_CORE_API extern const UInt8 BitReverseTable256[256]; } + /*! + * \ingroup core + * \brief Access a non-typed struct field by offset + * \return A pointer to the field of the asked type + * + * \param basePtr Pointer to the start of the struct + * \param offset Offset to the field (as generated by offsetof or similar) + */ + template + decltype(auto) AccessByOffset(void* basePtr, std::size_t offset) + { + static_assert((std::is_reference_v && !std::is_rvalue_reference_v) || std::is_pointer_v); + + if constexpr (std::is_reference_v) + return *reinterpret_cast*>(static_cast(basePtr) + offset); + else + return reinterpret_cast(static_cast(basePtr) + offset); + } + + /*! + * \ingroup core + * \brief Access a non-typed struct field by offset + * \return A pointer to the field of the asked type + * + * \param basePtr Pointer to the start of the struct + * \param offset Offset to the field (as generated by offsetof or similar) + */ + template + decltype(auto) AccessByOffset(const void* basePtr, std::size_t offset) + { + static_assert((std::is_reference_v && !std::is_rvalue_reference_v) || std::is_pointer_v); + + if constexpr (std::is_reference_v) + return *reinterpret_cast*>(static_cast(basePtr) + offset); + else + return reinterpret_cast(static_cast(basePtr) + offset); + } + /*! * \ingroup core * \brief Align an offset @@ -330,7 +368,7 @@ namespace Nz // Flush bits in case a writing is in progress context.FlushBits(); - if (context.endianness != Endianness_Unknown && context.endianness != GetPlatformEndianness()) + if (context.endianness != Endianness::Unknown && context.endianness != GetPlatformEndianness()) SwapBytes(&value, sizeof(T)); return context.stream->Write(&value, sizeof(T)) == sizeof(T); @@ -409,7 +447,7 @@ namespace Nz if (context.stream->Read(value, sizeof(T)) == sizeof(T)) { - if (context.endianness != Endianness_Unknown && context.endianness != GetPlatformEndianness()) + if (context.endianness != Endianness::Unknown && context.endianness != GetPlatformEndianness()) SwapBytes(value, sizeof(T)); return true; diff --git a/include/Nazara/Core/Core.hpp b/include/Nazara/Core/Core.hpp index 10cc2eb65..ff7dbb40c 100644 --- a/include/Nazara/Core/Core.hpp +++ b/include/Nazara/Core/Core.hpp @@ -8,6 +8,7 @@ #define NAZARA_CORE_HPP #include +#include #include #include diff --git a/include/Nazara/Core/Endianness.inl b/include/Nazara/Core/Endianness.inl index b3eca0b09..daae48586 100644 --- a/include/Nazara/Core/Endianness.inl +++ b/include/Nazara/Core/Endianness.inl @@ -15,9 +15,9 @@ namespace Nz inline constexpr Endianness GetPlatformEndianness() { #if defined(NAZARA_BIG_ENDIAN) - return Endianness_BigEndian; + return Endianness::BigEndian; #elif defined(NAZARA_LITTLE_ENDIAN) - return Endianness_LittleEndian; + return Endianness::LittleEndian; #endif } diff --git a/include/Nazara/Core/Enums.hpp b/include/Nazara/Core/Enums.hpp index d69e75e72..ecfef308b 100644 --- a/include/Nazara/Core/Enums.hpp +++ b/include/Nazara/Core/Enums.hpp @@ -11,204 +11,224 @@ namespace Nz { - enum CoordSys + enum class CoordSys { - CoordSys_Global, - CoordSys_Local, + Global, + Local, - CoordSys_Max = CoordSys_Local + Max = Local }; - enum CursorPosition + enum class CursorPosition { - CursorPosition_AtBegin, // beginning of the file - CursorPosition_AtCurrent, // Position of the cursor - CursorPosition_AtEnd, // End of the file + AtBegin, // beginning of the file + AtCurrent, // Position of the cursor + AtEnd, // End of the file - CursorPosition_Max = CursorPosition_AtEnd + Max = AtEnd }; - enum Endianness + enum class Endianness { - Endianness_Unknown = -1, + Unknown = -1, - Endianness_BigEndian, - Endianness_LittleEndian, + BigEndian, + LittleEndian, - Endianness_Max = Endianness_LittleEndian + Max = LittleEndian }; - enum ErrorFlag + enum class ErrorMode { - ErrorFlag_None = 0, + None, - ErrorFlag_Silent = 0x1, - ErrorFlag_SilentDisabled = 0x2, - ErrorFlag_ThrowException = 0x4, - ErrorFlag_ThrowExceptionDisabled = 0x8, + Silent, + SilentDisabled, + ThrowException, + ThrowExceptionDisabled, - ErrorFlag_Max = ErrorFlag_ThrowExceptionDisabled * 2 - 1 + Max = ThrowExceptionDisabled }; - enum ErrorType + template<> + struct EnumAsFlags { - ErrorType_AssertFailed, - ErrorType_Internal, - ErrorType_Normal, - ErrorType_Warning, - - ErrorType_Max = ErrorType_Warning + static constexpr ErrorMode max = ErrorMode::Max; }; - enum HashType - { - HashType_CRC32, - HashType_CRC64, - HashType_Fletcher16, - HashType_MD5, - HashType_SHA1, - HashType_SHA224, - HashType_SHA256, - HashType_SHA384, - HashType_SHA512, - HashType_Whirlpool, + using ErrorModeFlags = Flags; - HashType_Max = HashType_Whirlpool + enum class ErrorType + { + AssertFailed, + Internal, + Normal, + Warning, + + Max = Warning }; - enum OpenMode + constexpr std::size_t ErrorTypeCount = static_cast(ErrorType::Max) + 1; + + enum class HashType { - OpenMode_NotOpen, // Use the current mod of opening + CRC32, + CRC64, + Fletcher16, + MD5, + SHA1, + SHA224, + SHA256, + SHA384, + SHA512, + Whirlpool, - OpenMode_Append, // Disable writing on existing parts and put the cursor at the end - OpenMode_Lock, // Disable modifying the file before it is open - OpenMode_MustExist, // Fail if the file doesn't exists, even if opened in write mode - OpenMode_ReadOnly, // Open in read only - OpenMode_Text, // Open in text mod - OpenMode_Truncate, // Create the file if it doesn't exist and empty it if it exists - OpenMode_WriteOnly, // Open in write only, create the file if it doesn't exist + Max = Whirlpool + }; - OpenMode_Max = OpenMode_WriteOnly + constexpr std::size_t HashTypeCount = static_cast(HashType::Max) + 1; + + enum class OpenMode + { + NotOpen, // Use the current mod of opening + + Append, // Disable writing on existing parts and put the cursor at the end + Lock, // Disable modifying the file before it is open + MustExist, // Fail if the file doesn't exists, even if opened in write mode + ReadOnly, // Open in read only + Text, // Open in text mod + Truncate, // Create the file if it doesn't exist and empty it if it exists + WriteOnly, // Open in write only, create the file if it doesn't exist + + Max = WriteOnly }; template<> struct EnumAsFlags { - static constexpr OpenMode max = OpenMode_Max; + static constexpr OpenMode max = OpenMode::Max; }; using OpenModeFlags = Flags; - constexpr OpenModeFlags OpenMode_ReadWrite = OpenMode_ReadOnly | OpenMode_WriteOnly; + constexpr OpenModeFlags OpenMode_ReadWrite = OpenMode::ReadOnly | OpenMode::WriteOnly; - enum ParameterType + enum class ParameterType { - ParameterType_Boolean, - ParameterType_Color, - ParameterType_Double, - ParameterType_Integer, - ParameterType_None, - ParameterType_Pointer, - ParameterType_String, - ParameterType_Userdata, + Boolean, + Color, + Double, + Integer, + None, + Pointer, + String, + Userdata, - ParameterType_Max = ParameterType_Userdata + Max = Userdata }; - enum Plugin + enum class Plugin { - Plugin_Assimp, + Assimp, - Plugin_Count + Max = Assimp }; - enum PrimitiveType - { - PrimitiveType_Box, - PrimitiveType_Cone, - PrimitiveType_Plane, - PrimitiveType_Sphere, + constexpr std::size_t PluginCount = static_cast(Plugin::Max) + 1; - PrimitiveType_Max = PrimitiveType_Sphere + enum class PrimitiveType + { + Box, + Cone, + Plane, + Sphere, + + Max = Sphere }; - enum ProcessorCap - { - ProcessorCap_x64, - ProcessorCap_AVX, - ProcessorCap_FMA3, - ProcessorCap_FMA4, - ProcessorCap_MMX, - ProcessorCap_XOP, - ProcessorCap_SSE, - ProcessorCap_SSE2, - ProcessorCap_SSE3, - ProcessorCap_SSSE3, - ProcessorCap_SSE41, - ProcessorCap_SSE42, - ProcessorCap_SSE4a, + constexpr std::size_t PrimitiveTypeCount = static_cast(PrimitiveType::Max) + 1; - ProcessorCap_Max = ProcessorCap_SSE4a + enum class ProcessorCap + { + x64, + AVX, + FMA3, + FMA4, + MMX, + XOP, + SSE, + SSE2, + SSE3, + SSSE3, + SSE41, + SSE42, + SSE4a, + + Max = SSE4a }; - enum ProcessorVendor + constexpr std::size_t ProcessorCapCount = static_cast(ProcessorCap::Max) + 1; + + enum class ProcessorVendor { - ProcessorVendor_Unknown = -1, + Unknown = -1, - ProcessorVendor_AMD, - ProcessorVendor_Centaur, - ProcessorVendor_Cyrix, - ProcessorVendor_Intel, - ProcessorVendor_KVM, - ProcessorVendor_HyperV, - ProcessorVendor_NSC, - ProcessorVendor_NexGen, - ProcessorVendor_Rise, - ProcessorVendor_SIS, - ProcessorVendor_Transmeta, - ProcessorVendor_UMC, - ProcessorVendor_VIA, - ProcessorVendor_VMware, - ProcessorVendor_Vortex, - ProcessorVendor_XenHVM, + AMD, + Centaur, + Cyrix, + Intel, + KVM, + HyperV, + NSC, + NexGen, + Rise, + SIS, + Transmeta, + UMC, + VIA, + VMware, + Vortex, + XenHVM, - ProcessorVendor_Max = ProcessorVendor_XenHVM + Max = XenHVM }; - enum SphereType - { - SphereType_Cubic, - SphereType_Ico, - SphereType_UV, + constexpr std::size_t ProcessorVendorCount = static_cast(ProcessorVendor::Max) + 1; - SphereType_Max = SphereType_UV + enum class SphereType + { + Cubic, + Ico, + UV, + + Max = UV }; - enum StreamOption + enum class StreamOption { - StreamOption_None, + None, - StreamOption_Sequential, - StreamOption_Text, + Sequential, + Text, - StreamOption_Max = StreamOption_Text + Max = Text }; template<> struct EnumAsFlags { - static constexpr StreamOption max = StreamOption_Max; + static constexpr StreamOption max = StreamOption::Max; }; using StreamOptionFlags = Flags; - enum Ternary + enum class Ternary { - Ternary_False, - Ternary_True, - Ternary_Unknown, + False, + True, + Unknown, - Ternary_Max = Ternary_Unknown + Max = Unknown }; } diff --git a/include/Nazara/Core/Error.hpp b/include/Nazara/Core/Error.hpp index 4ff2e229f..ef20ffd24 100644 --- a/include/Nazara/Core/Error.hpp +++ b/include/Nazara/Core/Error.hpp @@ -13,14 +13,14 @@ #include #if NAZARA_CORE_ENABLE_ASSERTS || defined(NAZARA_DEBUG) - #define NazaraAssert(a, err) if (!(a)) Nz::Error::Trigger(Nz::ErrorType_AssertFailed, err, __LINE__, __FILE__, NAZARA_FUNCTION) + #define NazaraAssert(a, err) if (!(a)) Nz::Error::Trigger(Nz::ErrorType::AssertFailed, err, __LINE__, __FILE__, NAZARA_FUNCTION) #else #define NazaraAssert(a, err) for (;;) break #endif -#define NazaraError(err) Nz::Error::Trigger(Nz::ErrorType_Normal, err, __LINE__, __FILE__, NAZARA_FUNCTION) -#define NazaraInternalError(err) Nz::Error::Trigger(Nz::ErrorType_Internal, err, __LINE__, __FILE__, NAZARA_FUNCTION) -#define NazaraWarning(err) Nz::Error::Trigger(Nz::ErrorType_Warning, err, __LINE__, __FILE__, NAZARA_FUNCTION) +#define NazaraError(err) Nz::Error::Trigger(Nz::ErrorType::Normal, err, __LINE__, __FILE__, NAZARA_FUNCTION) +#define NazaraInternalError(err) Nz::Error::Trigger(Nz::ErrorType::Internal, err, __LINE__, __FILE__, NAZARA_FUNCTION) +#define NazaraWarning(err) Nz::Error::Trigger(Nz::ErrorType::Warning, err, __LINE__, __FILE__, NAZARA_FUNCTION) namespace Nz { @@ -30,12 +30,12 @@ namespace Nz Error() = delete; ~Error() = delete; - static UInt32 GetFlags(); + static ErrorModeFlags GetFlags(); static std::string GetLastError(const char** file = nullptr, unsigned int* line = nullptr, const char** function = nullptr); static unsigned int GetLastSystemErrorCode(); static std::string GetLastSystemError(unsigned int code = GetLastSystemErrorCode()); - static void SetFlags(UInt32 flags); + static void SetFlags(ErrorModeFlags flags); static void Trigger(ErrorType type, std::string error); static void Trigger(ErrorType type, std::string error, unsigned int line, const char* file, const char* function); @@ -43,7 +43,7 @@ namespace Nz private: static const char* GetCurrentFileRelativeToEngine(const char* file); - static UInt32 s_flags; + static ErrorModeFlags s_flags; static std::string s_lastError; static const char* s_lastErrorFunction; static const char* s_lastErrorFile; diff --git a/include/Nazara/Core/ErrorFlags.hpp b/include/Nazara/Core/ErrorFlags.hpp index abcabbfc5..3c7ddd43f 100644 --- a/include/Nazara/Core/ErrorFlags.hpp +++ b/include/Nazara/Core/ErrorFlags.hpp @@ -8,26 +8,27 @@ #define NAZARA_ERRORFLAGS_HPP #include +#include namespace Nz { class NAZARA_CORE_API ErrorFlags { public: - ErrorFlags(UInt32 flags, bool replace = false); + ErrorFlags(ErrorModeFlags flags, bool replace = false); ErrorFlags(const ErrorFlags&) = delete; ErrorFlags(ErrorFlags&&) = delete; ~ErrorFlags(); - UInt32 GetPreviousFlags() const; + ErrorModeFlags GetPreviousFlags() const; - void SetFlags(UInt32 flags, bool replace = false); + void SetFlags(ErrorModeFlags flags, bool replace = false); ErrorFlags& operator=(const ErrorFlags&) = delete; ErrorFlags& operator=(ErrorFlags&&) = delete; private: - UInt32 m_previousFlags; + ErrorModeFlags m_previousFlags; }; } diff --git a/include/Nazara/Core/File.hpp b/include/Nazara/Core/File.hpp index f41c4e773..f0da5c4f4 100644 --- a/include/Nazara/Core/File.hpp +++ b/include/Nazara/Core/File.hpp @@ -48,8 +48,8 @@ namespace Nz bool IsOpen() const; - bool Open(OpenModeFlags openMode = OpenMode_NotOpen); - bool Open(const std::filesystem::path& filePath, OpenModeFlags openMode = OpenMode_NotOpen); + bool Open(OpenModeFlags openMode = OpenMode::NotOpen); + bool Open(const std::filesystem::path& filePath, OpenModeFlags openMode = OpenMode::NotOpen); bool SetCursorPos(CursorPosition pos, Int64 offset = 0); bool SetCursorPos(UInt64 offset) override; diff --git a/include/Nazara/Core/Flags.hpp b/include/Nazara/Core/Flags.hpp index 36ff02f6b..2211a9d9f 100644 --- a/include/Nazara/Core/Flags.hpp +++ b/include/Nazara/Core/Flags.hpp @@ -18,26 +18,29 @@ namespace Nz { }; - // From: https://stackoverflow.com/questions/11927032/sfinae-check-for-static-member-using-decltype - template - class IsEnumFlag - { - template::max)>::value>::type> - static std::true_type check(int); - template static std::false_type check(...); + template + struct IsEnumFlag : std::false_type {}; - public: - static constexpr bool value = decltype(check(0))::value; - }; + template + struct IsEnumFlag::max)>> : std::true_type {}; + + + template + struct GetEnumAutoFlag : std::integral_constant {}; + + template + struct GetEnumAutoFlag> : std::integral_constant {}; template class Flags { - static_assert(std::is_enum::value, "Type must be an enumeration"); - static_assert(IsEnumFlag::value, "Enum has not been enabled as flags by an EnumAsFlags specialization"); + static_assert(std::is_enum_v, "Type must be an enumeration"); + static_assert(IsEnumFlag(), "Enum has not been enabled as flags by an EnumAsFlags specialization"); + static_assert(std::is_same_v::max)>, E>, "EnumAsFlags field max should be of the same type as the enum"); static constexpr std::size_t MaxValue = static_cast(EnumAsFlags::max); + static constexpr bool AutoFlag = GetEnumAutoFlag(); using BitField16 = std::conditional_t<(MaxValue >= 8), UInt16, UInt8>; using BitField32 = std::conditional_t<(MaxValue >= 16), UInt32, BitField16>; diff --git a/include/Nazara/Core/Flags.inl b/include/Nazara/Core/Flags.inl index 36a001c4f..cb51a277a 100644 --- a/include/Nazara/Core/Flags.inl +++ b/include/Nazara/Core/Flags.inl @@ -258,7 +258,10 @@ namespace Nz template constexpr typename Flags::BitField Flags::GetFlagValue(E enumValue) { - return 1U << static_cast(enumValue); + if constexpr (AutoFlag) + return 1U << static_cast(enumValue); + else + return enumValue; } /*! diff --git a/include/Nazara/Core/HandledObject.hpp b/include/Nazara/Core/HandledObject.hpp index 50a283059..d5293dc84 100644 --- a/include/Nazara/Core/HandledObject.hpp +++ b/include/Nazara/Core/HandledObject.hpp @@ -37,7 +37,10 @@ namespace Nz HandledObject(HandledObject&& object) noexcept; ~HandledObject(); - ObjectHandle CreateHandle(); + template + ObjectHandle CreateHandle(); + + std::shared_ptr GetHandleData(); HandledObject& operator=(const HandledObject& object); HandledObject& operator=(HandledObject&& object) noexcept; @@ -48,7 +51,6 @@ namespace Nz void UnregisterAllHandles() noexcept; private: - std::shared_ptr GetHandleData(); void InitHandleData(); std::shared_ptr m_handleData; diff --git a/include/Nazara/Core/HandledObject.inl b/include/Nazara/Core/HandledObject.inl index 909828277..fd731b536 100644 --- a/include/Nazara/Core/HandledObject.inl +++ b/include/Nazara/Core/HandledObject.inl @@ -58,9 +58,20 @@ namespace Nz * \return ObjectHandle to this */ template - ObjectHandle HandledObject::CreateHandle() + template + ObjectHandle HandledObject::CreateHandle() { - return ObjectHandle(static_cast(this)); + static_assert(std::is_base_of::value, "Cannot retrieve a handle for a non-related class"); + return ObjectHandle(static_cast(this)); + } + + template + std::shared_ptr HandledObject::GetHandleData() + { + if (!m_handleData) + InitHandleData(); + + return std::shared_ptr(m_handleData); } /*! @@ -112,15 +123,6 @@ namespace Nz } } - template - std::shared_ptr HandledObject::GetHandleData() - { - if (!m_handleData) - InitHandleData(); - - return std::shared_ptr(m_handleData); - } - template void HandledObject::InitHandleData() { diff --git a/include/Nazara/Core/MemoryStream.inl b/include/Nazara/Core/MemoryStream.inl index 1395b3137..0e7b0abc3 100644 --- a/include/Nazara/Core/MemoryStream.inl +++ b/include/Nazara/Core/MemoryStream.inl @@ -13,7 +13,7 @@ namespace Nz * \brief Constructs a MemoryStream object by default */ inline MemoryStream::MemoryStream() : - Stream(StreamOption_None, OpenMode_ReadWrite), + Stream(StreamOption::None, OpenMode_ReadWrite), m_pos(0) { } diff --git a/include/Nazara/Core/ModuleBase.hpp b/include/Nazara/Core/ModuleBase.hpp index 8d484f209..2796ed8f2 100644 --- a/include/Nazara/Core/ModuleBase.hpp +++ b/include/Nazara/Core/ModuleBase.hpp @@ -18,6 +18,12 @@ namespace Nz friend class Core; public: + ModuleBase(const ModuleBase&) = delete; + ModuleBase(ModuleBase&&) = delete; + + ModuleBase& operator=(const ModuleBase&) = delete; + ModuleBase& operator=(ModuleBase&&) = delete; + static T* Instance(); protected: @@ -30,6 +36,7 @@ namespace Nz ModuleBase(std::string moduleName, T* pointer, NoLog); void LogInit(); + void LogUninit(); std::string m_moduleName; }; diff --git a/include/Nazara/Core/ModuleBase.inl b/include/Nazara/Core/ModuleBase.inl index 0ec21b215..8a8006111 100644 --- a/include/Nazara/Core/ModuleBase.inl +++ b/include/Nazara/Core/ModuleBase.inl @@ -26,7 +26,7 @@ namespace Nz template ModuleBase::~ModuleBase() { - NazaraNotice("Uninitializing " + m_moduleName + "..."); + LogUninit(); T::s_instance = nullptr; } @@ -41,6 +41,12 @@ namespace Nz { NazaraNotice("Initializing " + m_moduleName + "..."); } + + template + void ModuleBase::LogUninit() + { + NazaraNotice("Uninitializing " + m_moduleName + "..."); + } } #include diff --git a/include/Nazara/Core/Modules.inl b/include/Nazara/Core/Modules.inl index 933720166..7752fcba5 100644 --- a/include/Nazara/Core/Modules.inl +++ b/include/Nazara/Core/Modules.inl @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include namespace Nz @@ -18,7 +19,10 @@ namespace Nz if constexpr (std::is_same_v>) return std::forward(first); else + { + NazaraUnused(first); return Get(std::forward(args)...); + } } static auto Get() diff --git a/include/Nazara/Core/ObjectHandle.hpp b/include/Nazara/Core/ObjectHandle.hpp index 5173838ad..08795b8f0 100644 --- a/include/Nazara/Core/ObjectHandle.hpp +++ b/include/Nazara/Core/ObjectHandle.hpp @@ -23,6 +23,8 @@ namespace Nz public: ObjectHandle(); explicit ObjectHandle(T* object); + template ObjectHandle(const ObjectHandle& ref); + template ObjectHandle(ObjectHandle&& ref); ObjectHandle(const ObjectHandle& handle) = default; ObjectHandle(ObjectHandle&& handle) noexcept; ~ObjectHandle(); @@ -79,6 +81,11 @@ namespace Nz template bool operator>=(const T& lhs, const ObjectHandle& rhs); template bool operator>=(const ObjectHandle& lhs, const T& rhs); + template ObjectHandle ConstRefCast(const ObjectHandle& ref); + template ObjectHandle DynamicRefCast(const ObjectHandle& ref); + template ObjectHandle ReinterpretRefCast(const ObjectHandle& ref); + template ObjectHandle StaticRefCast(const ObjectHandle& ref); + template struct PointedType> { using type = T; }; template struct PointedType> { using type = T; }; } diff --git a/include/Nazara/Core/ObjectHandle.inl b/include/Nazara/Core/ObjectHandle.inl index e94624780..d6e10d3e6 100644 --- a/include/Nazara/Core/ObjectHandle.inl +++ b/include/Nazara/Core/ObjectHandle.inl @@ -26,15 +26,34 @@ namespace Nz { } + template + template + ObjectHandle::ObjectHandle(const ObjectHandle& ref) : + m_handleData(ref.m_handleData) + { + static_assert(std::is_base_of::value, "Can only implicitly convert from a derived to a base"); + } + + template + template + ObjectHandle::ObjectHandle(ObjectHandle&& ref) : + m_handleData(std::move(ref.m_handleData)) + { + ref.m_handleData = Detail::HandleData::GetEmptyObject(); + + static_assert(std::is_base_of::value, "Can only implicitly convert from a derived to a base"); + } + /*! * \brief Constructs a ObjectHandle object by move semantic * * \param handle ObjectHandle to move into this */ template - ObjectHandle::ObjectHandle(ObjectHandle&& handle) noexcept + ObjectHandle::ObjectHandle(ObjectHandle&& handle) noexcept : + m_handleData(std::move(handle.m_handleData)) { - Reset(std::move(handle)); + handle.m_handleData = Detail::HandleData::GetEmptyObject(); } /*! @@ -458,6 +477,60 @@ namespace Nz return !(lhs < rhs); } + /*! + * \brief Casts an ObjectHandle from one type to another using static_cast + * \return Reference to the casted object + * + * \param ref The reference to convert + * + * \remark It is an undefined behavior to cast between incompatible types + */ + template + ObjectHandle ConstRefCast(const ObjectHandle& ref) + { + return ObjectHandle(const_cast(ref.GetObject())); + } + + /*! + * \brief Casts an ObjectHandle from one type to another using static_cast + * \return Reference to the casted object + * + * \param ref The reference to convert + */ + template + ObjectHandle DynamicRefCast(const ObjectHandle& ref) + { + return ObjectHandle(dynamic_cast(ref.GetObject())); + } + + /*! + * \brief Casts an ObjectHandle from one type to another using static_cast + * \return Reference to the casted object + * + * \param ref The reference to convert + * + * \remark It is an undefined behavior to cast between incompatible types + */ + template + ObjectHandle ReinterpretRefCast(const ObjectHandle& ref) + { + return ObjectHandle(static_cast(ref.GetObject())); + } + + /*! + * \brief Casts an ObjectHandle from one type to another using static_cast + * \return Reference to the casted object + * + * \param ref The reference to convert + * + * \remark It is an undefined behavior to cast between incompatible types + */ + template + ObjectHandle StaticRefCast(const ObjectHandle& ref) + { + return ObjectHandle(static_cast(ref.GetObject())); + } + template const ObjectHandle ObjectHandle::InvalidHandle; } diff --git a/include/Nazara/Core/ObjectLibrary.hpp b/include/Nazara/Core/ObjectLibrary.hpp index 859dc82bb..0a69c14ed 100644 --- a/include/Nazara/Core/ObjectLibrary.hpp +++ b/include/Nazara/Core/ObjectLibrary.hpp @@ -7,8 +7,7 @@ #ifndef NAZARA_OBJECTLIBRARY_HPP #define NAZARA_OBJECTLIBRARY_HPP -#include -#include +#include #include #include @@ -20,23 +19,20 @@ namespace Nz friend Type; public: - ObjectLibrary() = delete; - ~ObjectLibrary() = delete; + ObjectLibrary() = default; + ~ObjectLibrary() = default; - static void Clear(); + void Clear(); - static ObjectRef Get(const std::string& name); - static bool Has(const std::string& name); + std::shared_ptr Get(const std::string& name); + bool Has(const std::string& name); - static void Register(const std::string& name, ObjectRef object); - static ObjectRef Query(const std::string& name); - static void Unregister(const std::string& name); + void Register(const std::string& name, std::shared_ptr object); + std::shared_ptr Query(const std::string& name); + void Unregister(const std::string& name); private: - static bool Initialize(); - static void Uninitialize(); - - using LibraryMap = std::unordered_map>; + std::unordered_map> m_library; }; } diff --git a/include/Nazara/Core/ObjectLibrary.inl b/include/Nazara/Core/ObjectLibrary.inl index a39b0b7a8..6d30b64cb 100644 --- a/include/Nazara/Core/ObjectLibrary.inl +++ b/include/Nazara/Core/ObjectLibrary.inl @@ -20,11 +20,11 @@ namespace Nz template void ObjectLibrary::Clear() { - Type::s_library.clear(); + m_library.clear(); } /*! - * \brief Gets the ObjectRef object by name + * \brief Gets the std::shared_ptr object by name * \return Optional reference * * \param name Name of the object @@ -32,9 +32,9 @@ namespace Nz * \remark Produces a NazaraError if object not found */ template - ObjectRef ObjectLibrary::Get(const std::string& name) + std::shared_ptr ObjectLibrary::Get(const std::string& name) { - ObjectRef ref = Query(name); + std::shared_ptr ref = Query(name); if (!ref) NazaraError("Object \"" + name + "\" is not present"); @@ -48,58 +48,46 @@ namespace Nz template bool ObjectLibrary::Has(const std::string& name) { - return Type::s_library.find(name) != Type::s_library.end(); + return m_library.find(name) != m_library.end(); } /*! - * \brief Registers the ObjectRef object with that name + * \brief Registers the std::shared_ptr object with that name * * \param name Name of the object * \param object Object to stock */ template - void ObjectLibrary::Register(const std::string& name, ObjectRef object) + void ObjectLibrary::Register(const std::string& name, std::shared_ptr object) { - Type::s_library.emplace(name, object); + m_library.emplace(name, object); } /*! - * \brief Gets the ObjectRef object by name + * \brief Gets the std::shared_ptr object by name * \return Optional reference * * \param name Name of the object */ template - ObjectRef ObjectLibrary::Query(const std::string& name) + std::shared_ptr ObjectLibrary::Query(const std::string& name) { - auto it = Type::s_library.find(name); - if (it != Type::s_library.end()) + auto it = m_library.find(name); + if (it != m_library.end()) return it->second; else return nullptr; } /*! - * \brief Unregisters the ObjectRef object with that name + * \brief Unregisters the std::shared_ptr object with that name * * \param name Name of the object */ template void ObjectLibrary::Unregister(const std::string& name) { - Type::s_library.erase(name); - } - - template - bool ObjectLibrary::Initialize() - { - return true; // Nothing to do - } - - template - void ObjectLibrary::Uninitialize() - { - Type::s_library.clear(); + m_library.erase(name); } } diff --git a/include/Nazara/Core/Primitive.inl b/include/Nazara/Core/Primitive.inl index d9bd6f24c..58810e287 100644 --- a/include/Nazara/Core/Primitive.inl +++ b/include/Nazara/Core/Primitive.inl @@ -24,7 +24,7 @@ namespace Nz { matrix = transformMatrix; textureCoords = uvCoords; - type = PrimitiveType_Box; + type = PrimitiveType::Box; box.lengths = lengths; box.subdivision = subdivision; } @@ -56,7 +56,7 @@ namespace Nz { matrix = transformMatrix; textureCoords = uvCoords; - type = PrimitiveType_Cone; + type = PrimitiveType::Cone; cone.length = length; cone.radius = radius; cone.subdivision = subdivision; @@ -89,9 +89,9 @@ namespace Nz { matrix = transformMatrix; textureCoords = uvCoords; - type = PrimitiveType_Sphere; + type = PrimitiveType::Sphere; sphere.size = size; - sphere.type = SphereType_Cubic; + sphere.type = SphereType::Cubic; sphere.cubic.subdivision = subdivision; } @@ -121,9 +121,9 @@ namespace Nz { matrix = transformMatrix; textureCoords = uvCoords; - type = PrimitiveType_Sphere; + type = PrimitiveType::Sphere; sphere.size = size; - sphere.type = SphereType_Ico; + sphere.type = SphereType::Ico; sphere.ico.recursionLevel = recursionLevel; } @@ -153,7 +153,7 @@ namespace Nz { matrix = transformMatrix; textureCoords = uvCoords; - type = PrimitiveType_Plane; + type = PrimitiveType::Plane; plane.size = size; plane.subdivision = subdivision; } @@ -198,9 +198,9 @@ namespace Nz { matrix = transformMatrix; textureCoords = uvCoords; - type = PrimitiveType_Sphere; + type = PrimitiveType::Sphere; sphere.size = size; - sphere.type = SphereType_UV; + sphere.type = SphereType::UV; sphere.uv.sliceCount = sliceCount; sphere.uv.stackCount = stackCount; } diff --git a/include/Nazara/Core/ResourceLoader.hpp b/include/Nazara/Core/ResourceLoader.hpp index 97f9a8d83..a1ab46e39 100644 --- a/include/Nazara/Core/ResourceLoader.hpp +++ b/include/Nazara/Core/ResourceLoader.hpp @@ -8,14 +8,13 @@ #define NAZARA_RESOURCELOADER_HPP #include -#include -#include #include #include #include -#include -#include +#include +#include #include +#include namespace Nz { @@ -29,27 +28,43 @@ namespace Nz friend Type; public: - using ExtensionGetter = bool (*)(const std::string& extension); - using FileLoader = ObjectRef (*)(const std::filesystem::path& filePath, const Parameters& parameters); - using MemoryLoader = ObjectRef (*)(const void* data, std::size_t size, const Parameters& parameters); - using StreamChecker = Ternary (*)(Stream& stream, const Parameters& parameters); - using StreamLoader = ObjectRef (*)(Stream& stream, const Parameters& parameters); + struct Entry; + using ExtensionSupport = std::function; + using FileLoader = std::function(const std::filesystem::path& filePath, const Parameters& parameters)>; + using MemoryLoader = std::function(const void* data, std::size_t size, const Parameters& parameters)>; + using StreamChecker = std::function; + using StreamLoader = std::function(Stream& stream, const Parameters& parameters)>; - ResourceLoader() = delete; - ~ResourceLoader() = delete; + ResourceLoader() = default; + ResourceLoader(const ResourceLoader&) = delete; + ResourceLoader(ResourceLoader&&) noexcept = default; + ~ResourceLoader() = default; - static bool IsExtensionSupported(const std::string& extension); + void Clear(); - static ObjectRef LoadFromFile(const std::filesystem::path& filePath, const Parameters& parameters = Parameters()); - static ObjectRef LoadFromMemory(const void* data, std::size_t size, const Parameters& parameters = Parameters()); - static ObjectRef LoadFromStream(Stream& stream, const Parameters& parameters = Parameters()); + bool IsExtensionSupported(const std::string_view& extension) const; - static void RegisterLoader(ExtensionGetter extensionGetter, StreamChecker checkFunc, StreamLoader streamLoader, FileLoader fileLoader = nullptr, MemoryLoader memoryLoader = nullptr); - static void UnregisterLoader(ExtensionGetter extensionGetter, StreamChecker checkFunc, StreamLoader streamLoader, FileLoader fileLoader = nullptr, MemoryLoader memoryLoader = nullptr); + std::shared_ptr LoadFromFile(const std::filesystem::path& filePath, const Parameters& parameters = Parameters()) const; + std::shared_ptr LoadFromMemory(const void* data, std::size_t size, const Parameters& parameters = Parameters()) const; + std::shared_ptr LoadFromStream(Stream& stream, const Parameters& parameters = Parameters()) const; + + const Entry* RegisterLoader(Entry loader); + void UnregisterLoader(const Entry* loader); + + ResourceLoader& operator=(const ResourceLoader&) = delete; + ResourceLoader& operator=(ResourceLoader&&) noexcept = default; + + struct Entry + { + ExtensionSupport extensionSupport; + FileLoader fileLoader; + MemoryLoader memoryLoader; + StreamChecker streamChecker; + StreamLoader streamLoader; + }; private: - using Loader = std::tuple; - using LoaderList = std::list; + std::vector> m_loaders; }; } diff --git a/include/Nazara/Core/ResourceLoader.inl b/include/Nazara/Core/ResourceLoader.inl index baddafd4f..c9d7362b9 100644 --- a/include/Nazara/Core/ResourceLoader.inl +++ b/include/Nazara/Core/ResourceLoader.inl @@ -18,20 +18,29 @@ namespace Nz * \brief Core class that represents a loader of resources */ + /*! + * \brief Unregister every loader registered + */ + template + void ResourceLoader::Clear() + { + m_loaders.clear(); + } + /*! * \brief Checks whether the extension of the file is supported * \return true if supported * - * \param extension Extension of the file + * \param extension Extension of the file (ex: "png") */ template - bool ResourceLoader::IsExtensionSupported(const std::string& extension) + bool ResourceLoader::IsExtensionSupported(const std::string_view& extension) const { - for (Loader& loader : Type::s_loaders) + for (auto& loaderPtr : m_loaders) { - ExtensionGetter isExtensionSupported = std::get<0>(loader); + const Entry& loader = *loaderPtr; - if (isExtensionSupported && isExtensionSupported(extension)) + if (loader.extensionSupport && loader.extensionSupport(extension)) return true; } @@ -54,7 +63,7 @@ namespace Nz * \remark Produces a NazaraError if all loaders failed or no loader was found */ template - ObjectRef ResourceLoader::LoadFromFile(const std::filesystem::path& filePath, const Parameters& parameters) + std::shared_ptr ResourceLoader::LoadFromFile(const std::filesystem::path& filePath, const Parameters& parameters) const { NazaraAssert(parameters.IsValid(), "Invalid parameters"); @@ -71,45 +80,42 @@ namespace Nz File file(filePath.generic_u8string()); // Open only if needed bool found = false; - for (Loader& loader : Type::s_loaders) + for (auto& loaderPtr : m_loaders) { - ExtensionGetter isExtensionSupported = std::get<0>(loader); - if (!isExtensionSupported || !isExtensionSupported(ext)) + const Entry& loader = *loaderPtr; + + if (loader.extensionSupport && !loader.extensionSupport(ext)) continue; - StreamChecker checkFunc = std::get<1>(loader); - StreamLoader streamLoader = std::get<2>(loader); - FileLoader fileLoader = std::get<3>(loader); - - if (checkFunc && !file.IsOpen()) + if (loader.streamChecker && !file.IsOpen()) { - if (!file.Open(OpenMode_ReadOnly)) + if (!file.Open(OpenMode::ReadOnly)) { NazaraError("Failed to load file: unable to open \"" + filePath.generic_u8string() + '"'); return nullptr; } } - Ternary recognized = Ternary_Unknown; - if (fileLoader) + Ternary recognized = Ternary::Unknown; + if (loader.fileLoader) { - if (checkFunc) + if (loader.streamChecker) { file.SetCursorPos(0); - recognized = checkFunc(file, parameters); - if (recognized == Ternary_False) + recognized = loader.streamChecker(file, parameters); + if (recognized == Ternary::False) continue; else found = true; } else { - recognized = Ternary_Unknown; + recognized = Ternary::Unknown; found = true; } - ObjectRef resource = fileLoader(filePath, parameters); + std::shared_ptr resource = loader.fileLoader(filePath, parameters); if (resource) { resource->SetFilePath(filePath); @@ -118,17 +124,19 @@ namespace Nz } else { + assert(loader.streamChecker); + file.SetCursorPos(0); - recognized = checkFunc(file, parameters); - if (recognized == Ternary_False) + recognized = loader.streamChecker(file, parameters); + if (recognized == Ternary::False) continue; - else if (recognized == Ternary_True) + else if (recognized == Ternary::True) found = true; file.SetCursorPos(0); - ObjectRef resource = streamLoader(file, parameters); + std::shared_ptr resource = loader.streamLoader(file, parameters); if (resource) { resource->SetFilePath(filePath); @@ -136,7 +144,7 @@ namespace Nz } } - if (recognized == Ternary_True) + if (recognized == Ternary::True) NazaraWarning("Loader failed"); } @@ -164,7 +172,7 @@ namespace Nz * \remark Produces a NazaraError if all loaders failed or no loader was found */ template - ObjectRef ResourceLoader::LoadFromMemory(const void* data, std::size_t size, const Parameters& parameters) + std::shared_ptr ResourceLoader::LoadFromMemory(const void* data, std::size_t size, const Parameters& parameters) const { NazaraAssert(data, "Invalid data pointer"); NazaraAssert(size, "No data to load"); @@ -172,54 +180,53 @@ namespace Nz MemoryView stream(data, size); + UInt64 streamPos = stream.GetCursorPos(); bool found = false; - for (Loader& loader : Type::s_loaders) + for (auto& loaderPtr : m_loaders) { - StreamChecker checkFunc = std::get<1>(loader); - StreamLoader streamLoader = std::get<2>(loader); - MemoryLoader memoryLoader = std::get<4>(loader); + const Entry& loader = *loaderPtr; - Ternary recognized = Ternary_Unknown; - if (memoryLoader) + Ternary recognized = Ternary::Unknown; + if (loader.memoryLoader) { - if (checkFunc) + if (loader.streamChecker) { - stream.SetCursorPos(0); + stream.SetCursorPos(streamPos); - recognized = checkFunc(stream, parameters); - if (recognized == Ternary_False) + recognized = loader.streamChecker(stream, parameters); + if (recognized == Ternary::False) continue; else found = true; } else { - recognized = Ternary_Unknown; + recognized = Ternary::Unknown; found = true; } - ObjectRef resource = memoryLoader(data, size, parameters); + std::shared_ptr resource = loader.memoryLoader(data, size, parameters); if (resource) return resource; } else { - stream.SetCursorPos(0); + stream.SetCursorPos(streamPos); - recognized = checkFunc(stream, parameters); - if (recognized == Ternary_False) + recognized = loader.streamChecker(stream, parameters); + if (recognized == Ternary::False) continue; - else if (recognized == Ternary_True) + else if (recognized == Ternary::True) found = true; - stream.SetCursorPos(0); + stream.SetCursorPos(streamPos); - ObjectRef resource = streamLoader(stream, parameters); + std::shared_ptr resource = loader.streamLoader(stream, parameters); if (resource) return resource; } - if (recognized == Ternary_True) + if (recognized == Ternary::True) NazaraWarning("Loader failed"); } @@ -246,36 +253,35 @@ namespace Nz * \remark Produces a NazaraError if all loaders failed or no loader was found */ template - ObjectRef ResourceLoader::LoadFromStream(Stream& stream, const Parameters& parameters) + std::shared_ptr ResourceLoader::LoadFromStream(Stream& stream, const Parameters& parameters) const { NazaraAssert(stream.GetCursorPos() < stream.GetSize(), "No data to load"); NazaraAssert(parameters.IsValid(), "Invalid parameters"); UInt64 streamPos = stream.GetCursorPos(); bool found = false; - for (Loader& loader : Type::s_loaders) + for (auto& loaderPtr : m_loaders) { - StreamChecker checkFunc = std::get<1>(loader); - StreamLoader streamLoader = std::get<2>(loader); + const Entry& loader = *loaderPtr; stream.SetCursorPos(streamPos); // Does the loader support these data ? - Ternary recognized = checkFunc(stream, parameters); - if (recognized == Ternary_False) + Ternary recognized = loader.streamChecker(stream, parameters); + if (recognized == Ternary::False) continue; - else if (recognized == Ternary_True) + else if (recognized == Ternary::True) found = true; // We move the stream to its old position stream.SetCursorPos(streamPos); // Load of the resource - ObjectRef resource = streamLoader(stream, parameters); + std::shared_ptr resource = loader.streamLoader(stream, parameters); if (resource) return resource; - if (recognized == Ternary_True) + if (recognized == Ternary::True) NazaraWarning("Loader failed"); } @@ -288,36 +294,36 @@ namespace Nz } /*! - * \brief Registers the loader + * \brief Registers a loader + * \return A pointer to the registered Entry which can be unsed to unregister it later * - * \param extensionGetter A function to test whether the extension (as a string) is supported by this loader - * \param checkFunc A function to check the stream with the parser - * \param streamLoader A function to load the data from a stream in the resource - * \param fileLoader Optional function to load the data from a file in the resource - * \param memoryLoader Optional function to load the data from a raw memory in the resource + * \param loader A collection of loader callbacks that will be registered + * + * \see UnregisterLoader */ template - void ResourceLoader::RegisterLoader(ExtensionGetter extensionGetter, StreamChecker checkFunc, StreamLoader streamLoader, FileLoader fileLoader, MemoryLoader memoryLoader) + auto ResourceLoader::RegisterLoader(Entry loader) -> const Entry* { - NazaraAssert(checkFunc || !streamLoader, "StreamLoader present without StreamChecker"); - NazaraAssert(fileLoader || memoryLoader || streamLoader, "A loader function is mandatory"); + NazaraAssert(loader.streamChecker || !loader.streamLoader, "StreamLoader present without StreamChecker"); + NazaraAssert(loader.fileLoader || loader.memoryLoader || loader.streamLoader, "A loader function is mandatory"); - Type::s_loaders.push_front(std::make_tuple(extensionGetter, checkFunc, streamLoader, fileLoader, memoryLoader)); + auto it = m_loaders.emplace(m_loaders.begin(), std::make_unique(std::move(loader))); + return it->get(); } /*! - * \brief Unregisters the loader + * \brief Unregisters a loader * - * \param extensionGetter A function to test whether the extension (as a string) is supported by this loader - * \param checkFunc A function to check the stream with the parser - * \param streamLoader A function to load the data from a stream in the resource - * \param fileLoader Optional function to load the data from a file in the resource - * \param memoryLoader Optional function to load the data from a raw memory in the resource + * \param loader A pointer to a loader returned by RegisterLoad + * + * \see RegisterLoader */ template - void ResourceLoader::UnregisterLoader(ExtensionGetter extensionGetter, StreamChecker checkFunc, StreamLoader streamLoader, FileLoader fileLoader, MemoryLoader memoryLoader) + void ResourceLoader::UnregisterLoader(const Entry* loader) { - Type::s_loaders.remove(std::make_tuple(extensionGetter, checkFunc, streamLoader, fileLoader, memoryLoader)); + auto it = std::find_if(m_loaders.begin(), m_loaders.end(), [&](const std::unique_ptr& loaderPtr) { return loaderPtr.get() == loader; }); + if (it != m_loaders.end()) + m_loaders.erase(it); } } diff --git a/include/Nazara/Core/ResourceManager.hpp b/include/Nazara/Core/ResourceManager.hpp index f3a388c03..d61f183f6 100644 --- a/include/Nazara/Core/ResourceManager.hpp +++ b/include/Nazara/Core/ResourceManager.hpp @@ -7,9 +7,9 @@ #ifndef NAZARA_RESOURCEMANAGER_HPP #define NAZARA_RESOURCEMANAGER_HPP -#include -#include +#include #include +#include #include namespace Nz @@ -17,26 +17,27 @@ namespace Nz template class ResourceManager { - friend Type; - public: - ResourceManager() = delete; - ~ResourceManager() = delete; + using Loader = ResourceLoader; - static void Clear(); + ResourceManager(Loader& loader); + explicit ResourceManager(const ResourceManager&) = default; + ResourceManager(ResourceManager&&) noexcept = default; + ~ResourceManager() = default; - static ObjectRef Get(const std::filesystem::path& filePath); - static const Parameters& GetDefaultParameters(); + void Clear(); - static void Purge(); - static void Register(const std::filesystem::path& filePath, ObjectRef resource); - static void SetDefaultParameters(const Parameters& params); - static void Unregister(const std::filesystem::path& filePath); + std::shared_ptr Get(const std::filesystem::path& filePath); + const Parameters& GetDefaultParameters(); + + void Register(const std::filesystem::path& filePath, std::shared_ptr resource); + void SetDefaultParameters(Parameters params); + void Unregister(const std::filesystem::path& filePath); + + ResourceManager& operator=(const ResourceManager&) = delete; + ResourceManager& operator=(ResourceManager&&) = delete; private: - static bool Initialize(); - static void Uninitialize(); - // https://stackoverflow.com/questions/51065244/is-there-no-standard-hash-for-stdfilesystempath struct PathHash { @@ -46,8 +47,9 @@ namespace Nz } }; - using ManagerMap = std::unordered_map, PathHash>; - using ManagerParams = Parameters; + std::unordered_map, PathHash> m_resources; + Loader& m_loader; + Parameters m_defaultParameters; }; } diff --git a/include/Nazara/Core/ResourceManager.inl b/include/Nazara/Core/ResourceManager.inl index 992b3e081..6e0c238d9 100644 --- a/include/Nazara/Core/ResourceManager.inl +++ b/include/Nazara/Core/ResourceManager.inl @@ -15,13 +15,23 @@ namespace Nz * \brief Core class that represents a resource manager */ + + /*! + * \brief Clears the content of the manager + */ + template + ResourceManager::ResourceManager(Loader& loader) : + m_loader(loader) + { + } + /*! * \brief Clears the content of the manager */ template void ResourceManager::Clear() { - Type::s_managerMap.clear(); + m_resources.clear(); } /*! @@ -31,22 +41,22 @@ namespace Nz * \param filePath Path to the asset that will be loaded */ template - ObjectRef ResourceManager::Get(const std::filesystem::path& filePath) + std::shared_ptr ResourceManager::Get(const std::filesystem::path& filePath) { std::filesystem::path absolutePath = std::filesystem::canonical(filePath); - auto it = Type::s_managerMap.find(absolutePath); - if (it == Type::s_managerMap.end()) + auto it = m_resources.find(absolutePath); + if (it == m_resources.end()) { - ObjectRef resource = Type::LoadFromFile(absolutePath, GetDefaultParameters()); + std::shared_ptr resource = m_loader.LoadFromFile(absolutePath, GetDefaultParameters()); if (!resource) { NazaraError("Failed to load resource from file: " + absolutePath.generic_u8string()); - return ObjectRef(); + return std::shared_ptr(); } NazaraDebug("Loaded resource from file " + absolutePath.generic_u8string()); - it = Type::s_managerMap.insert(std::make_pair(absolutePath, resource)).first; + it = m_resources.insert(std::make_pair(absolutePath, resource)).first; } return it->second; @@ -59,27 +69,7 @@ namespace Nz template const Parameters& ResourceManager::GetDefaultParameters() { - return Type::s_managerParameters; - } - - /*! - * \brief Purges the resource manager from every asset whose it is the only owner - */ - template - void ResourceManager::Purge() - { - auto it = Type::s_managerMap.begin(); - while (it != Type::s_managerMap.end()) - { - const ObjectRef& ref = it->second; - if (ref->GetReferenceCount() == 1) // Are we the only ones to own the resource ? - { - NazaraDebug("Purging resource from file " + ref->GetFilePath().generic_u8string()); - Type::s_managerMap.erase(it++); // Then we erase it - } - else - ++it; - } + return m_defaultParameters; } /*! @@ -89,11 +79,11 @@ namespace Nz * \param resource Object to associate with */ template - void ResourceManager::Register(const std::filesystem::path& filePath, ObjectRef resource) + void ResourceManager::Register(const std::filesystem::path& filePath, std::shared_ptr resource) { std::filesystem::path absolutePath = std::filesystem::canonical(filePath); - Type::s_managerMap[absolutePath] = resource; + m_resources[absolutePath] = resource; } /*! @@ -102,9 +92,9 @@ namespace Nz * \param params Default parameters for loading from file */ template - void ResourceManager::SetDefaultParameters(const Parameters& params) + void ResourceManager::SetDefaultParameters(Parameters params) { - Type::s_managerParameters = params; + m_defaultParameters = std::move(params); } /*! @@ -117,26 +107,7 @@ namespace Nz { std::filesystem::path absolutePath = std::filesystem::canonical(filePath); - Type::s_managerMap.erase(absolutePath); - } - - /*! - * \brief Initializes the resource manager - * \return true - */ - template - bool ResourceManager::Initialize() - { - return true; - } - - /*! - * \brief Uninitialize the resource manager - */ - template - void ResourceManager::Uninitialize() - { - Clear(); + m_resources.erase(absolutePath); } } diff --git a/include/Nazara/Core/ResourceSaver.hpp b/include/Nazara/Core/ResourceSaver.hpp index 4333106e9..a9cc4bcef 100644 --- a/include/Nazara/Core/ResourceSaver.hpp +++ b/include/Nazara/Core/ResourceSaver.hpp @@ -28,25 +28,38 @@ namespace Nz friend Type; public: - using ExtensionGetter = bool (*)(const std::string& extension); - using FormatQuerier = bool (*)(const std::string& format); - using FileSaver = bool (*)(const Type& resource, const std::filesystem::path& filePath, const Parameters& parameters); - using StreamSaver = bool (*)(const Type& resource, const std::string& format, Stream& stream, const Parameters& parameters); + struct Entry; + using FormatSupport = std::function; + using FileSaver = std::function; + using StreamSaver = std::function; - ResourceSaver() = delete; - ~ResourceSaver() = delete; + ResourceSaver() = default; + ResourceSaver(const ResourceSaver&) = delete; + ResourceSaver(ResourceSaver&&) noexcept = default; + ~ResourceSaver() = default; - static bool IsFormatSupported(const std::string& extension); + void Clear(); - static bool SaveToFile(const Type& resource, const std::filesystem::path& filePath, const Parameters& parameters = Parameters()); - static bool SaveToStream(const Type& resource, Stream& stream, const std::string& format, const Parameters& parameters = Parameters()); + bool IsExtensionSupported(const std::string_view& extension) const; - static void RegisterSaver(FormatQuerier formatQuerier, StreamSaver streamSaver, FileSaver fileSaver = nullptr); - static void UnregisterSaver(FormatQuerier formatQuerier, StreamSaver streamSaver, FileSaver fileSaver = nullptr); + bool SaveToFile(const Type& resource, const std::filesystem::path& filePath, const Parameters& parameters = Parameters()) const; + bool SaveToStream(const Type& resource, Stream& stream, const std::string& format, const Parameters& parameters = Parameters()) const; + + const Entry* RegisterSaver(Entry saver); + void UnregisterSaver(const Entry* saver); + + ResourceSaver& operator=(const ResourceSaver&) = delete; + ResourceSaver& operator=(ResourceSaver&&) noexcept = default; + + struct Entry + { + FormatSupport formatSupport; + FileSaver fileSaver; + StreamSaver streamSaver; + }; private: - using Saver = std::tuple; - using SaverList = std::list; + std::vector> m_savers; }; } diff --git a/include/Nazara/Core/ResourceSaver.inl b/include/Nazara/Core/ResourceSaver.inl index 7686ce4d9..6cf4a7955 100644 --- a/include/Nazara/Core/ResourceSaver.inl +++ b/include/Nazara/Core/ResourceSaver.inl @@ -18,6 +18,15 @@ namespace Nz * \brief Core class that represents a list of saver functions for a specific resource type */ + /*! + * \brief Unregister every saver registered + */ + template + void ResourceSaver::Clear() + { + m_savers.clear(); + } + /*! * \brief Checks whether the extension of the file is supported * \return true if supported @@ -25,13 +34,12 @@ namespace Nz * \param extension Extension of the file */ template - bool ResourceSaver::IsFormatSupported(const std::string& extension) + bool ResourceSaver::IsExtensionSupported(const std::string_view& extension) const { - for (Saver& saver : Type::s_savers) + for (const auto& saverPtr : m_savers) { - ExtensionGetter isExtensionSupported = std::get<0>(saver); - - if (isExtensionSupported && isExtensionSupported(extension)) + const Entry& saver = *saverPtr; + if (saver.formatSupport(extension)) return true; } @@ -52,45 +60,42 @@ namespace Nz * \see SaveToStream */ template - bool ResourceSaver::SaveToFile(const Type& resource, const std::filesystem::path& filePath, const Parameters& parameters) + bool ResourceSaver::SaveToFile(const Type& resource, const std::filesystem::path& filePath, const Parameters& parameters) const { NazaraAssert(parameters.IsValid(), "Invalid parameters"); - std::string ext = ToLower(filePath.extension().generic_u8string()); - if (ext.empty()) + std::string extension = ToLower(filePath.extension().generic_u8string()); + if (extension.empty()) { NazaraError("Failed to get file extension from \"" + filePath.generic_u8string() + '"'); return false; } - File file(filePath.generic_u8string()); // Opened only is required - bool found = false; - for (Saver& saver : Type::s_savers) + for (const auto& saverPtr : m_savers) { - FormatQuerier formatQuerier = std::get<0>(saver); - if (!formatQuerier || !formatQuerier(ext)) + const Entry& saver = *saverPtr; + if (!saver.formatSupport(extension)) continue; found = true; - StreamSaver streamSeaver = std::get<1>(saver); - FileSaver fileSaver = std::get<2>(saver); - - if (fileSaver) + if (saver.fileSaver) { - if (fileSaver(resource, filePath, parameters)) + if (saver.fileSaver(resource, filePath, parameters)) return true; } else { - if (!file.Open(OpenMode_WriteOnly | OpenMode_Truncate)) + File file(filePath.generic_u8string()); + + if (!file.Open(OpenMode::WriteOnly | OpenMode::Truncate)) { NazaraError("Failed to save to file: unable to open \"" + filePath.generic_u8string() + "\" in write mode"); return false; } - if (streamSeaver(resource, ext, file, parameters)) + if (saver.streamSaver(resource, extension, file, parameters)) return true; } @@ -100,7 +105,7 @@ namespace Nz if (found) NazaraError("Failed to save resource: all savers failed"); else - NazaraError("Failed to save resource: no saver found for extension \"" + ext + '"'); + NazaraError("Failed to save resource: no saver found for extension \"" + extension + '"'); return false; } @@ -117,28 +122,26 @@ namespace Nz * \see SaveToFile */ template - bool ResourceSaver::SaveToStream(const Type& resource, Stream& stream, const std::string& format, const Parameters& parameters) + bool ResourceSaver::SaveToStream(const Type& resource, Stream& stream, const std::string& format, const Parameters& parameters) const { NazaraAssert(stream.IsWritable(), "Stream is not writable"); NazaraAssert(parameters.IsValid(), "Invalid parameters"); UInt64 streamPos = stream.GetCursorPos(); bool found = false; - for (Saver& saver : Type::s_savers) + for (const auto& saverPtr : m_savers) { - FormatQuerier formatQuerier = std::get<0>(saver); - if (!formatQuerier || !formatQuerier(format)) + const Entry& saver = *saverPtr; + if (!saver.formatSupport(format)) continue; found = true; - StreamSaver streamSeaver = std::get<1>(saver); - // We move the stream to its old position stream.SetCursorPos(streamPos); // Load of the resource - if (streamSeaver(resource, format, stream, parameters)) + if (saver.streamSaver(resource, format, stream, parameters)) return true; NazaraWarning("Saver failed"); @@ -154,36 +157,35 @@ namespace Nz /*! * \brief Registers a saver + * \return A pointer to the registered Entry which can be unsed to unregister it later * - * \param formatQuerier A function to test whether the format (as a string) is supported by this saver - * \param streamSaver A function which saves the resource to a stream - * \param fileSaver Optional function which saves the resource directly to a file given a file path + * \param loader A collection of saver callbacks that will be registered * - * \remark The fileSaver argument is only present for compatibility with external savers which cannot be interfaced with streams - * \remark At least one saver is required + * \see UnregisterLoader */ template - void ResourceSaver::RegisterSaver(FormatQuerier formatQuerier, StreamSaver streamSaver, FileSaver fileSaver) + auto ResourceSaver::RegisterSaver(Entry saver) -> const Entry* { - NazaraAssert(formatQuerier, "A format querier is mandaroty"); - NazaraAssert(streamSaver || fileSaver, "A saver function is mandaroty"); + NazaraAssert(saver.formatSupport, "A format support callback is mandatory"); + NazaraAssert(saver.streamSaver || saver.fileSaver, "A saver function is mandatory"); - Type::s_savers.push_front(std::make_tuple(formatQuerier, streamSaver, fileSaver)); + auto it = m_savers.emplace(m_savers.begin(), std::make_unique(std::move(saver))); + return it->get(); } /*! * \brief Unregisters a saver * - * \param formatQuerier A function to test whether the format (as a string) is supported by this saver - * \param streamSaver A function which saves the resource to a stream - * \param fileSaver A function function which saves the resource directly to a file given a file path + * \param saver A pointer to a loader returned by RegisterSaver * - * \remark The saver will only be unregistered if the function pointers are exactly the same + * \see RegisterSaver */ template - void ResourceSaver::UnregisterSaver(FormatQuerier formatQuerier, StreamSaver streamSaver, FileSaver fileSaver) + void ResourceSaver::UnregisterSaver(const Entry* saver) { - Type::s_savers.remove(std::make_tuple(formatQuerier, streamSaver, fileSaver)); + auto it = std::find_if(m_savers.begin(), m_savers.end(), [&](const std::unique_ptr& saverPtr) { return saverPtr.get() == saver; }); + if (it != m_savers.end()) + m_savers.erase(it); } } diff --git a/include/Nazara/Core/SerializationContext.hpp b/include/Nazara/Core/SerializationContext.hpp index 9cd64f2fd..0d715cd6a 100644 --- a/include/Nazara/Core/SerializationContext.hpp +++ b/include/Nazara/Core/SerializationContext.hpp @@ -20,7 +20,7 @@ namespace Nz struct NAZARA_CORE_API SerializationContext { MovablePtr stream; - Endianness endianness = Endianness_BigEndian; //< Default to Big Endian encoding + Endianness endianness = Endianness::BigEndian; //< Default to Big Endian encoding UInt8 readBitPos = 8; //< 8 means no bit is currently read UInt8 readByte; //< Undefined value, will be initialized at the first bit read UInt8 writeBitPos = 8; //< 8 means no bit is currently wrote diff --git a/include/Nazara/Core/Stream.hpp b/include/Nazara/Core/Stream.hpp index cd21c5f12..6813e2f20 100644 --- a/include/Nazara/Core/Stream.hpp +++ b/include/Nazara/Core/Stream.hpp @@ -56,7 +56,7 @@ namespace Nz Stream& operator=(Stream&&) noexcept = default; protected: - inline Stream(StreamOptionFlags streamOptions = StreamOption_None, OpenModeFlags openMode = OpenMode_NotOpen); + inline Stream(StreamOptionFlags streamOptions = StreamOption::None, OpenModeFlags openMode = OpenMode::NotOpen); virtual void FlushStream() = 0; virtual std::size_t ReadBlock(void* buffer, std::size_t size) = 0; diff --git a/include/Nazara/Core/Stream.inl b/include/Nazara/Core/Stream.inl index 0c014919d..c55d6ed3b 100644 --- a/include/Nazara/Core/Stream.inl +++ b/include/Nazara/Core/Stream.inl @@ -29,9 +29,9 @@ namespace Nz inline void Stream::EnableTextMode(bool textMode) { if (textMode) - m_streamOptions |= StreamOption_Text; + m_streamOptions |= StreamOption::Text; else - m_streamOptions &= ~StreamOption_Text; + m_streamOptions &= ~StreamOption::Text; } /*! @@ -74,7 +74,7 @@ namespace Nz inline bool Stream::IsReadable() const { - return (m_openMode & OpenMode_ReadOnly) != 0; + return (m_openMode & OpenMode::ReadOnly) != 0; } /*! @@ -84,7 +84,7 @@ namespace Nz inline bool Stream::IsSequential() const { - return (m_streamOptions & StreamOption_Sequential) != 0; + return (m_streamOptions & StreamOption::Sequential) != 0; } /*! @@ -94,7 +94,7 @@ namespace Nz inline bool Stream::IsTextModeEnabled() const { - return (m_streamOptions & StreamOption_Text) != 0; + return (m_streamOptions & StreamOption::Text) != 0; } /*! @@ -104,7 +104,7 @@ namespace Nz inline bool Stream::IsWritable() const { - return (m_openMode & OpenMode_WriteOnly) != 0; + return (m_openMode & OpenMode::WriteOnly) != 0; } /*! diff --git a/include/Nazara/Graphics.hpp b/include/Nazara/Graphics.hpp index dfdcd7991..f2ae8975c 100644 --- a/include/Nazara/Graphics.hpp +++ b/include/Nazara/Graphics.hpp @@ -29,8 +29,25 @@ #ifndef NAZARA_GLOBAL_GRAPHICS_HPP #define NAZARA_GLOBAL_GRAPHICS_HPP +#include +#include #include +#include #include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #endif // NAZARA_GLOBAL_GRAPHICS_HPP diff --git a/include/Nazara/Graphics/BakedFrameGraph.hpp b/include/Nazara/Graphics/BakedFrameGraph.hpp new file mode 100644 index 000000000..d3c609f56 --- /dev/null +++ b/include/Nazara/Graphics/BakedFrameGraph.hpp @@ -0,0 +1,99 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_BAKEDFRAMEGRAPH_HPP +#define NAZARA_BAKEDFRAMEGRAPH_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class RenderFrame; + + class NAZARA_GRAPHICS_API BakedFrameGraph + { + friend class FrameGraph; + + public: + BakedFrameGraph(const BakedFrameGraph&) = delete; + BakedFrameGraph(BakedFrameGraph&&) noexcept = default; + ~BakedFrameGraph() = default; + + void Execute(RenderFrame& renderFrame); + + const std::shared_ptr& GetAttachmentTexture(std::size_t attachmentIndex) const; + const std::shared_ptr& GetRenderPass(std::size_t passIndex) const; + + void Resize(unsigned int width, unsigned int height); + + BakedFrameGraph& operator=(const BakedFrameGraph&) = delete; + BakedFrameGraph& operator=(BakedFrameGraph&&) noexcept = default; + + private: + struct PassData; + struct TextureData; + using AttachmentIdToTextureId = std::unordered_map; + using PassIdToPhysicalPassIndex = std::unordered_map; + + BakedFrameGraph(std::vector passes, std::vector textures, AttachmentIdToTextureId attachmentIdToTextureMapping, PassIdToPhysicalPassIndex passIdToPhysicalPassMapping); + + struct TextureTransition + { + std::size_t textureId; + MemoryAccessFlags dstAccessMask; + MemoryAccessFlags srcAccessMask; + PipelineStageFlags dstStageMask; + PipelineStageFlags srcStageMask; + TextureLayout newLayout; + TextureLayout oldLayout; + }; + + struct SubpassData + { + FramePass::CommandCallback commandCallback; + }; + + struct PassData + { + CommandBufferPtr commandBuffer; + std::shared_ptr framebuffer; + std::shared_ptr renderPass; + std::string name; + std::vector outputTextureIndices; + std::vector subpasses; + std::vector transitions; + FramePass::ExecutionCallback executionCallback; + Recti renderRect; + }; + + struct TextureData + { + std::shared_ptr texture; + PixelFormat format; + TextureUsageFlags usage; + unsigned int width; + unsigned int height; + }; + + std::shared_ptr m_commandPool; + std::vector m_passes; + std::vector m_textures; + AttachmentIdToTextureId m_attachmentToTextureMapping; + PassIdToPhysicalPassIndex m_passIdToPhysicalPassMapping; + }; +} + +#include + +#endif diff --git a/include/Nazara/Graphics/BakedFrameGraph.inl b/include/Nazara/Graphics/BakedFrameGraph.inl new file mode 100644 index 000000000..7aaeece99 --- /dev/null +++ b/include/Nazara/Graphics/BakedFrameGraph.inl @@ -0,0 +1,12 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ +} + +#include diff --git a/include/Nazara/Graphics/BasicMaterial.hpp b/include/Nazara/Graphics/BasicMaterial.hpp new file mode 100644 index 000000000..8142e9cc0 --- /dev/null +++ b/include/Nazara/Graphics/BasicMaterial.hpp @@ -0,0 +1,89 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_BASIC_MATERIAL_HPP +#define NAZARA_BASIC_MATERIAL_HPP + +#include +#include + +namespace Nz +{ + class NAZARA_GRAPHICS_API BasicMaterial + { + friend class MaterialPipeline; + + public: + struct UniformOffsets; + + BasicMaterial(Material& material); + + inline void EnableAlphaTest(bool alphaTest); + + inline const std::shared_ptr& GetAlphaMap() const; + inline const TextureSamplerInfo& GetAlphaSampler() const; + float GetAlphaTestThreshold() const; + Color GetDiffuseColor() const; + inline const std::shared_ptr& GetDiffuseMap() const; + inline const TextureSamplerInfo& GetDiffuseSampler() const; + + inline bool HasAlphaMap() const; + inline bool HasAlphaTest() const; + inline bool HasAlphaTestThreshold() const; + inline bool HasDiffuseColor() const; + inline bool HasDiffuseMap() const; + + inline void SetAlphaMap(std::shared_ptr alphaMap); + inline void SetAlphaSampler(TextureSamplerInfo alphaSampler); + void SetAlphaTestThreshold(float alphaThreshold); + void SetDiffuseColor(const Color& diffuse); + inline void SetDiffuseMap(std::shared_ptr diffuseMap); + inline void SetDiffuseSampler(TextureSamplerInfo diffuseSampler); + + static inline const UniformOffsets& GetOffsets(); + static inline const std::shared_ptr& GetSettings(); + + struct UniformOffsets + { + std::size_t alphaThreshold; + std::size_t diffuseColor; + std::size_t totalSize; + }; + + private: + struct ConditionIndexes + { + std::size_t alphaTest; + std::size_t hasAlphaMap; + std::size_t hasDiffuseMap; + }; + + struct TextureIndexes + { + std::size_t alpha; + std::size_t diffuse; + }; + + static bool Initialize(); + static void Uninitialize(); + + Material& m_material; + std::size_t m_uniformBlockIndex; + ConditionIndexes m_conditionIndexes; + TextureIndexes m_textureIndexes; + UniformOffsets m_uniformOffsets; + + static std::shared_ptr s_materialSettings; + static std::size_t s_uniformBlockIndex; + static ConditionIndexes s_conditionIndexes; + static TextureIndexes s_textureIndexes; + static UniformOffsets s_uniformOffsets; + }; +} + +#include + +#endif // NAZARA_BASIC_MATERIAL_HPP diff --git a/include/Nazara/Graphics/BasicMaterial.inl b/include/Nazara/Graphics/BasicMaterial.inl new file mode 100644 index 000000000..4ed3ad8ca --- /dev/null +++ b/include/Nazara/Graphics/BasicMaterial.inl @@ -0,0 +1,124 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include + +namespace Nz +{ + /*! + * \brief Enable/Disable alpha test for this material + * + * When enabled, all objects using this material will be rendered using alpha testing, + * rejecting pixels if their alpha component is under a defined threshold. + * This allows some kind of transparency with a much cheaper cost as it doesn't prevent any optimization (as deferred rendering or batching). + * + * \param alphaTest Defines if this material will use alpha testing + * + * \remark Invalidates the pipeline + * + * \see IsAlphaTestEnabled + * \see SetAlphaThreshold + */ + inline void BasicMaterial::EnableAlphaTest(bool alphaTest) + { + NazaraAssert(HasAlphaTest(), "Material has no alpha test condition"); + m_material.EnableCondition(m_conditionIndexes.alphaTest, alphaTest); + } + + inline const std::shared_ptr& BasicMaterial::GetAlphaMap() const + { + NazaraAssert(HasAlphaMap(), "Material has no alpha texture slot"); + return m_material.GetTexture(m_textureIndexes.alpha); + } + + inline const TextureSamplerInfo& BasicMaterial::GetAlphaSampler() const + { + NazaraAssert(HasAlphaMap(), "Material has no alpha texture slot"); + return m_material.GetTextureSampler(m_textureIndexes.alpha); + } + + inline const std::shared_ptr& BasicMaterial::GetDiffuseMap() const + { + NazaraAssert(HasDiffuseMap(), "Material has no alpha texture slot"); + return m_material.GetTexture(m_textureIndexes.diffuse); + } + + inline const TextureSamplerInfo& BasicMaterial::GetDiffuseSampler() const + { + NazaraAssert(HasDiffuseMap(), "Material has no alpha texture slot"); + return m_material.GetTextureSampler(m_textureIndexes.diffuse); + } + + inline bool BasicMaterial::HasAlphaMap() const + { + return m_textureIndexes.alpha != MaterialSettings::InvalidIndex; + } + + inline bool BasicMaterial::HasAlphaTest() const + { + return m_conditionIndexes.alphaTest != MaterialSettings::InvalidIndex; + } + + inline bool BasicMaterial::HasAlphaTestThreshold() const + { + return m_uniformOffsets.alphaThreshold != MaterialSettings::InvalidIndex; + } + + inline bool BasicMaterial::HasDiffuseColor() const + { + return m_uniformOffsets.diffuseColor != MaterialSettings::InvalidIndex; + } + + inline bool BasicMaterial::HasDiffuseMap() const + { + return m_textureIndexes.diffuse != MaterialSettings::InvalidIndex; + } + + inline void BasicMaterial::SetAlphaMap(std::shared_ptr alphaMap) + { + NazaraAssert(HasAlphaMap(), "Material has no alpha map slot"); + bool hasAlphaMap = (alphaMap != nullptr); + m_material.SetTexture(m_textureIndexes.alpha, std::move(alphaMap)); + + if (m_conditionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex) + m_material.EnableCondition(m_conditionIndexes.hasAlphaMap, hasAlphaMap); + } + + inline void BasicMaterial::SetAlphaSampler(TextureSamplerInfo alphaSampler) + { + NazaraAssert(HasAlphaMap(), "Material has no alpha map slot"); + m_material.SetTextureSampler(m_textureIndexes.alpha, std::move(alphaSampler)); + } + + inline void BasicMaterial::SetDiffuseMap(std::shared_ptr diffuseMap) + { + NazaraAssert(HasDiffuseMap(), "Material has no diffuse map slot"); + bool hasDiffuseMap = (diffuseMap != nullptr); + m_material.SetTexture(m_textureIndexes.diffuse, std::move(diffuseMap)); + + if (m_conditionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex) + m_material.EnableCondition(m_conditionIndexes.hasDiffuseMap, hasDiffuseMap); + } + + inline void BasicMaterial::SetDiffuseSampler(TextureSamplerInfo diffuseSampler) + { + NazaraAssert(HasDiffuseMap(), "Material has no diffuse map slot"); + m_material.SetTextureSampler(m_textureIndexes.diffuse, std::move(diffuseSampler)); + } + + inline const std::shared_ptr& BasicMaterial::GetSettings() + { + return s_materialSettings; + } + + inline auto BasicMaterial::GetOffsets() -> const UniformOffsets& + { + return s_uniformOffsets; + } +} + +#include diff --git a/include/Nazara/Graphics/CullingList.hpp b/include/Nazara/Graphics/CullingList.hpp new file mode 100644 index 000000000..7eff97852 --- /dev/null +++ b/include/Nazara/Graphics/CullingList.hpp @@ -0,0 +1,215 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_CULLINGLIST_HPP +#define NAZARA_CULLINGLIST_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + template + class CullingList + { + public: + template class Entry; + class BoxEntry; + class NoTestEntry; + class SphereEntry; + class VolumeEntry; + + template friend class Entry; + friend BoxEntry; + friend NoTestEntry; + friend SphereEntry; + friend VolumeEntry; + + using ResultContainer = std::vector; + + CullingList() = default; + CullingList(const CullingList& renderable) = delete; + CullingList(CullingList&& renderable) = delete; + ~CullingList(); + + std::size_t Cull(const Frustumf& frustum, bool* forceInvalidation = nullptr); + + std::size_t FillWithAllEntries(bool* forceInvalidation = nullptr); + + const ResultContainer& GetFullyVisibleResults() const; + const ResultContainer& GetPartiallyVisibleResults() const; + + BoxEntry RegisterBoxTest(const T* renderable); + NoTestEntry RegisterNoTest(const T* renderable); + SphereEntry RegisterSphereTest(const T* renderable); + VolumeEntry RegisterVolumeTest(const T* renderable); + + CullingList& operator=(const CullingList& renderable) = delete; + CullingList& operator=(CullingList&& renderable) = delete; + + NazaraSignal(OnCullingListRelease, CullingList* /*cullingList*/); + + private: + inline void NotifyBoxUpdate(std::size_t index, const Boxf& boundingVolume); + inline void NotifyForceInvalidation(CullTest type, std::size_t index); + inline void NotifyMovement(CullTest type, std::size_t index, void* oldPtr, void* newPtr); + inline void NotifyRelease(CullTest type, std::size_t index); + inline void NotifySphereUpdate(std::size_t index, const Spheref& sphere); + inline void NotifyVolumeUpdate(std::size_t index, const BoundingVolumef& boundingVolume); + + struct BoxVisibilityEntry + { + Boxf box; + BoxEntry* entry; + const T* renderable; + bool forceInvalidation; + }; + + struct NoTestVisibilityEntry + { + NoTestEntry* entry; + const T* renderable; + bool forceInvalidation; + }; + + struct SphereVisibilityEntry + { + Spheref sphere; + SphereEntry* entry; + const T* renderable; + bool forceInvalidation; + }; + + struct VolumeVisibilityEntry + { + BoundingVolumef volume; + VolumeEntry* entry; + const T* renderable; + bool forceInvalidation; + }; + + std::vector m_boxTestList; + std::vector m_noTestList; + std::vector m_sphereTestList; + std::vector m_volumeTestList; + ResultContainer m_fullyVisibleResults; + ResultContainer m_partiallyVisibleResults; + }; + + template + template + class CullingList::Entry + { + public: + Entry(); + Entry(const Entry&) = delete; + Entry(Entry&& entry); + ~Entry(); + + void ForceInvalidation(); + + CullingList* GetParent() const; + + void UpdateIndex(std::size_t index); + + Entry& operator=(const Entry&) = delete; + Entry& operator=(Entry&& entry); + + protected: + Entry(CullingList* parent, std::size_t index); + + std::size_t m_index; + CullingList* m_parent; + }; + + template + class CullingList::BoxEntry : public CullingList::template Entry + { + friend CullingList; + + using ParentType = Entry; + + public: + BoxEntry(); + BoxEntry(BoxEntry&&) = default; + ~BoxEntry() = default; + + void UpdateBox(const Boxf& box); + + BoxEntry& operator=(BoxEntry&&) = default; + + private: + BoxEntry(CullingList* parent, std::size_t index); + }; + + template + class CullingList::NoTestEntry : public CullingList::template Entry + { + friend CullingList; + + using ParentType = Entry; + + public: + NoTestEntry(); + NoTestEntry(NoTestEntry&&) = default; + ~NoTestEntry() = default; + + NoTestEntry& operator=(NoTestEntry&&) = default; + + private: + NoTestEntry(CullingList* parent, std::size_t index); + }; + + template + class CullingList::SphereEntry : public CullingList::template Entry + { + friend CullingList; + + using ParentType = Entry; + + public: + SphereEntry(); + SphereEntry(SphereEntry&&) = default; + ~SphereEntry() = default; + + void UpdateSphere(const Spheref& sphere); + + SphereEntry& operator=(SphereEntry&&) = default; + + private: + SphereEntry(CullingList* parent, std::size_t index); + }; + + template + class CullingList::VolumeEntry : public CullingList::template Entry + { + friend CullingList; + + using ParentType = Entry; + + public: + VolumeEntry(); + VolumeEntry(VolumeEntry&&) = default; + ~VolumeEntry() = default; + + void UpdateVolume(const BoundingVolumef& sphere); + + VolumeEntry& operator=(VolumeEntry&&) = default; + + private: + VolumeEntry(CullingList* parent, std::size_t index); + }; +} + +#include + +#endif // NAZARA_CULLINGLIST_HPP diff --git a/include/Nazara/Graphics/CullingList.inl b/include/Nazara/Graphics/CullingList.inl new file mode 100644 index 000000000..aa94bc995 --- /dev/null +++ b/include/Nazara/Graphics/CullingList.inl @@ -0,0 +1,498 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + template + CullingList::~CullingList() + { + OnCullingListRelease(this); + } + + template + std::size_t CullingList::Cull(const Frustumf& frustum, bool* forceInvalidation) + { + m_fullyVisibleResults.clear(); + m_partiallyVisibleResults.clear(); + + bool forcedInvalidation = false; + + std::size_t fullyVisibleHash = 5U; + std::size_t partiallyVisibleHash = 5U; + + auto CombineHash = [](std::size_t currentHash, std::size_t newHash) + { + return currentHash * 23 + newHash; + }; + + for (BoxVisibilityEntry& entry : m_boxTestList) + { + switch (frustum.Intersect(entry.box)) + { + case IntersectionSide_Inside: + m_fullyVisibleResults.push_back(entry.renderable); + fullyVisibleHash = CombineHash(fullyVisibleHash, std::hash()(entry.renderable)); + + forcedInvalidation = forcedInvalidation | entry.forceInvalidation; + entry.forceInvalidation = false; + break; + + case IntersectionSide_Intersecting: + m_partiallyVisibleResults.push_back(entry.renderable); + partiallyVisibleHash = CombineHash(partiallyVisibleHash, std::hash()(entry.renderable)); + + forcedInvalidation = forcedInvalidation | entry.forceInvalidation; + entry.forceInvalidation = false; + break; + + case IntersectionSide_Outside: + break; + } + } + + for (NoTestVisibilityEntry& entry : m_noTestList) + { + m_fullyVisibleResults.push_back(entry.renderable); + CombineHash(fullyVisibleHash, std::hash()(entry.renderable)); + + if (entry.forceInvalidation) + { + forcedInvalidation = true; + entry.forceInvalidation = false; + } + } + + for (SphereVisibilityEntry& entry : m_sphereTestList) + { + switch (frustum.Intersect(entry.sphere)) + { + case IntersectionSide_Inside: + m_fullyVisibleResults.push_back(entry.renderable); + fullyVisibleHash = CombineHash(fullyVisibleHash, std::hash()(entry.renderable)); + + forcedInvalidation = forcedInvalidation | entry.forceInvalidation; + entry.forceInvalidation = false; + break; + + case IntersectionSide_Intersecting: + m_partiallyVisibleResults.push_back(entry.renderable); + partiallyVisibleHash = CombineHash(partiallyVisibleHash, std::hash()(entry.renderable)); + + forcedInvalidation = forcedInvalidation | entry.forceInvalidation; + entry.forceInvalidation = false; + break; + + case IntersectionSide_Outside: + break; + } + } + + for (VolumeVisibilityEntry& entry : m_volumeTestList) + { + switch (frustum.Intersect(entry.volume)) + { + case IntersectionSide_Inside: + m_fullyVisibleResults.push_back(entry.renderable); + fullyVisibleHash = CombineHash(fullyVisibleHash, std::hash()(entry.renderable)); + + forcedInvalidation = forcedInvalidation | entry.forceInvalidation; + entry.forceInvalidation = false; + break; + + case IntersectionSide_Intersecting: + m_partiallyVisibleResults.push_back(entry.renderable); + partiallyVisibleHash = CombineHash(partiallyVisibleHash, std::hash()(entry.renderable)); + + forcedInvalidation = forcedInvalidation | entry.forceInvalidation; + entry.forceInvalidation = false; + break; + + case IntersectionSide_Outside: + break; + } + } + + if (forceInvalidation) + *forceInvalidation = forcedInvalidation; + + return 5 + partiallyVisibleHash * 17 + fullyVisibleHash; + } + + template + std::size_t CullingList::FillWithAllEntries(bool* forceInvalidation) + { + m_fullyVisibleResults.clear(); + m_partiallyVisibleResults.clear(); + + bool forcedInvalidation = false; + + std::size_t visibleHash = 5U; + + auto FillWithList = [&](auto& testList) + { + for (auto& entry : testList) + { + m_fullyVisibleResults.push_back(entry.renderable); + visibleHash = visibleHash * 23 + std::hash()(entry.renderable); + + forcedInvalidation = forcedInvalidation | entry.forceInvalidation; + entry.forceInvalidation = false; + } + }; + + FillWithList(m_boxTestList); + FillWithList(m_noTestList); + FillWithList(m_sphereTestList); + FillWithList(m_volumeTestList); + + if (forceInvalidation) + *forceInvalidation = forcedInvalidation; + + return visibleHash; + } + + template + auto CullingList::GetFullyVisibleResults() const -> const ResultContainer& + { + return m_fullyVisibleResults; + } + + template + auto CullingList::GetPartiallyVisibleResults() const -> const ResultContainer& + { + return m_partiallyVisibleResults; + } + + template + auto CullingList::RegisterBoxTest(const T* renderable) -> BoxEntry + { + BoxEntry newEntry(this, m_boxTestList.size()); + m_boxTestList.emplace_back(BoxVisibilityEntry{ Nz::Boxf(), &newEntry, renderable, false }); //< Address of entry will be updated when moving + + return newEntry; + } + + template + auto CullingList::RegisterNoTest(const T* renderable) -> NoTestEntry + { + NoTestEntry newEntry(this, m_volumeTestList.size()); + m_noTestList.emplace_back(NoTestVisibilityEntry{&newEntry, renderable, false}); //< Address of entry will be updated when moving + + return newEntry; + } + + template + auto CullingList::RegisterSphereTest(const T* renderable) -> SphereEntry + { + SphereEntry newEntry(this, m_sphereTestList.size()); + m_sphereTestList.emplace_back(SphereVisibilityEntry{Nz::Spheref(), &newEntry, renderable, false}); //< Address of entry will be updated when moving + + return newEntry; + } + + template + auto CullingList::RegisterVolumeTest(const T* renderable) -> VolumeEntry + { + VolumeEntry newEntry(this, m_volumeTestList.size()); + m_volumeTestList.emplace_back(VolumeVisibilityEntry{Nz::BoundingVolumef(), &newEntry, renderable, false}); //< Address of entry will be updated when moving + + return newEntry; + } + + template + inline void CullingList::NotifyBoxUpdate(std::size_t index, const Boxf& box) + { + m_boxTestList[index].box = box; + } + + template + void CullingList::NotifyForceInvalidation(CullTest type, std::size_t index) + { + switch (type) + { + case CullTest::Box: + { + m_boxTestList[index].forceInvalidation = true; + break; + } + + case CullTest::NoTest: + { + m_noTestList[index].forceInvalidation = true; + break; + } + + case CullTest::Sphere: + { + m_sphereTestList[index].forceInvalidation = true; + break; + } + + case CullTest::Volume: + { + m_volumeTestList[index].forceInvalidation = true; + break; + } + + default: + NazaraInternalError("Unhandled culltype"); + break; + } + } + + template + void CullingList::NotifyMovement(CullTest type, std::size_t index, void* oldPtr, void* newPtr) + { + NazaraUnused(oldPtr); + + switch (type) + { + case CullTest::Box: + { + BoxVisibilityEntry& entry = m_boxTestList[index]; + NazaraAssert(entry.entry == oldPtr, "Invalid box entry"); + + entry.entry = static_cast(newPtr); + break; + } + + case CullTest::NoTest: + { + NoTestVisibilityEntry& entry = m_noTestList[index]; + NazaraAssert(entry.entry == oldPtr, "Invalid entry"); + + entry.entry = static_cast(newPtr); + break; + } + + case CullTest::Sphere: + { + SphereVisibilityEntry& entry = m_sphereTestList[index]; + NazaraAssert(entry.entry == oldPtr, "Invalid sphere entry"); + + entry.entry = static_cast(newPtr); + break; + } + + case CullTest::Volume: + { + VolumeVisibilityEntry& entry = m_volumeTestList[index]; + NazaraAssert(entry.entry == oldPtr, "Invalid volume entry"); + + entry.entry = static_cast(newPtr); + break; + } + + default: + NazaraInternalError("Unhandled culltype"); + break; + } + } + + template + void CullingList::NotifyRelease(CullTest type, std::size_t index) + { + switch (type) + { + case CullTest::Box: + { + m_boxTestList[index] = std::move(m_boxTestList.back()); + m_boxTestList[index].entry->UpdateIndex(index); + m_boxTestList.pop_back(); + break; + } + + case CullTest::NoTest: + { + m_noTestList[index] = std::move(m_noTestList.back()); + m_noTestList[index].entry->UpdateIndex(index); + m_noTestList.pop_back(); + break; + } + + case CullTest::Sphere: + { + m_sphereTestList[index] = std::move(m_sphereTestList.back()); + m_sphereTestList[index].entry->UpdateIndex(index); + m_sphereTestList.pop_back(); + break; + } + + case CullTest::Volume: + { + m_volumeTestList[index] = std::move(m_volumeTestList.back()); + m_volumeTestList[index].entry->UpdateIndex(index); + m_volumeTestList.pop_back(); + break; + } + + default: + NazaraInternalError("Unhandled culltype"); + break; + } + } + + template + void CullingList::NotifySphereUpdate(std::size_t index, const Spheref& sphere) + { + m_sphereTestList[index].sphere = sphere; + } + + template + void CullingList::NotifyVolumeUpdate(std::size_t index, const BoundingVolumef& boundingVolume) + { + m_volumeTestList[index].volume = boundingVolume; + } + + ////////////////////////////////////////////////////////////////////////// + + template + template + CullingList::Entry::Entry() : + m_parent(nullptr) + { + } + + template + template + CullingList::Entry::Entry(CullingList* parent, std::size_t index) : + m_index(index), + m_parent(parent) + { + } + + template + template + CullingList::Entry::Entry(Entry&& entry) : + m_index(entry.m_index), + m_parent(entry.m_parent) + { + if (m_parent) + m_parent->NotifyMovement(Type, m_index, &entry, this); + + entry.m_parent = nullptr; + } + + template + template + CullingList::Entry::~Entry() + { + if (m_parent) + m_parent->NotifyRelease(Type, m_index); + } + + template + template + void CullingList::Entry::ForceInvalidation() + { + m_parent->NotifyForceInvalidation(Type, m_index); + } + + template + template + CullingList* CullingList::Entry::GetParent() const + { + return m_parent; + } + + template + template + void CullingList::Entry::UpdateIndex(std::size_t index) + { + m_index = index; + } + + template + template + typename CullingList::template Entry& CullingList::Entry::operator=(Entry&& entry) + { + m_index = entry.m_index; + m_parent = entry.m_parent; + if (m_parent) + m_parent->NotifyMovement(Type, m_index, &entry, this); + + entry.m_parent = nullptr; + + return *this; + } + + ////////////////////////////////////////////////////////////////////////// + + template + CullingList::BoxEntry::BoxEntry() : + ParentType() + { + } + + template + CullingList::BoxEntry::BoxEntry(CullingList* parent, std::size_t index) : + ParentType(parent, index) + { + } + + template + void CullingList::BoxEntry::UpdateBox(const Boxf& box) + { + this->m_parent->NotifyBoxUpdate(this->m_index, box); + } + + ////////////////////////////////////////////////////////////////////////// + + template + CullingList::NoTestEntry::NoTestEntry() : + ParentType() + { + } + + template + CullingList::NoTestEntry::NoTestEntry(CullingList* parent, std::size_t index) : + ParentType(parent, index) + { + } + + ////////////////////////////////////////////////////////////////////////// + + template + CullingList::SphereEntry::SphereEntry() : + ParentType() + { + } + + template + CullingList::SphereEntry::SphereEntry(CullingList* parent, std::size_t index) : + ParentType(parent, index) + { + } + + template + void CullingList::SphereEntry::UpdateSphere(const Spheref& sphere) + { + this->m_parent->NotifySphereUpdate(this->m_index, sphere); + } + + ////////////////////////////////////////////////////////////////////////// + + template + CullingList::VolumeEntry::VolumeEntry() : + ParentType() + { + } + + template + CullingList::VolumeEntry::VolumeEntry(CullingList* parent, std::size_t index) : + ParentType(parent, index) + { + } + + template + void CullingList::VolumeEntry::UpdateVolume(const BoundingVolumef& volume) + { + this->m_parent->NotifyVolumeUpdate(this->m_index, volume); + } +} + +#include diff --git a/include/Nazara/Graphics/Enums.hpp b/include/Nazara/Graphics/Enums.hpp index f847d5fe4..5c9a41952 100644 --- a/include/Nazara/Graphics/Enums.hpp +++ b/include/Nazara/Graphics/Enums.hpp @@ -9,6 +9,25 @@ namespace Nz { + enum class CullTest + { + Box, + NoTest, + Sphere, + Volume + }; + + enum class PredefinedShaderBinding + { + TexOverlay, + UboInstanceData, + UboLighData, + UboViewerData, + + Max = UboViewerData + }; + + constexpr std::size_t PredefinedShaderBindingCount = static_cast(PredefinedShaderBinding::Max) + 1; } #endif // NAZARA_ENUMS_GRAPHICS_HPP diff --git a/include/Nazara/Graphics/FrameGraph.hpp b/include/Nazara/Graphics/FrameGraph.hpp new file mode 100644 index 000000000..c90c8c81b --- /dev/null +++ b/include/Nazara/Graphics/FrameGraph.hpp @@ -0,0 +1,121 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_FRAMEGRAPH_HPP +#define NAZARA_FRAMEGRAPH_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_GRAPHICS_API FrameGraph + { + public: + FrameGraph() = default; + FrameGraph(const FrameGraph&) = delete; + FrameGraph(FrameGraph&&) noexcept = default; + ~FrameGraph() = default; + + inline std::size_t AddAttachment(FramePassAttachment attachment); + inline FramePass& AddPass(std::string name); + + BakedFrameGraph Bake(); + + inline void SetBackbufferOutput(std::size_t backbufferOutput); + + FrameGraph& operator=(const FrameGraph&) = delete; + FrameGraph& operator=(FrameGraph&&) noexcept = default; + + private: + struct PassBarriers; + + using BarrierList = std::vector; + using PassList = std::vector; + using AttachmentIdToPassMap = std::unordered_map; + using AttachmentIdToTextureId = std::unordered_map; + using PassIdToPhysicalPassIndex = std::unordered_map; + using TextureTransition = BakedFrameGraph::TextureTransition; + + struct Barrier + { + std::size_t textureId; + MemoryAccessFlags access; + PipelineStageFlags stages; + TextureLayout layout; + }; + + struct PassBarriers + { + std::vector invalidationBarriers; + std::vector flushBarriers; + }; + + struct PhysicalPassData + { + struct Subpass + { + std::size_t passIndex; + }; + + std::string name; + std::vector textureTransitions; + std::vector passes; + }; + + struct TextureData + { + PixelFormat format; + TextureUsageFlags usage; + unsigned int width; + unsigned int height; + }; + + struct WorkData + { + std::size_t backbufferResourceIndex; + std::vector> renderPasses; + std::vector physicalPasses; + std::vector textures; + AttachmentIdToPassMap attachmentReadList; + AttachmentIdToPassMap attachmentWriteList; + AttachmentIdToTextureId attachmentToTextures; + BarrierList barrierList; + PassList passList; + PassIdToPhysicalPassIndex passIdToPhysicalPassIndex; + }; + + void AssignPhysicalPasses(); + void AssignPhysicalTextures(); + void BuildBarriers(); + void BuildPhysicalBarriers(); + void BuildPhysicalPassDependencies(std::size_t colorAttachmentCount, bool hasDepthStencilAttachment, std::vector& renderPassAttachments, std::vector& subpasses, std::vector& dependencies); + void BuildPhysicalPasses(); + void BuildReadWriteList(); + void RemoveDuplicatePasses(); + void ReorderPasses(); + void TraverseGraph(std::size_t passIndex); + + std::optional m_backbufferOutput; + std::vector m_framePasses; + std::vector m_attachments; + WorkData m_pending; + }; +} + +#include + +#endif diff --git a/include/Nazara/Graphics/FrameGraph.inl b/include/Nazara/Graphics/FrameGraph.inl new file mode 100644 index 000000000..eed77970d --- /dev/null +++ b/include/Nazara/Graphics/FrameGraph.inl @@ -0,0 +1,31 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + inline std::size_t FrameGraph::AddAttachment(FramePassAttachment attachment) + { + std::size_t id = m_attachments.size(); + m_attachments.emplace_back(std::move(attachment)); + + return id; + } + + inline FramePass& FrameGraph::AddPass(std::string name) + { + std::size_t id = m_framePasses.size(); + return m_framePasses.emplace_back(*this, id, std::move(name)); + } + + inline void FrameGraph::SetBackbufferOutput(std::size_t backbufferOutput) + { + m_backbufferOutput = backbufferOutput; + } +} + +#include diff --git a/include/Nazara/Graphics/FramePass.hpp b/include/Nazara/Graphics/FramePass.hpp new file mode 100644 index 000000000..99eafd2d0 --- /dev/null +++ b/include/Nazara/Graphics/FramePass.hpp @@ -0,0 +1,103 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_FRAMEPASS_HPP +#define NAZARA_FRAMEPASS_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class CommandBufferBuilder; + class FrameGraph; + + enum class FramePassExecution + { + Execute, + Skip, + UpdateAndExecute + }; + + class NAZARA_GRAPHICS_API FramePass + { + public: + using CommandCallback = std::function; + using ExecutionCallback = std::function; + struct DepthStencilClear; + struct Input; + struct Output; + + inline FramePass(FrameGraph& owner, std::size_t passId, std::string name); + FramePass(const FramePass&) = delete; + FramePass(FramePass&&) noexcept = default; + ~FramePass() = default; + + inline std::size_t AddInput(std::size_t attachmentId); + inline std::size_t AddOutput(std::size_t attachmentId); + + inline const CommandCallback& GetCommandCallback() const; + inline const std::optional& GetDepthStencilClear() const; + inline std::size_t GetDepthStencilInput() const; + inline std::size_t GetDepthStencilOutput() const; + inline const ExecutionCallback& GetExecutionCallback() const; + inline const std::vector& GetInputs() const; + inline const std::string& GetName() const; + inline const std::vector& GetOutputs() const; + inline std::size_t GetPassId() const; + + inline void SetCommandCallback(CommandCallback callback); + inline void SetClearColor(std::size_t outputIndex, const std::optional& color); + inline void SetDepthStencilClear(float depth, UInt32 stencil); + inline void SetExecutionCallback(ExecutionCallback callback); + + inline void SetDepthStencilInput(std::size_t attachmentId); + inline void SetDepthStencilOutput(std::size_t attachmentId); + + FramePass& operator=(const FramePass&) = delete; + FramePass& operator=(FramePass&&) noexcept = default; + + static constexpr std::size_t InvalidAttachmentId = std::numeric_limits::max(); + + struct DepthStencilClear + { + float depth; + UInt32 stencil; + }; + + struct Input + { + std::size_t attachmentId; + }; + + struct Output + { + std::size_t attachmentId; + std::optional clearColor; + }; + + private: + std::optional m_depthStencilClear; + std::size_t m_depthStencilInput; + std::size_t m_depthStencilOutput; + std::size_t m_passId; + std::string m_name; + std::vector m_inputs; + std::vector m_outputs; + FrameGraph& m_owner; + CommandCallback m_commandCallback; + ExecutionCallback m_executionCallback; + }; +} + +#include + +#endif diff --git a/include/Nazara/Graphics/FramePass.inl b/include/Nazara/Graphics/FramePass.inl new file mode 100644 index 000000000..4fd92d2db --- /dev/null +++ b/include/Nazara/Graphics/FramePass.inl @@ -0,0 +1,121 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + inline FramePass::FramePass(FrameGraph& owner, std::size_t passId, std::string name) : + m_depthStencilInput(InvalidAttachmentId), + m_depthStencilOutput(InvalidAttachmentId), + m_passId(passId), + m_name(std::move(name)), + m_owner(owner) + { + } + + inline std::size_t FramePass::AddInput(std::size_t attachmentId) + { + assert(attachmentId != InvalidAttachmentId); + + std::size_t inputIndex = m_inputs.size(); + auto& input = m_inputs.emplace_back(); + input.attachmentId = attachmentId; + + return inputIndex; + } + + inline std::size_t FramePass::AddOutput(std::size_t attachmentId) + { + assert(attachmentId != InvalidAttachmentId); + + std::size_t outputIndex = m_outputs.size(); + auto& output = m_outputs.emplace_back(); + output.attachmentId = attachmentId; + + return outputIndex; + } + + inline auto FramePass::GetCommandCallback() const -> const CommandCallback& + { + return m_commandCallback; + } + + inline auto FramePass::GetDepthStencilClear() const -> const std::optional& + { + return m_depthStencilClear; + } + + inline std::size_t FramePass::GetDepthStencilInput() const + { + return m_depthStencilInput; + } + + inline std::size_t FramePass::GetDepthStencilOutput() const + { + return m_depthStencilOutput; + } + + inline auto FramePass::GetExecutionCallback() const -> const ExecutionCallback& + { + return m_executionCallback; + } + + inline auto FramePass::GetInputs() const -> const std::vector& + { + return m_inputs; + } + + inline const std::string& FramePass::GetName() const + { + return m_name; + } + + inline auto FramePass::GetOutputs() const -> const std::vector& + { + return m_outputs; + } + + inline std::size_t FramePass::GetPassId() const + { + return m_passId; + } + + inline void FramePass::SetCommandCallback(CommandCallback callback) + { + m_commandCallback = std::move(callback); + } + + inline void FramePass::SetClearColor(std::size_t outputIndex, const std::optional& color) + { + assert(outputIndex < m_outputs.size()); + m_outputs[outputIndex].clearColor = color; + } + + inline void FramePass::SetDepthStencilClear(float depth, UInt32 stencil) + { + auto& dsClear = m_depthStencilClear.emplace(); + dsClear.depth = depth; + dsClear.stencil = stencil; + } + + inline void FramePass::SetExecutionCallback(ExecutionCallback callback) + { + m_executionCallback = std::move(callback); + } + + inline void FramePass::SetDepthStencilInput(std::size_t attachmentId) + { + m_depthStencilInput = attachmentId; + } + + inline void FramePass::SetDepthStencilOutput(std::size_t attachmentId) + { + m_depthStencilOutput = attachmentId; + } +} + +#include diff --git a/include/Nazara/Graphics/FramePassAttachment.hpp b/include/Nazara/Graphics/FramePassAttachment.hpp new file mode 100644 index 000000000..f77afe314 --- /dev/null +++ b/include/Nazara/Graphics/FramePassAttachment.hpp @@ -0,0 +1,28 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_FRAMEPASSATTACHMENT_HPP +#define NAZARA_FRAMEPASSATTACHMENT_HPP + +#include +#include +#include +#include + +namespace Nz +{ + struct FramePassAttachment + { + std::string name; + PixelFormat format; + unsigned int width = 100'000; + unsigned int height = 100'000; + }; +} + +#include + +#endif diff --git a/include/Nazara/Graphics/FramePassAttachment.inl b/include/Nazara/Graphics/FramePassAttachment.inl new file mode 100644 index 000000000..bf79d528f --- /dev/null +++ b/include/Nazara/Graphics/FramePassAttachment.inl @@ -0,0 +1,13 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ +} + +#include diff --git a/include/Nazara/Graphics/GraphicalMesh.hpp b/include/Nazara/Graphics/GraphicalMesh.hpp new file mode 100644 index 000000000..aabb44d32 --- /dev/null +++ b/include/Nazara/Graphics/GraphicalMesh.hpp @@ -0,0 +1,50 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_GRAPHICALMESH_HPP +#define NAZARA_GRAPHICALMESH_HPP + +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_GRAPHICS_API GraphicalMesh + { + public: + GraphicalMesh(const Mesh& mesh); + GraphicalMesh(const GraphicalMesh&) = delete; + GraphicalMesh(GraphicalMesh&&) noexcept = default; + ~GraphicalMesh() = default; + + inline const std::shared_ptr& GetIndexBuffer(std::size_t subMesh) const; + inline std::size_t GetIndexCount(std::size_t subMesh) const; + inline const std::shared_ptr& GetVertexBuffer(std::size_t subMesh) const; + inline const std::shared_ptr& GetVertexDeclaration(std::size_t subMesh) const; + inline std::size_t GetSubMeshCount() const; + + GraphicalMesh& operator=(const GraphicalMesh&) = delete; + GraphicalMesh& operator=(GraphicalMesh&&) noexcept = default; + + private: + struct GraphicalSubMesh + { + std::shared_ptr indexBuffer; + std::shared_ptr vertexBuffer; + std::size_t indexCount; + std::shared_ptr vertexDeclaration; + }; + + std::vector m_subMeshes; + }; +} + +#include + +#endif // NAZARA_GRAPHICALMESH_HPP diff --git a/include/Nazara/Graphics/GraphicalMesh.inl b/include/Nazara/Graphics/GraphicalMesh.inl new file mode 100644 index 000000000..5e1f73dd1 --- /dev/null +++ b/include/Nazara/Graphics/GraphicalMesh.inl @@ -0,0 +1,41 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + inline const std::shared_ptr& GraphicalMesh::GetIndexBuffer(std::size_t subMesh) const + { + assert(subMesh < m_subMeshes.size()); + return m_subMeshes[subMesh].indexBuffer; + } + + inline std::size_t GraphicalMesh::GetIndexCount(std::size_t subMesh) const + { + assert(subMesh < m_subMeshes.size()); + return m_subMeshes[subMesh].indexCount; + } + + inline const std::shared_ptr& GraphicalMesh::GetVertexBuffer(std::size_t subMesh) const + { + assert(subMesh < m_subMeshes.size()); + return m_subMeshes[subMesh].vertexBuffer; + } + + inline const std::shared_ptr& GraphicalMesh::GetVertexDeclaration(std::size_t subMesh) const + { + assert(subMesh < m_subMeshes.size()); + return m_subMeshes[subMesh].vertexDeclaration; + } + + inline std::size_t GraphicalMesh::GetSubMeshCount() const + { + return m_subMeshes.size(); + } +} + +#include diff --git a/include/Nazara/Graphics/Graphics.hpp b/include/Nazara/Graphics/Graphics.hpp index 71f7f533a..ec2d57238 100644 --- a/include/Nazara/Graphics/Graphics.hpp +++ b/include/Nazara/Graphics/Graphics.hpp @@ -9,10 +9,16 @@ #include #include +#include #include +#include +#include namespace Nz { + class AbstractBuffer; + class RenderDevice; + class NAZARA_GRAPHICS_API Graphics : public ModuleBase { friend ModuleBase; @@ -20,14 +26,29 @@ namespace Nz public: using Dependencies = TypeList; - struct Config {}; + struct Config; - Graphics(Config /*config*/); + Graphics(Config config); ~Graphics(); + inline const std::shared_ptr& GetRenderDevice() const; + inline TextureSamplerCache& GetSamplerCache(); + inline const std::shared_ptr& GetViewerDataUBO(); + + struct Config + { + bool useDedicatedRenderDevice = true; + }; + private: + std::optional m_samplerCache; + std::shared_ptr m_viewerDataUBO; + std::shared_ptr m_renderDevice; + static Graphics* s_instance; }; } +#include + #endif diff --git a/include/Nazara/Graphics/Graphics.inl b/include/Nazara/Graphics/Graphics.inl new file mode 100644 index 000000000..3362436ee --- /dev/null +++ b/include/Nazara/Graphics/Graphics.inl @@ -0,0 +1,26 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + inline const std::shared_ptr& Graphics::GetRenderDevice() const + { + return m_renderDevice; + } + + inline TextureSamplerCache& Graphics::GetSamplerCache() + { + return *m_samplerCache; + } + + inline const std::shared_ptr& Graphics::GetViewerDataUBO() + { + return m_viewerDataUBO; + } +} + +#include diff --git a/include/Nazara/Graphics/Material.hpp b/include/Nazara/Graphics/Material.hpp new file mode 100644 index 000000000..af7f38612 --- /dev/null +++ b/include/Nazara/Graphics/Material.hpp @@ -0,0 +1,145 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_BASE_MATERIAL_HPP +#define NAZARA_BASE_MATERIAL_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class CommandBufferBuilder; + class UploadPool; + + class NAZARA_GRAPHICS_API Material : public Resource + { + public: + Material(std::shared_ptr settings); + inline ~Material(); + + inline void Configure(std::shared_ptr pipeline); + inline void Configure(const MaterialPipelineInfo& pipelineInfo); + + inline void EnableBlending(bool blending); + inline void EnableColorWrite(bool colorWrite); + inline void EnableCondition(std::size_t conditionIndex, bool enable); + inline void EnableDepthBuffer(bool depthBuffer); + inline void EnableDepthSorting(bool depthSorting); + inline void EnableDepthWrite(bool depthWrite); + inline void EnableFaceCulling(bool faceCulling); + inline void EnableReflectionMapping(bool reflection); + inline void EnableScissorTest(bool scissorTest); + inline void EnableShadowCasting(bool castShadows); + inline void EnableShadowReceive(bool receiveShadows); + inline void EnableStencilTest(bool stencilTest); + inline void EnableVertexColor(bool vertexColor); + + inline void EnsurePipelineUpdate() const; + + inline RendererComparison GetDepthCompareFunc() const; + inline BlendEquation GetBlendAlphaModeEquation() const; + inline BlendEquation GetBlendColorModeEquation() const; + inline BlendFunc GetBlendDstAlphaFunc() const; + inline BlendFunc GetBlendDstColorFunc() const; + inline BlendFunc GetBlendSrcAlphaFunc() const; + inline BlendFunc GetBlendSrcColorFunc() const; + inline FaceSide GetFaceCulling() const; + inline FaceFilling GetFaceFilling() const; + inline float GetLineWidth() const; + inline const std::shared_ptr& GetPipeline() const; + inline const MaterialPipelineInfo& GetPipelineInfo() const; + inline float GetPointSize() const; + inline const std::shared_ptr& GetSettings() const; + inline const std::shared_ptr& GetShader(ShaderStageType shaderStage) const; + inline const std::shared_ptr& GetTexture(std::size_t textureIndex) const; + inline const TextureSamplerInfo& GetTextureSampler(std::size_t textureIndex) const; + inline const std::shared_ptr& GetUniformBuffer(std::size_t bufferIndex) const; + inline std::vector& GetUniformBufferData(std::size_t bufferIndex); + inline const std::vector& GetUniformBufferConstData(std::size_t bufferIndex); + + inline bool HasTexture(std::size_t textureIndex) const; + inline bool HasVertexColor() const; + + inline bool IsBlendingEnabled() const; + inline bool IsColorWriteEnabled() const; + inline bool IsConditionEnabled(std::size_t conditionIndex) const; + inline bool IsDepthBufferEnabled() const; + inline bool IsDepthSortingEnabled() const; + inline bool IsDepthWriteEnabled() const; + inline bool IsFaceCullingEnabled() const; + inline bool IsReflectionMappingEnabled() const; + inline bool IsScissorTestEnabled() const; + inline bool IsStencilTestEnabled() const; + inline bool IsShadowCastingEnabled() const; + inline bool IsShadowReceiveEnabled() const; + + inline void SetDepthCompareFunc(RendererComparison depthFunc); + inline void SetBlendEquation(BlendEquation colorMode, BlendEquation alphaMode); + inline void SetBlendFunc(BlendFunc srcColor, BlendFunc dstColor, BlendFunc srcAlpha, BlendFunc dstAlpha); + inline void SetFaceCulling(FaceSide faceSide); + inline void SetFaceFilling(FaceFilling filling); + inline void SetLineWidth(float lineWidth); + inline void SetPointSize(float pointSize); + inline void SetTexture(std::size_t textureIndex, std::shared_ptr texture); + inline void SetTextureSampler(std::size_t textureIndex, TextureSamplerInfo samplerInfo); + inline void SetUniformBuffer(std::size_t bufferIndex, std::shared_ptr uniformBuffer); + + void UpdateBuffers(UploadPool& uploadPool, CommandBufferBuilder& builder); + void UpdateShaderBinding(ShaderBinding& shaderBinding) const; + + // Signals: + NazaraSignal(OnMaterialRelease, const Material* /*material*/); + + private: + inline void InvalidatePipeline(); + inline void InvalidateShaderBinding(); + inline void InvalidateTextureSampler(std::size_t textureIndex); + inline void UpdatePipeline() const; + + struct MaterialTexture + { + mutable std::shared_ptr sampler; + std::shared_ptr texture; + TextureSamplerInfo samplerInfo; + }; + + struct UniformBuffer + { + std::shared_ptr buffer; + std::vector data; + bool dataInvalidated = true; + }; + + std::shared_ptr m_settings; + std::vector m_textures; + std::vector m_uniformBuffers; + mutable std::shared_ptr m_pipeline; + UInt64 m_enabledConditions; + mutable MaterialPipelineInfo m_pipelineInfo; + mutable bool m_pipelineUpdated; + bool m_shadowCastingEnabled; + }; +} + +#include + +#endif // NAZARA_BASE_MATERIAL_HPP diff --git a/include/Nazara/Graphics/Material.inl b/include/Nazara/Graphics/Material.inl new file mode 100644 index 000000000..016e4830e --- /dev/null +++ b/include/Nazara/Graphics/Material.inl @@ -0,0 +1,759 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include + +namespace Nz +{ + /*! + * \brief Destructs the object and calls OnMaterialRelease + * + * \see OnMaterialRelease + */ + inline Material::~Material() + { + OnMaterialRelease(this); + } + + /*! + * \brief Reset material pipeline state + * + * Sets the material pipeline + * + * \remark pipeline must be valid + * + * \see Configure + */ + inline void Material::Configure(std::shared_ptr pipeline) + { + NazaraAssert(pipeline, "Invalid material pipeline"); + + m_pipeline = std::move(pipeline); + m_pipelineInfo = m_pipeline->GetInfo(); + m_pipelineUpdated = true; + } + + /*! + * \brief Reset material pipeline state + * + * Sets the material pipeline using pipeline info + * + * \remark pipeline must be valid + * + * \see Configure + */ + inline void Material::Configure(const MaterialPipelineInfo& pipelineInfo) + { + m_pipelineInfo = pipelineInfo; + + InvalidatePipeline(); + } + + /*! + * \brief Enable/Disable blending for this material + * + * When enabled, all objects using this material will be rendered using blending, obeying the dstBlend and srcBlend parameters + * This is useful with translucent objects, but will reduces performance as it prevents some optimizations (as deferred rendering) + * + * \param blending Defines if this material will use blending + * + * \remark Invalidates the pipeline + * + * \see IsBlendingEnabled + * \see SetDstBlend + * \see SetSrcBlend + */ + inline void Material::EnableBlending(bool blending) + { + m_pipelineInfo.blending = blending; + + InvalidatePipeline(); + } + + /*! + * \brief Enable/Disable color writing for this material + * + * \param colorWrite Defines if this material will use color writing + * + * \remark Invalidates the pipeline + * + * \see IsColorWritingEnabled + */ + inline void Material::EnableColorWrite(bool colorWrite) + { + m_pipelineInfo.colorWrite = colorWrite; + + InvalidatePipeline(); + } + + inline void Material::EnableCondition(std::size_t conditionIndex, bool enable) + { + if (TestBit(m_enabledConditions, conditionIndex) != enable) + { + m_enabledConditions = SetBit(m_enabledConditions, conditionIndex); + InvalidatePipeline(); + } + } + + /*! + * \brief Enable/Disable depth buffer for this material + * + * When enabled, all objects using this material will be rendered using a depth buffer, if the RenderTarget has one. + * This will enable Depth Test, preventing further fragments to render on top of closer ones. + * + * This parameter is required for depth writing. + * + * In order to enable depth writing without enabling depth test, set the depth comparison function to RendererComparison::Never + * + * \param depthBuffer Defines if this material will use depth buffer + * + * \remark Invalidates the pipeline + * + * \see EnableDepthWrite + * \see IsDepthBufferEnabled + * \see SetDepthFunc + */ + inline void Material::EnableDepthBuffer(bool depthBuffer) + { + m_pipelineInfo.depthBuffer = depthBuffer; + + InvalidatePipeline(); + } + + /*! + * \brief Enable/Disable depth sorting for this material + * + * When enabled, all objects using this material will be rendered far from near + * This is useful with translucent objects, but will reduces performance as it breaks batching + * + * \param depthSorting Defines if this material will use depth sorting + * + * \remark Depth sorting may not be perfect (may be object-sorting instead of triangle-sorting) + * \remark Invalidates the pipeline + * + * \see IsDepthSortingEnabled + */ + inline void Material::EnableDepthSorting(bool depthSorting) + { + m_pipelineInfo.depthSorting = depthSorting; + + InvalidatePipeline(); + } + + /*! + * \brief Enable/Disable depth writing for this material + * + * When enabled, and if depth buffer is enabled and present, all fragments generated with this material will write + * to the depth buffer if they pass depth test. + * + * This is usually disabled with translucent objects, as depth test is wanted to prevent them from rendering on top of opaque objects but + * not depth writing (which could make other translucent fragments to fail depth test) + * + * \param depthBuffer Defines if this material will use depth write + * + * \remark Invalidates the pipeline + * + * \see EnableDepthBuffer + * \see IsDepthWriteEnabled + */ + inline void Material::EnableDepthWrite(bool depthWrite) + { + m_pipelineInfo.depthWrite = depthWrite; + + InvalidatePipeline(); + } + + /*! + * \brief Enable/Disable face culling for this material + * + * When enabled, the material prevents front and/or back faces from rendering. + * This is commonly used as an optimization to prevent processing of hidden faces by the rendering device. + * + * Use SetFaceCulling to control which side will be eliminated. + * + * \param faceCulling Defines if this material will use face culling + * + * \remark Invalidates the pipeline + * + * \see IsFaceCullingEnabled + * \see SetFaceCulling + */ + inline void Material::EnableFaceCulling(bool faceCulling) + { + m_pipelineInfo.faceCulling = faceCulling; + + InvalidatePipeline(); + } + + /*! + * \brief Enable/Disable reflection mapping for this material + * + * When enabled, the material will render reflections from the object environment according to the reflection mode. + * Whether or not this is expensive depends of the reflection mode and size. + * + * Please note this is only a hint for the render technique, and reflections can be forcefully enabled or disabled depending on the material shader. + * + * Use SetReflectionMode and SetReflectionSize to control reflection quality. + * + * \param reflection Defines if this material should use reflection mapping + * + * \remark May invalidates the pipeline + * + * \see IsReflectionMappingEnabled + * \see SetReflectionMode + * \see SetReflectionSize + */ + inline void Material::EnableReflectionMapping(bool reflection) + { + m_pipelineInfo.reflectionMapping = reflection; + + InvalidatePipeline(); + } + + /*! + * \brief Enable/Disable scissor test for this material + * + * When enabled, the material prevents fragments out of the scissor box to be rendered. + * This can be useful with GUI, where widgets must not be rendered outside of their parent rendering area. + * + * \param scissorTest Defines if this material will use scissor test + * + * \remark Invalidates the pipeline + * + * \see IsScissorTestEnabled + */ + inline void Material::EnableScissorTest(bool scissorTest) + { + m_pipelineInfo.scissorTest = scissorTest; + + InvalidatePipeline(); + } + + /*! + * \brief Enable/Disable shadow casting for this material + * + * When enabled, all objects using this material will be allowed to cast shadows upon any objects using a material with shadow receiving enabled. + * The depth material replaces this one when rendering shadows. + * + * \param castShadows Defines if this material will be allowed to cast shadows + * + * \remark Does not invalidate the pipeline + * + * \see EnableShadowReceive + * \see IsShadowCastingEnabled + * \see SetDepthMaterial + */ + inline void Material::EnableShadowCasting(bool castShadows) + { + // Has no influence on pipeline + m_shadowCastingEnabled = castShadows; + } + + /*! + * \brief Enable/Disable shadow receiving for this material + * + * When enabled, all objects using this material will be allowed to be casted shadows upon themselves + * Disabling this can be helpful to prevent some rendering artifacts (especially with translucent objects) + * + * \param receiveShadows Defines if this material will be able to receive shadows + * + * \remark Invalidates the pipeline + * + * \see IsShadowReceiveEnabled + */ + inline void Material::EnableShadowReceive(bool receiveShadows) + { + m_pipelineInfo.shadowReceive = receiveShadows; + + InvalidatePipeline(); + } + + /*! + * \brief Enable/Disable stencil test for this material + * + * When enabled, all fragments must pass the stencil test to be rendered. + * + * \param scissorTest Defines if this material will use stencil test + * + * \remark Invalidates the pipeline + * + * \see IsStencilTestEnabled + */ + inline void Material::EnableStencilTest(bool stencilTest) + { + m_pipelineInfo.stencilTest = stencilTest; + + InvalidatePipeline(); + } + + /*! + * \brief Enable/Disable vertex coloring on this material + * + * This is a temporary option, until the new material pipeline system is ready, allowing to enable vertex coloring. + * This option only works with meshes using vertex colors. + * + * \param vertexColor Defines if this material will use vertex color or not + * + * \remark Invalidates the pipeline + * + * \see HasVertexColor + */ + inline void Material::EnableVertexColor(bool vertexColor) + { + m_pipelineInfo.hasVertexColor = vertexColor; + + InvalidatePipeline(); + } + + /*! + * \brief Ensures the pipeline gets updated + * + * When the pipeline gets invalidated, it's not updated until required (per example by calling GetPipeline). + * Using this function forces the pipeline update, making GetPipeline thread-safe as long as the pipeline does not get invalidated. + * + * \see GetPipeline + */ + inline void Material::EnsurePipelineUpdate() const + { + if (!m_pipelineUpdated) + UpdatePipeline(); + } + + /*! + * \brief Gets the function to compare depth + * + * \return Function comparing the depth of two materials + * + * \see EnableDepthTest + * \see SetAmbientColor + */ + inline RendererComparison Material::GetDepthCompareFunc() const + { + return m_pipelineInfo.depthCompare; + } + + inline BlendEquation Material::GetBlendAlphaModeEquation() const + { + return m_pipelineInfo.blend.modeAlpha; + } + + inline BlendEquation Material::GetBlendColorModeEquation() const + { + return m_pipelineInfo.blend.modeColor; + } + + inline BlendFunc Material::GetBlendDstAlphaFunc() const + { + return m_pipelineInfo.blend.dstAlpha; + } + + inline BlendFunc Material::GetBlendDstColorFunc() const + { + return m_pipelineInfo.blend.dstColor; + } + + inline BlendFunc Material::GetBlendSrcAlphaFunc() const + { + return m_pipelineInfo.blend.srcAlpha; + } + + inline BlendFunc Material::GetBlendSrcColorFunc() const + { + return m_pipelineInfo.blend.srcColor; + } + + /*! + * \brief Gets the face culling + * + * \return Current face culling side + * + * \see SetFaceCulling + */ + inline FaceSide Material::GetFaceCulling() const + { + return m_pipelineInfo.cullingSide; + } + + /*! + * \brief Gets the face filling + * \return Current face filling + */ + inline FaceFilling Material::GetFaceFilling() const + { + return m_pipelineInfo.faceFilling; + } + + /*! + * \brief Gets the line width of this material + * \return Line width + */ + inline float Material::GetLineWidth() const + { + return m_pipelineInfo.lineWidth; + } + + /*! + * \brief Gets the render states + * \return Constant reference to the render states + */ + inline const std::shared_ptr& Material::GetPipeline() const + { + EnsurePipelineUpdate(); + + return m_pipeline; + } + + /*! + * \brief Gets the pipeline informations + * \return Constant reference to the pipeline info + */ + inline const MaterialPipelineInfo& Material::GetPipelineInfo() const + { + return m_pipelineInfo; + } + + /*! + * \brief Gets the point size of this material + * \return Point size + */ + inline float Material::GetPointSize() const + { + return m_pipelineInfo.pointSize; + } + + inline const std::shared_ptr& Material::GetSettings() const + { + return m_settings; + } + + /*! + * \brief Gets the über-shader used by this material + * \return Constant pointer to the über-shader used + */ + inline const std::shared_ptr& Material::GetShader(ShaderStageType shaderStage) const + { + return m_pipelineInfo.shaders[UnderlyingCast(shaderStage)].uberShader; + } + + inline const std::shared_ptr& Material::GetTexture(std::size_t textureIndex) const + { + NazaraAssert(textureIndex < m_textures.size(), "Invalid texture index"); + return m_textures[textureIndex].texture; + } + + inline const TextureSamplerInfo& Material::GetTextureSampler(std::size_t textureIndex) const + { + NazaraAssert(textureIndex < m_textures.size(), "Invalid texture index"); + return m_textures[textureIndex].samplerInfo; + } + + inline const std::shared_ptr& Material::GetUniformBuffer(std::size_t bufferIndex) const + { + NazaraAssert(bufferIndex < m_uniformBuffers.size(), "Invalid uniform buffer index"); + return m_uniformBuffers[bufferIndex].buffer; + } + + inline std::vector& Material::GetUniformBufferData(std::size_t bufferIndex) + { + NazaraAssert(bufferIndex < m_uniformBuffers.size(), "Invalid uniform buffer index"); + UniformBuffer& uboEntry = m_uniformBuffers[bufferIndex]; + uboEntry.dataInvalidated = true; + return uboEntry.data; + } + + inline const std::vector& Material::GetUniformBufferConstData(std::size_t bufferIndex) + { + NazaraAssert(bufferIndex < m_uniformBuffers.size(), "Invalid uniform buffer index"); + return m_uniformBuffers[bufferIndex].data; + } + + inline bool Material::HasTexture(std::size_t textureIndex) const + { + return GetTexture(textureIndex) != nullptr; + } + + /*! + * \brief Checks whether this material uses vertex coloring + * \return true If it is the case + */ + inline bool Material::HasVertexColor() const + { + return m_pipelineInfo.hasVertexColor; + } + + /*! + * \brief Checks whether this material has blending enabled + * \return true If it is the case + */ + inline bool Material::IsBlendingEnabled() const + { + return m_pipelineInfo.blending; + } + + /*! + * \brief Checks whether this material has color write enabled + * \return true If it is the case + */ + inline bool Material::IsColorWriteEnabled() const + { + return m_pipelineInfo.colorWrite; + } + + inline bool Material::IsConditionEnabled(std::size_t conditionIndex) const + { + return TestBit(m_enabledConditions, conditionIndex); + } + + /*! + * \brief Checks whether this material has depth buffer enabled + * \return true If it is the case + */ + inline bool Material::IsDepthBufferEnabled() const + { + return m_pipelineInfo.depthBuffer; + } + + /*! + * \brief Checks whether this material has depth sorting enabled + * \return true If it is the case + */ + inline bool Material::IsDepthSortingEnabled() const + { + return m_pipelineInfo.depthSorting; + } + + /*! + * \brief Checks whether this material has depth writing enabled + * \return true If it is the case + */ + inline bool Material::IsDepthWriteEnabled() const + { + return m_pipelineInfo.depthWrite; + } + + /*! + * \brief Checks whether this material has face culling enabled + * \return true If it is the case + */ + inline bool Material::IsFaceCullingEnabled() const + { + return m_pipelineInfo.faceCulling; + } + + /*! + * \brief Checks whether this material has reflection mapping enabled + * \return true If it is the case + * + * \see EnableReflectionMapping + */ + inline bool Material::IsReflectionMappingEnabled() const + { + return m_pipelineInfo.reflectionMapping; + } + + /*! + * \brief Checks whether this material has scissor test enabled + * \return true If it is the case + */ + inline bool Material::IsScissorTestEnabled() const + { + return m_pipelineInfo.scissorTest; + } + + /*! + * \brief Checks whether this material has stencil test enabled + * \return true If it is the case + */ + inline bool Material::IsStencilTestEnabled() const + { + return m_pipelineInfo.stencilTest; + } + + /*! + * \brief Checks whether this material cast shadow + * \return true If it is the case + */ + inline bool Material::IsShadowCastingEnabled() const + { + return m_shadowCastingEnabled; + } + + /*! + * \brief Checks whether this material receive shadow + * \return true If it is the case + */ + inline bool Material::IsShadowReceiveEnabled() const + { + return m_pipelineInfo.shadowReceive; + } + + /*! + * \brief Sets the depth functor + * + * \param depthFunc + * + * \remark Invalidates the pipeline + */ + inline void Material::SetDepthCompareFunc(RendererComparison depthFunc) + { + m_pipelineInfo.depthCompare = depthFunc; + + InvalidatePipeline(); + } + + inline void Material::SetBlendEquation(BlendEquation colorMode, BlendEquation alphaMode) + { + m_pipelineInfo.blend.modeAlpha = alphaMode; + m_pipelineInfo.blend.modeColor = colorMode; + + InvalidatePipeline(); + } + + inline void Material::SetBlendFunc(BlendFunc srcColor, BlendFunc dstColor, BlendFunc srcAlpha, BlendFunc dstAlpha) + { + m_pipelineInfo.blend.dstAlpha = dstAlpha; + m_pipelineInfo.blend.dstColor = dstColor; + m_pipelineInfo.blend.srcAlpha = srcAlpha; + m_pipelineInfo.blend.srcColor = srcColor; + + InvalidatePipeline(); + } + + /*! + * \brief Sets the face culling + * + * \param faceSide Face to cull + * + * \remark Invalidates the pipeline + */ + inline void Material::SetFaceCulling(FaceSide faceSide) + { + m_pipelineInfo.cullingSide = faceSide; + + InvalidatePipeline(); + } + + /*! + * \brief Sets the face filling + * + * \param filling Face to fill + * + * \remark Invalidates the pipeline + */ + inline void Material::SetFaceFilling(FaceFilling filling) + { + m_pipelineInfo.faceFilling = filling; + + InvalidatePipeline(); + } + + /*! + * \brief Sets the line width for this material + * + * This parameter is used when rendering lines, to define the width (in pixels) the line will take on the framebuffer + * + * \param lineWidth Width of the line + * + * \remark Invalidates the pipeline + * + * \see GetLineWidth + */ + inline void Material::SetLineWidth(float lineWidth) + { + m_pipelineInfo.lineWidth = lineWidth; + + InvalidatePipeline(); + } + + /*! + * \brief Sets the point size for this material + * + * This parameter is used when rendering points, to define the size (in pixels) the point will take on the framebuffer + * + * \param pointSize Size of the point + * + * \remark Invalidates the pipeline + * + * \see GetPointSize + */ + inline void Material::SetPointSize(float pointSize) + { + m_pipelineInfo.pointSize = pointSize; + + InvalidatePipeline(); + } + + inline void Material::SetTexture(std::size_t textureIndex, std::shared_ptr texture) + { + NazaraAssert(textureIndex < m_textures.size(), "Invalid texture index"); + if (m_textures[textureIndex].texture != texture) + { + m_textures[textureIndex].texture = std::move(texture); + InvalidateShaderBinding(); + } + } + + inline void Material::SetTextureSampler(std::size_t textureIndex, TextureSamplerInfo samplerInfo) + { + NazaraAssert(textureIndex < m_textures.size(), "Invalid texture index"); + if (m_textures[textureIndex].samplerInfo != samplerInfo) + { + m_textures[textureIndex].samplerInfo = std::move(samplerInfo); + InvalidateTextureSampler(textureIndex); + } + } + + inline void Material::SetUniformBuffer(std::size_t bufferIndex, std::shared_ptr uniformBuffer) + { + NazaraAssert(bufferIndex < m_uniformBuffers.size(), "Invalid shared uniform buffer index"); + if (m_uniformBuffers[bufferIndex].buffer != uniformBuffer) + { + m_uniformBuffers[bufferIndex].buffer = std::move(uniformBuffer); + m_uniformBuffers[bufferIndex].dataInvalidated = true; + InvalidateShaderBinding(); + } + } + + inline void Material::InvalidatePipeline() + { + m_pipelineUpdated = false; + } + + inline void Material::InvalidateShaderBinding() + { + //TODO + } + + inline void Material::InvalidateTextureSampler(std::size_t textureIndex) + { + assert(textureIndex < m_textures.size()); + m_textures[textureIndex].sampler.reset(); + + InvalidateShaderBinding(); + } + + inline void Material::UpdatePipeline() const + { + for (auto& shader : m_pipelineInfo.shaders) + shader.enabledConditions = 0; + + const auto& conditions = m_settings->GetConditions(); + for (std::size_t conditionIndex = 0; conditionIndex < conditions.size(); ++conditionIndex) + { + if (TestBit(m_enabledConditions, conditionIndex)) + { + for (std::size_t shaderStage = 0; shaderStage < ShaderStageTypeCount; ++shaderStage) + m_pipelineInfo.shaders[shaderStage].enabledConditions |= conditions[conditionIndex].enabledConditions[shaderStage]; + } + } + + m_pipeline = MaterialPipeline::Get(m_pipelineInfo); + m_pipelineUpdated = true; + } +} + +#include diff --git a/include/Nazara/Graphics/MaterialPipeline.hpp b/include/Nazara/Graphics/MaterialPipeline.hpp new file mode 100644 index 000000000..951320269 --- /dev/null +++ b/include/Nazara/Graphics/MaterialPipeline.hpp @@ -0,0 +1,77 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_MATERIALPIPELINE_HPP +#define NAZARA_MATERIALPIPELINE_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class UberShader; + + struct MaterialPipelineInfo : RenderStates + { + struct ShaderStage + { + std::shared_ptr uberShader; + Nz::UInt64 enabledConditions = 0; + }; + + bool depthSorting = false; + bool hasVertexColor = false; + bool reflectionMapping = false; + bool shadowReceive = true; + + std::array shaders; + std::shared_ptr settings; + }; + + inline bool operator==(const MaterialPipelineInfo& lhs, const MaterialPipelineInfo& rhs); + inline bool operator!=(const MaterialPipelineInfo& lhs, const MaterialPipelineInfo& rhs); + + + class NAZARA_GRAPHICS_API MaterialPipeline + { + friend class Graphics; + + struct Token {}; + + public: + inline MaterialPipeline(const MaterialPipelineInfo& pipelineInfo, Token); + MaterialPipeline(const MaterialPipeline&) = delete; + MaterialPipeline(MaterialPipeline&&) = delete; + ~MaterialPipeline() = default; + + MaterialPipeline& operator=(const MaterialPipeline&) = delete; + MaterialPipeline& operator=(MaterialPipeline&&) = delete; + + inline const MaterialPipelineInfo& GetInfo() const; + const std::shared_ptr& GetRenderPipeline(const std::vector& vertexBuffers) const; + + static const std::shared_ptr& Get(const MaterialPipelineInfo& pipelineInfo); + + private: + static bool Initialize(); + static void Uninitialize(); + + mutable std::vector> m_renderPipelines; + MaterialPipelineInfo m_pipelineInfo; + + using PipelineCache = std::unordered_map>; + static PipelineCache s_pipelineCache; + }; +} + +#include + +#endif // NAZARA_MATERIALPIPELINE_HPP diff --git a/include/Nazara/Graphics/MaterialPipeline.inl b/include/Nazara/Graphics/MaterialPipeline.inl new file mode 100644 index 000000000..0131b7153 --- /dev/null +++ b/include/Nazara/Graphics/MaterialPipeline.inl @@ -0,0 +1,102 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + inline MaterialPipeline::MaterialPipeline(const MaterialPipelineInfo& pipelineInfo, Token) : + m_pipelineInfo(pipelineInfo) + { + } + + /*! + * \brief Retrieve a MaterialPipelineInfo object describing this pipeline + * + * \return Pipeline informations + */ + const MaterialPipelineInfo& MaterialPipeline::GetInfo() const + { + return m_pipelineInfo; + } + + bool operator==(const MaterialPipelineInfo& lhs, const MaterialPipelineInfo& rhs) + { + if (!operator==(static_cast(lhs), static_cast(rhs))) + return false; + + #define NazaraPipelineMember(field) if (lhs.field != rhs.field) return false + #define NazaraPipelineBoolMember NazaraPipelineMember + + NazaraPipelineBoolMember(depthSorting); + NazaraPipelineBoolMember(hasVertexColor); + NazaraPipelineBoolMember(reflectionMapping); + NazaraPipelineBoolMember(shadowReceive); + + NazaraPipelineMember(settings); + + for (std::size_t i = 0; i < lhs.shaders.size(); ++i) + { + if (lhs.shaders[i].enabledConditions != rhs.shaders[i].enabledConditions) + return false; + + if (lhs.shaders[i].uberShader != rhs.shaders[i].uberShader) + return false; + } + + #undef NazaraPipelineMember + #undef NazaraPipelineBoolMember + + return true; + } + + bool operator!=(const MaterialPipelineInfo& lhs, const MaterialPipelineInfo& rhs) + { + return !operator==(lhs, rhs); + } +} + +namespace std +{ + template<> + struct hash + { + size_t operator()(const Nz::MaterialPipelineInfo& pipelineInfo) const + { + hash parentHash; + + std::size_t seed = parentHash(pipelineInfo); + + Nz::UInt16 parameterHash = 0; + Nz::UInt16 parameterIndex = 0; + + #define NazaraPipelineMember(member) Nz::HashCombine(seed, pipelineInfo.member) + #define NazaraPipelineBoolMember(member) parameterHash |= ((pipelineInfo.member) ? 1U : 0U) << (parameterIndex++) + + NazaraPipelineBoolMember(depthSorting); + NazaraPipelineBoolMember(hasVertexColor); + NazaraPipelineBoolMember(reflectionMapping); + NazaraPipelineBoolMember(shadowReceive); + + NazaraPipelineMember(settings.get()); //< Hash pointer + + for (const auto& shader : pipelineInfo.shaders) + { + Nz::HashCombine(seed, shader.enabledConditions); + Nz::HashCombine(seed, shader.uberShader.get()); + } + + #undef NazaraPipelineMember + #undef NazaraPipelineBoolMember + + Nz::HashCombine(seed, parameterHash); + + return seed; + } + }; +} + +#include diff --git a/include/Nazara/Graphics/MaterialSettings.hpp b/include/Nazara/Graphics/MaterialSettings.hpp new file mode 100644 index 000000000..9ea0fa54c --- /dev/null +++ b/include/Nazara/Graphics/MaterialSettings.hpp @@ -0,0 +1,116 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_MATERIALSETTINGS_HPP +#define NAZARA_MATERIALSETTINGS_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class UberShader; + + class MaterialSettings + { + public: + using PredefinedBinding = std::array; + using Shaders = std::array, ShaderStageTypeCount>; + + struct Builder; + struct Condition; + struct SharedUniformBlock; + struct Texture; + struct UniformBlock; + + inline MaterialSettings(); + inline MaterialSettings(Builder builder); + MaterialSettings(const MaterialSettings&) = default; + MaterialSettings(MaterialSettings&&) = delete; + ~MaterialSettings() = default; + + inline const Builder& GetBuilderData() const; + inline const std::vector& GetConditions() const; + inline std::size_t GetConditionIndex(const std::string_view& name) const; + inline std::size_t GetPredefinedBindingIndex(PredefinedShaderBinding binding) const; + inline const std::shared_ptr& GetRenderPipelineLayout() const; + inline const std::shared_ptr& GetShader(ShaderStageType stage) const; + inline const Shaders& GetShaders() const; + inline const std::vector& GetSharedUniformBlocks() const; + inline std::size_t GetSharedUniformBlockIndex(const std::string_view& name) const; + inline std::size_t GetSharedUniformBlockVariableOffset(std::size_t uniformBlockIndex, const std::string_view& name) const; + inline const std::vector& GetTextures() const; + inline std::size_t GetTextureIndex(const std::string_view& name) const; + inline const std::vector& GetUniformBlocks() const; + inline std::size_t GetUniformBlockIndex(const std::string_view& name) const; + inline std::size_t GetUniformBlockVariableOffset(std::size_t uniformBlockIndex, const std::string_view& name) const; + + MaterialSettings& operator=(const MaterialSettings&) = delete; + MaterialSettings& operator=(MaterialSettings&&) = delete; + + static constexpr std::size_t InvalidIndex = std::numeric_limits::max(); + + struct Builder + { + PredefinedBinding predefinedBinding; + Shaders shaders; + std::vector conditions; + std::vector textures; + std::vector uniformBlocks; + std::vector sharedUniformBlocks; + }; + + struct Condition + { + std::string name; + std::array enabledConditions; + }; + + struct UniformVariable + { + std::string name; + std::size_t offset; + }; + + struct SharedUniformBlock + { + std::string name; + std::string bindingPoint; + std::vector uniforms; + }; + + struct Texture + { + std::string bindingPoint; + std::string name; + ImageType type; + }; + + struct UniformBlock + { + std::size_t blockSize; + std::string name; + std::string bindingPoint; + std::vector uniforms; + std::vector defaultValues; + }; + + private: + std::shared_ptr m_pipelineLayout; + Builder m_data; + }; +} + +#include + +#endif // NAZARA_MATERIALPIPELINESETTINGS_HPP diff --git a/include/Nazara/Graphics/MaterialSettings.inl b/include/Nazara/Graphics/MaterialSettings.inl new file mode 100644 index 000000000..b91f84ef5 --- /dev/null +++ b/include/Nazara/Graphics/MaterialSettings.inl @@ -0,0 +1,175 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include + +namespace Nz +{ + inline MaterialSettings::MaterialSettings() : + MaterialSettings(Builder{}) + { + } + + inline MaterialSettings::MaterialSettings(Builder data) : + m_data(std::move(data)) + { + RenderPipelineLayoutInfo info; + + unsigned int bindingIndex = 0; + + for (const Texture& textureInfo : m_data.textures) + { + info.bindings.push_back({ + //textureInfo.bindingPoint, + ShaderBindingType::Texture, + ShaderStageType_All, + bindingIndex++ + }); + } + + for (const UniformBlock& ubo : m_data.uniformBlocks) + { + info.bindings.push_back({ + //ubo.bindingPoint, + ShaderBindingType::UniformBuffer, + ShaderStageType_All, + bindingIndex++ + }); + } + + for (const SharedUniformBlock& ubo : m_data.sharedUniformBlocks) + { + info.bindings.push_back({ + //ubo.bindingPoint, + ShaderBindingType::UniformBuffer, + ShaderStageType_All, + bindingIndex++ + }); + } + + m_pipelineLayout = Graphics::Instance()->GetRenderDevice()->InstantiateRenderPipelineLayout(std::move(info)); + } + + inline auto MaterialSettings::GetBuilderData() const -> const Builder& + { + return m_data; + } + + inline auto MaterialSettings::GetConditions() const -> const std::vector& + { + return m_data.conditions; + } + + inline std::size_t MaterialSettings::GetConditionIndex(const std::string_view& name) const + { + for (std::size_t i = 0; i < m_data.conditions.size(); ++i) + { + if (m_data.conditions[i].name == name) + return i; + } + + return InvalidIndex; + } + + inline std::size_t MaterialSettings::GetPredefinedBindingIndex(PredefinedShaderBinding binding) const + { + return m_data.predefinedBinding[UnderlyingCast(binding)]; + } + + inline const std::shared_ptr& MaterialSettings::GetRenderPipelineLayout() const + { + return m_pipelineLayout; + } + + inline const std::shared_ptr& MaterialSettings::GetShader(ShaderStageType stage) const + { + return m_data.shaders[UnderlyingCast(stage)]; + } + + inline auto MaterialSettings::GetShaders() const -> const Shaders& + { + return m_data.shaders; + } + + inline auto MaterialSettings::GetSharedUniformBlocks() const -> const std::vector& + { + return m_data.sharedUniformBlocks; + } + + inline std::size_t MaterialSettings::GetSharedUniformBlockIndex(const std::string_view& name) const + { + for (std::size_t i = 0; i < m_data.sharedUniformBlocks.size(); ++i) + { + if (m_data.sharedUniformBlocks[i].name == name) + return i; + } + + return InvalidIndex; + } + + inline std::size_t MaterialSettings::GetSharedUniformBlockVariableOffset(std::size_t uniformBlockIndex, const std::string_view& name) const + { + assert(uniformBlockIndex < m_data.sharedUniformBlocks.size()); + + const std::vector& variables = m_data.sharedUniformBlocks[uniformBlockIndex].uniforms; + for (std::size_t i = 0; i < variables.size(); ++i) + { + if (variables[i].name == name) + return i; + } + + return InvalidIndex; + } + + inline auto MaterialSettings::GetTextures() const -> const std::vector& + { + return m_data.textures; + } + + inline std::size_t MaterialSettings::GetTextureIndex(const std::string_view& name) const + { + for (std::size_t i = 0; i < m_data.textures.size(); ++i) + { + if (m_data.textures[i].name == name) + return i; + } + + return InvalidIndex; + } + + inline auto MaterialSettings::GetUniformBlocks() const -> const std::vector& + { + return m_data.uniformBlocks; + } + + inline std::size_t MaterialSettings::GetUniformBlockIndex(const std::string_view& name) const + { + for (std::size_t i = 0; i < m_data.uniformBlocks.size(); ++i) + { + if (m_data.uniformBlocks[i].name == name) + return i; + } + + return InvalidIndex; + } + + inline std::size_t MaterialSettings::GetUniformBlockVariableOffset(std::size_t uniformBlockIndex, const std::string_view& name) const + { + assert(uniformBlockIndex < m_data.uniformBlocks.size()); + + const std::vector& variables = m_data.uniformBlocks[uniformBlockIndex].uniforms; + for (std::size_t i = 0; i < variables.size(); ++i) + { + if (variables[i].name == name) + return i; + } + + return InvalidIndex; + } +} + +#include diff --git a/include/Nazara/Graphics/Model.hpp b/include/Nazara/Graphics/Model.hpp new file mode 100644 index 000000000..47f9a1697 --- /dev/null +++ b/include/Nazara/Graphics/Model.hpp @@ -0,0 +1,55 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_MODEL_HPP +#define NAZARA_MODEL_HPP + +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class GraphicalMesh; + class Material; + + class NAZARA_GRAPHICS_API Model + { + public: + Model(std::shared_ptr graphicalMesh); + Model(const Model&) = delete; + Model(Model&&) noexcept = default; + ~Model() = default; + + const std::shared_ptr& GetIndexBuffer(std::size_t subMeshIndex) const; + std::size_t GetIndexCount(std::size_t subMeshIndex) const; + const std::shared_ptr& GetRenderPipeline(std::size_t subMeshIndex) const; + const std::shared_ptr& GetVertexBuffer(std::size_t subMeshIndex) const; + inline std::size_t GetSubMeshCount() const; + + inline void SetMaterial(std::size_t subMeshIndex, std::shared_ptr material); + + Model& operator=(const Model&) = delete; + Model& operator=(Model&&) noexcept = default; + + private: + struct SubMeshData + { + std::shared_ptr material; + std::vector vertexBufferData; + }; + + std::shared_ptr m_graphicalMesh; + std::vector m_subMeshes; + }; +} + +#include + +#endif diff --git a/include/Nazara/Graphics/Model.inl b/include/Nazara/Graphics/Model.inl new file mode 100644 index 000000000..de31598dc --- /dev/null +++ b/include/Nazara/Graphics/Model.inl @@ -0,0 +1,23 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + inline std::size_t Model::GetSubMeshCount() const + { + return m_subMeshes.size(); + } + + inline void Model::SetMaterial(std::size_t subMeshIndex, std::shared_ptr material) + { + assert(subMeshIndex < m_subMeshes.size()); + m_subMeshes[subMeshIndex].material = std::move(material); + } +} + +#include diff --git a/include/Nazara/Graphics/ModelInstance.hpp b/include/Nazara/Graphics/ModelInstance.hpp new file mode 100644 index 000000000..4067249e4 --- /dev/null +++ b/include/Nazara/Graphics/ModelInstance.hpp @@ -0,0 +1,43 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_MODELINSTANCE_HPP +#define NAZARA_MODELINSTANCE_HPP + +#include +#include +#include +#include + +namespace Nz +{ + class AbstractBuffer; + class MaterialSettings; + + class NAZARA_GRAPHICS_API ModelInstance + { + public: + ModelInstance(const std::shared_ptr& settings); + ModelInstance(const ModelInstance&) = delete; + ModelInstance(ModelInstance&&) noexcept = default; + ~ModelInstance() = default; + + inline std::shared_ptr& GetInstanceBuffer(); + inline const std::shared_ptr& GetInstanceBuffer() const; + inline ShaderBinding& GetShaderBinding(); + + ModelInstance& operator=(const ModelInstance&) = delete; + ModelInstance& operator=(ModelInstance&&) noexcept = default; + + private: + std::shared_ptr m_instanceDataBuffer; + ShaderBindingPtr m_shaderBinding; + }; +} + +#include + +#endif // NAZARA_MODELINSTANCE_HPP diff --git a/include/Nazara/Graphics/ModelInstance.inl b/include/Nazara/Graphics/ModelInstance.inl new file mode 100644 index 000000000..2c87c6ecf --- /dev/null +++ b/include/Nazara/Graphics/ModelInstance.inl @@ -0,0 +1,26 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + inline std::shared_ptr& ModelInstance::GetInstanceBuffer() + { + return m_instanceDataBuffer; + } + + inline const std::shared_ptr& ModelInstance::GetInstanceBuffer() const + { + return m_instanceDataBuffer; + } + + inline ShaderBinding& ModelInstance::GetShaderBinding() + { + return *m_shaderBinding; + } +} + +#include diff --git a/include/Nazara/Graphics/PhongLightingMaterial.hpp b/include/Nazara/Graphics/PhongLightingMaterial.hpp new file mode 100644 index 000000000..34f4cf42a --- /dev/null +++ b/include/Nazara/Graphics/PhongLightingMaterial.hpp @@ -0,0 +1,103 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_PHONG_LIGHTING_MATERIAL_HPP +#define NAZARA_PHONG_LIGHTING_MATERIAL_HPP + +#include +#include + +namespace Nz +{ + class NAZARA_GRAPHICS_API PhongLightingMaterial + { + friend class MaterialPipeline; + + public: + PhongLightingMaterial(Material& material); + + inline const std::shared_ptr& GetAlphaMap() const; + float GetAlphaThreshold() const; + Color GetAmbientColor() const; + Color GetDiffuseColor() const; + inline const std::shared_ptr& GetDiffuseMap() const; + inline TextureSampler& GetDiffuseSampler(); + inline const TextureSampler& GetDiffuseSampler() const; + inline const std::shared_ptr& GetEmissiveMap() const; + inline const std::shared_ptr& GetHeightMap() const; + inline const std::shared_ptr& GetNormalMap() const; + float GetShininess() const; + Color GetSpecularColor() const; + inline const std::shared_ptr& GetSpecularMap() const; + inline TextureSampler& GetSpecularSampler(); + inline const TextureSampler& GetSpecularSampler() const; + + inline bool HasAlphaMap() const; + inline bool HasAlphaThreshold() const; + inline bool HasAmbientColor() const; + inline bool HasDiffuseColor() const; + inline bool HasDiffuseMap() const; + inline bool HasEmissiveMap() const; + inline bool HasHeightMap() const; + inline bool HasNormalMap() const; + inline bool HasShininess() const; + inline bool HasSpecularColor() const; + inline bool HasSpecularMap() const; + + inline void SetAlphaMap(std::shared_ptr alphaMap); + void SetAlphaThreshold(float alphaThreshold); + void SetAmbientColor(const Color& ambient); + void SetDiffuseColor(const Color& diffuse); + inline void SetDiffuseMap(std::shared_ptr diffuseMap); + inline void SetDiffuseSampler(const TextureSampler& sampler); + inline void SetEmissiveMap(std::shared_ptr textureName); + inline void SetHeightMap(std::shared_ptr textureName); + inline void SetNormalMap(std::shared_ptr textureName); + void SetShininess(float shininess); + void SetSpecularColor(const Color& specular); + inline void SetSpecularMap(std::shared_ptr specularMap); + inline void SetSpecularSampler(const TextureSampler& sampler); + + static const std::shared_ptr& GetSettings(); + + private: + struct PhongUniformOffsets + { + std::size_t alphaThreshold; + std::size_t shininess; + std::size_t ambientColor; + std::size_t diffuseColor; + std::size_t specularColor; + }; + + struct TextureIndexes + { + std::size_t alpha; + std::size_t diffuse; + std::size_t emissive; + std::size_t height; + std::size_t normal; + std::size_t specular; + }; + + static bool Initialize(); + static void Uninitialize(); + + Material& m_material; + std::size_t m_phongUniformIndex; + TextureIndexes m_textureIndexes; + PhongUniformOffsets m_phongUniformOffsets; + + static std::shared_ptr s_materialSettings; + static std::size_t s_phongUniformBlockIndex; + static TextureIndexes s_textureIndexes; + static PhongUniformOffsets s_phongUniformOffsets; + }; +} + +#include + +#endif // NAZARA_PHONG_LIGHTING_MATERIAL_HPP diff --git a/include/Nazara/Graphics/PhongLightingMaterial.inl b/include/Nazara/Graphics/PhongLightingMaterial.inl new file mode 100644 index 000000000..b9bd61d20 --- /dev/null +++ b/include/Nazara/Graphics/PhongLightingMaterial.inl @@ -0,0 +1,122 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include + +namespace Nz +{ + inline const std::shared_ptr& PhongLightingMaterial::GetAlphaMap() const + { + NazaraAssert(HasAlphaMap(), "Material has no alpha map slot"); + return m_material.GetTexture(m_textureIndexes.alpha); + } + + inline const std::shared_ptr& PhongLightingMaterial::GetDiffuseMap() const + { + NazaraAssert(HasDiffuseMap(), "Material has no alpha map slot"); + return m_material.GetTexture(m_textureIndexes.diffuse); + } + + inline const std::shared_ptr& PhongLightingMaterial::GetEmissiveMap() const + { + NazaraAssert(HasEmissiveMap(), "Material has no alpha map slot"); + return m_material.GetTexture(m_textureIndexes.emissive); + } + + inline const std::shared_ptr& PhongLightingMaterial::GetHeightMap() const + { + NazaraAssert(HasHeightMap(), "Material has no alpha map slot"); + return m_material.GetTexture(m_textureIndexes.height); + } + + inline const std::shared_ptr& PhongLightingMaterial::GetNormalMap() const + { + NazaraAssert(HasNormalMap(), "Material has no alpha map slot"); + return m_material.GetTexture(m_textureIndexes.normal); + } + + inline const std::shared_ptr& PhongLightingMaterial::GetSpecularMap() const + { + NazaraAssert(HasSpecularMap(), "Material has no alpha map slot"); + return m_material.GetTexture(m_textureIndexes.specular); + } + + inline bool PhongLightingMaterial::HasAlphaMap() const + { + return m_textureIndexes.alpha != MaterialSettings::InvalidIndex; + } + + inline bool PhongLightingMaterial::HasAlphaThreshold() const + { + return m_phongUniformOffsets.alphaThreshold != MaterialSettings::InvalidIndex; + } + + inline bool PhongLightingMaterial::HasAmbientColor() const + { + return m_phongUniformOffsets.ambientColor != MaterialSettings::InvalidIndex; + } + + inline bool PhongLightingMaterial::HasDiffuseColor() const + { + return m_phongUniformOffsets.diffuseColor != MaterialSettings::InvalidIndex; + } + + inline bool PhongLightingMaterial::HasDiffuseMap() const + { + return m_textureIndexes.diffuse != MaterialSettings::InvalidIndex; + } + + inline bool PhongLightingMaterial::HasEmissiveMap() const + { + return m_textureIndexes.emissive != MaterialSettings::InvalidIndex; + } + + inline bool PhongLightingMaterial::HasHeightMap() const + { + return m_textureIndexes.height != MaterialSettings::InvalidIndex; + } + + inline bool PhongLightingMaterial::HasNormalMap() const + { + return m_textureIndexes.normal != MaterialSettings::InvalidIndex; + } + + inline bool PhongLightingMaterial::HasShininess() const + { + return m_phongUniformOffsets.shininess != MaterialSettings::InvalidIndex; + } + + inline bool PhongLightingMaterial::HasSpecularColor() const + { + return m_phongUniformOffsets.specularColor != MaterialSettings::InvalidIndex; + } + + inline bool PhongLightingMaterial::HasSpecularMap() const + { + return m_textureIndexes.specular != MaterialSettings::InvalidIndex; + } + + inline void PhongLightingMaterial::SetAlphaMap(std::shared_ptr alphaMap) + { + NazaraAssert(HasAlphaMap(), "Material has no alpha map slot"); + m_material.SetTexture(m_textureIndexes.alpha, std::move(alphaMap)); + } + + inline void PhongLightingMaterial::SetDiffuseMap(std::shared_ptr diffuseMap) + { + NazaraAssert(HasDiffuseMap(), "Material has no diffuse map slot"); + m_material.SetTexture(m_textureIndexes.diffuse, std::move(diffuseMap)); + } + + inline void PhongLightingMaterial::SetNormalMap(std::shared_ptr normalMap) + { + NazaraAssert(HasNormalMap(), "Material has no normal map slot"); + m_material.SetTexture(m_textureIndexes.normal, std::move(normalMap)); + } +} + +#include diff --git a/include/Nazara/Graphics/PredefinedShaderStructs.hpp b/include/Nazara/Graphics/PredefinedShaderStructs.hpp new file mode 100644 index 000000000..89b207ed1 --- /dev/null +++ b/include/Nazara/Graphics/PredefinedShaderStructs.hpp @@ -0,0 +1,68 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_PREDEFINEDSHADERSTRUCTS_HPP +#define NAZARA_PREDEFINEDSHADERSTRUCTS_HPP + +#include +#include +#include + +namespace Nz +{ + struct NAZARA_GRAPHICS_API PredefinedLightData + { + struct InnerStruct + { + std::size_t type; + std::size_t color; + std::size_t factor; + std::size_t parameter1; + std::size_t parameter2; + std::size_t parameter3; + std::size_t shadowMappingFlag; + std::size_t totalSize; + }; + + InnerStruct innerOffsets; + std::array lightArray; + std::size_t lightArraySize; + + static PredefinedLightData GetOffset(); + static MaterialSettings::SharedUniformBlock GetUniformBlock(); + }; + + struct NAZARA_GRAPHICS_API PredefinedInstanceData + { + std::size_t invWorldMatrixOffset; + std::size_t totalSize; + std::size_t worldMatrixOffset; + + static PredefinedInstanceData GetOffsets(); + static MaterialSettings::SharedUniformBlock GetUniformBlock(); + }; + + struct NAZARA_GRAPHICS_API PredefinedViewerData + { + std::size_t eyePositionOffset; + std::size_t invProjMatrixOffset; + std::size_t invTargetSizeOffset; + std::size_t invViewMatrixOffset; + std::size_t invViewProjMatrixOffset; + std::size_t projMatrixOffset; + std::size_t targetSizeOffset; + std::size_t totalSize; + std::size_t viewMatrixOffset; + std::size_t viewProjMatrixOffset; + + static PredefinedViewerData GetOffsets(); + static MaterialSettings::SharedUniformBlock GetUniformBlock(); + }; +} + +#include + +#endif // NAZARA_PREDEFINEDSHADERSTRUCTS_HPP diff --git a/include/Nazara/Graphics/PredefinedShaderStructs.inl b/include/Nazara/Graphics/PredefinedShaderStructs.inl new file mode 100644 index 000000000..e3daa8694 --- /dev/null +++ b/include/Nazara/Graphics/PredefinedShaderStructs.inl @@ -0,0 +1,9 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include + +namespace Nz +{ +} diff --git a/include/Nazara/Graphics/RenderQueue.hpp b/include/Nazara/Graphics/RenderQueue.hpp new file mode 100644 index 000000000..0d1f1fb81 --- /dev/null +++ b/include/Nazara/Graphics/RenderQueue.hpp @@ -0,0 +1,101 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_RENDERQUEUE_HPP +#define NAZARA_RENDERQUEUE_HPP + +#include +#include +#include + +namespace Nz +{ + class RenderQueueInternal + { + public: + using Index = Nz::UInt64; + + RenderQueueInternal() = default; + RenderQueueInternal(const RenderQueueInternal&) = default; + RenderQueueInternal(RenderQueueInternal&&) = default; + ~RenderQueueInternal() = default; + + RenderQueueInternal& operator=(const RenderQueueInternal&) = default; + RenderQueueInternal& operator=(RenderQueueInternal&&) = default; + + protected: + using RenderDataPair = std::pair; + + void Sort(); + + std::vector m_orderedRenderQueue; + }; + + template + class RenderQueue : public RenderQueueInternal + { + public: + class const_iterator; + friend const_iterator; + using size_type = std::size_t; + + RenderQueue() = default; + RenderQueue(const RenderQueue&) = default; + RenderQueue(RenderQueue&&) noexcept = default; + ~RenderQueue() = default; + + void Clear(); + + void Insert(RenderData&& data); + + template void Sort(IndexFunc&& func); + + // STL API + inline const_iterator begin() const; + inline bool empty() const; + inline const_iterator end() const; + inline size_type size() const; + + RenderQueue& operator=(const RenderQueue&) = default; + RenderQueue& operator=(RenderQueue&&) noexcept = default; + + private: + const RenderData& GetData(std::size_t i) const; + + std::vector m_data; + }; + + template + class RenderQueue::const_iterator : public std::iterator + { + friend RenderQueue; + + public: + const_iterator(const const_iterator& it); + + const RenderData& operator*() const; + + const_iterator& operator=(const const_iterator& it); + const_iterator& operator++(); + const_iterator operator++(int); + + bool operator==(const const_iterator& rhs) const; + bool operator!=(const const_iterator& rhs) const; + + void swap(const_iterator& rhs); + + private: + const_iterator(const RenderQueue* queue, std::size_t nextId); + + std::size_t m_nextDataId; + const RenderQueue* m_queue; + }; + +} + +#include + +#endif // NAZARA_RENDERQUEUE_HPP diff --git a/include/Nazara/Graphics/RenderQueue.inl b/include/Nazara/Graphics/RenderQueue.inl new file mode 100644 index 000000000..47ec03c98 --- /dev/null +++ b/include/Nazara/Graphics/RenderQueue.inl @@ -0,0 +1,136 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + template + void RenderQueue::Clear() + { + m_orderedRenderQueue.clear(); + m_data.clear(); + } + + template + void RenderQueue::Insert(RenderData&& data) + { + m_data.emplace_back(std::move(data)); + } + + template + template + void RenderQueue::Sort(IndexFunc&& func) + { + m_orderedRenderQueue.clear(); + m_orderedRenderQueue.reserve(m_data.size()); + + std::size_t dataIndex = 0; + for (const RenderData& renderData : m_data) + m_orderedRenderQueue.emplace_back(func(renderData), dataIndex++); + + RenderQueueInternal::Sort(); + } + + template + typename RenderQueue::const_iterator RenderQueue::begin() const + { + return const_iterator(this, 0); + } + + template + bool RenderQueue::empty() const + { + return m_orderedRenderQueue.empty(); + } + + template + typename RenderQueue::const_iterator RenderQueue::end() const + { + return const_iterator(this, m_orderedRenderQueue.size()); + } + + template + typename RenderQueue::size_type RenderQueue::size() const + { + return m_orderedRenderQueue.size(); + } + + template + const RenderData& RenderQueue::GetData(std::size_t i) const + { + NazaraAssert(i < m_orderedRenderQueue.size(), "Cannot dereference post-end iterator"); + + return m_data[m_orderedRenderQueue[i].second]; + } + + + template + RenderQueue::const_iterator::const_iterator(const RenderQueue* queue, std::size_t nextId) : + m_nextDataId(nextId), + m_queue(queue) + { + } + + template + RenderQueue::const_iterator::const_iterator(const const_iterator& it) : + m_nextDataId(it.m_nextDataId), + m_queue(it.m_queue) + { + } + + template + const RenderData& RenderQueue::const_iterator::operator*() const + { + return m_queue->GetData(m_nextDataId); + } + + template + typename RenderQueue::const_iterator& RenderQueue::const_iterator::operator=(const const_iterator& it) + { + m_nextDataId = it.m_nextDataId; + m_queue = it.m_queue; + + return *this; + } + + template + typename RenderQueue::const_iterator& RenderQueue::const_iterator::operator++() + { + ++m_nextDataId; + + return *this; + } + + template + typename RenderQueue::const_iterator RenderQueue::const_iterator::operator++(int) + { + return iterator(m_queue, m_nextDataId++); + } + + template + bool RenderQueue::const_iterator::operator==(const typename RenderQueue::const_iterator& rhs) const + { + NazaraAssert(m_queue == rhs.m_queue, "Cannot compare iterator coming from different queues"); + + return m_nextDataId == rhs.m_nextDataId; + } + + template + bool RenderQueue::const_iterator::operator!=(const typename RenderQueue::const_iterator& rhs) const + { + return !operator==(rhs); + } + + template + void RenderQueue::const_iterator::swap(typename RenderQueue::const_iterator& rhs) + { + NazaraAssert(m_queue == rhs.m_queue, "Cannot swap iterator coming from different queues"); + + using std::swap; + + swap(m_nextDataId, rhs.m_nextDataId); + } +} diff --git a/include/Nazara/Graphics/TextureSamplerCache.hpp b/include/Nazara/Graphics/TextureSamplerCache.hpp new file mode 100644 index 000000000..71a7e4c5d --- /dev/null +++ b/include/Nazara/Graphics/TextureSamplerCache.hpp @@ -0,0 +1,40 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_TEXTURESAMPLERCACHE_HPP +#define NAZARA_TEXTURESAMPLERCACHE_HPP + +#include +#include +#include +#include + +namespace Nz +{ + class RenderDevice; + + class NAZARA_GRAPHICS_API TextureSamplerCache + { + public: + inline TextureSamplerCache(std::shared_ptr device); + TextureSamplerCache(const TextureSamplerCache&) = delete; + TextureSamplerCache(TextureSamplerCache&&) = delete; + ~TextureSamplerCache() = default; + + const std::shared_ptr& Get(const TextureSamplerInfo& info); + + TextureSamplerCache& operator=(const TextureSamplerCache&) = delete; + TextureSamplerCache& operator=(TextureSamplerCache&&) = delete; + + private: + std::shared_ptr m_device; + std::unordered_map> m_samplers; + }; +} + +#include + +#endif diff --git a/include/Nazara/Graphics/TextureSamplerCache.inl b/include/Nazara/Graphics/TextureSamplerCache.inl new file mode 100644 index 000000000..e72e3c4cd --- /dev/null +++ b/include/Nazara/Graphics/TextureSamplerCache.inl @@ -0,0 +1,17 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + inline TextureSamplerCache::TextureSamplerCache(std::shared_ptr device) : + m_device(std::move(device)) + { + } +} + +#include diff --git a/include/Nazara/Graphics/UberShader.hpp b/include/Nazara/Graphics/UberShader.hpp new file mode 100644 index 000000000..f661b99be --- /dev/null +++ b/include/Nazara/Graphics/UberShader.hpp @@ -0,0 +1,41 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_UBER_SHADER_HPP +#define NAZARA_UBER_SHADER_HPP + +#include +#include +#include +#include +#include + +namespace Nz +{ + class ShaderModule; + + class NAZARA_GRAPHICS_API UberShader + { + public: + UberShader(ShaderStageType shaderStage, const ShaderAst::StatementPtr& shaderAst); + ~UberShader() = default; + + UInt64 GetOptionFlagByName(const std::string& optionName) const; + + const std::shared_ptr& Get(UInt64 combination); + + private: + std::unordered_map> m_combinations; + std::unordered_map m_optionIndexByName; + ShaderAst::StatementPtr m_shaderAst; + ShaderStageType m_shaderStage; + UInt64 m_combinationMask; + }; +} + +#include + +#endif // NAZARA_UBER_SHADER_HPP diff --git a/include/Nazara/Graphics/UberShader.inl b/include/Nazara/Graphics/UberShader.inl new file mode 100644 index 000000000..376dc23cb --- /dev/null +++ b/include/Nazara/Graphics/UberShader.inl @@ -0,0 +1,12 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ +} + +#include diff --git a/include/Nazara/Math/Algorithm.hpp b/include/Nazara/Math/Algorithm.hpp index 7c22947b9..4c07bfb96 100644 --- a/include/Nazara/Math/Algorithm.hpp +++ b/include/Nazara/Math/Algorithm.hpp @@ -9,6 +9,7 @@ #define NAZARA_ALGORITHM_MATH_HPP #include +#include #include #include #include @@ -35,11 +36,12 @@ namespace Nz { + template class Angle; + template constexpr T Approach(T value, T objective, T increment); template constexpr T Clamp(T value, T min, T max); + template constexpr Angle Clamp(Angle value, T min, T max); template constexpr std::size_t CountBits(T value); - template constexpr T FromDegrees(T degrees); - template constexpr T FromRadians(T radians); template constexpr T DegreeToRadian(T degrees); template constexpr T GetNearestPowerOfTwo(T number); constexpr unsigned int GetNumberLength(signed char number); @@ -56,14 +58,13 @@ namespace Nz template constexpr T IntegralPow(T base, unsigned int exponent); template constexpr T Lerp(const T& from, const T& to, const T2& interpolation); template constexpr T MultiplyAdd(T x, T y, T z); - template constexpr T NormalizeAngle(T angle); template constexpr bool NumberEquals(T a, T b); template constexpr bool NumberEquals(T a, T b, T maxDifference); inline std::string NumberToString(long long number, UInt8 radix = 10); template constexpr T RadianToDegree(T radians); + template T SetBit(T number, T bit); inline long long StringToNumber(const std::string_view& str, UInt8 radix = 10, bool* ok = nullptr); - template constexpr T ToDegrees(T angle); - template constexpr T ToRadians(T angle); + template bool TestBit(T number, T bit); } #include diff --git a/include/Nazara/Math/Algorithm.inl b/include/Nazara/Math/Algorithm.inl index d480f60f8..54b6c0d7c 100644 --- a/include/Nazara/Math/Algorithm.inl +++ b/include/Nazara/Math/Algorithm.inl @@ -157,6 +157,21 @@ namespace Nz return std::max(std::min(value, max), min); } + /*! + * \ingroup math + * \brief Clamps an angle value between min and max and returns the expected value + * \return If value is not in the interval of min..max, value obtained is the nearest limit of this interval + * + * \param value Value to clamp + * \param min Minimum of the interval + * \param max Maximum of the interval + */ + template + constexpr Angle Clamp(Angle value, T min, T max) + { + return std::max(std::min(value.value, max), min); + } + /*! * \ingroup math * \brief Gets number of bits set in the number @@ -191,40 +206,6 @@ namespace Nz return degrees * T(M_PI/180.0); } - /*! - * \ingroup math - * \brief Gets the unit from degree and convert it according to NAZARA_MATH_ANGLE_RADIAN - * \return Express the degrees - * - * \param degrees Convert degree to NAZARA_MATH_ANGLE_RADIAN unit - */ - template - constexpr T FromDegrees(T degrees) - { - #if NAZARA_MATH_ANGLE_RADIAN - return DegreeToRadian(degrees); - #else - return degrees; - #endif - } - - /*! - * \ingroup math - * \brief Gets the unit from radian and convert it according to NAZARA_MATH_ANGLE_RADIAN - * \return Express the radians - * - * \param radians Convert radian to NAZARA_MATH_ANGLE_RADIAN unit - */ - template - constexpr T FromRadians(T radians) - { - #if NAZARA_MATH_ANGLE_RADIAN - return radians; - #else - return RadianToDegree(radians); - #endif - } - /*! * \ingroup math * \brief Gets the nearest power of two for the number @@ -506,30 +487,6 @@ namespace Nz } #endif - /*! - * \ingroup math - * \brief Normalizes the angle - * \return Normalized value between 0..2*(pi if radian or 180 if degrees) - * - * \param angle Angle to normalize - */ - template - constexpr inline T NormalizeAngle(T angle) - { - #if NAZARA_MATH_ANGLE_RADIAN - const T limit = T(M_PI); - #else - const T limit = T(180.0); - #endif - const T twoLimit = limit * T(2); - - angle = std::fmod(angle, twoLimit); - if (angle < T(0)) - angle += twoLimit; - - return angle; - } - /*! * \ingroup math * \brief Checks whether two numbers are equal @@ -624,6 +581,13 @@ namespace Nz return radians * T(180.0/M_PI); } + template + T SetBit(T number, T bit) + { + NazaraAssert(bit < sizeof(number)* CHAR_BIT, "bit index out of range"); + return number |= (T(1) << bit); + } + /*! * \ingroup math * \brief Converts the string to number @@ -689,39 +653,13 @@ namespace Nz return (negative) ? -static_cast(total) : total; } - /*! - * \ingroup math - * \brief Gets the degree from unit and convert it according to NAZARA_MATH_ANGLE_RADIAN - * \return Express in degrees - * - * \param angle Convert degree from NAZARA_MATH_ANGLE_RADIAN unit to degrees - */ template - constexpr T ToDegrees(T angle) + bool TestBit(T number, T bit) { - #if NAZARA_MATH_ANGLE_RADIAN - return RadianToDegree(angle); - #else - return angle; - #endif - } - - /*! - * \ingroup math - * \brief Gets the radian from unit and convert it according to NAZARA_MATH_ANGLE_RADIAN - * \return Express in radians - * - * \param angle Convert degree from NAZARA_MATH_ANGLE_RADIAN unit to radians - */ - template - constexpr T ToRadians(T angle) - { - #if NAZARA_MATH_ANGLE_RADIAN - return angle; - #else - return DegreeToRadian(angle); - #endif + NazaraAssert(bit < sizeof(number) * CHAR_BIT, "bit index out of range"); + return number & (T(1) << bit); } } #include +#include "Algorithm.hpp" diff --git a/include/Nazara/Math/Angle.hpp b/include/Nazara/Math/Angle.hpp index 46c1d30ab..c59f629ab 100644 --- a/include/Nazara/Math/Angle.hpp +++ b/include/Nazara/Math/Angle.hpp @@ -26,11 +26,11 @@ namespace Nz class Angle { public: - Angle() = default; - Angle(T angle); - Angle(const Angle& angle); - Angle(const Angle& angle); - template explicit Angle(const Angle& Angle); + constexpr Angle() = default; + constexpr Angle(T angle); + template constexpr explicit Angle(const Angle& Angle); + constexpr Angle(const Angle& angle); + constexpr Angle(const Angle& angle); ~Angle() = default; T GetCos() const; @@ -38,39 +38,39 @@ namespace Nz std::pair GetSinCos() const; T GetTan() const; - Angle& MakeZero(); + constexpr Angle& MakeZero(); - void Normalize(); + constexpr Angle& Normalize(); - Angle& Set(const Angle& ang); - template Angle& Set(const Angle& ang); + constexpr Angle& Set(const Angle& ang); + template constexpr Angle& Set(const Angle& ang); - T ToDegrees() const; - Angle ToDegreeAngle() const; + constexpr T ToDegrees() const; + constexpr Angle ToDegreeAngle() const; EulerAngles ToEulerAngles() const; Quaternion ToQuaternion() const; - T ToRadians() const; - Angle ToRadianAngle() const; + constexpr T ToRadians() const; + constexpr Angle ToRadianAngle() const; std::string ToString() const; - Angle& operator=(const Angle&) = default; + constexpr Angle& operator=(const Angle&) = default; - Angle operator+(const Angle& other) const; - Angle operator-(const Angle& other) const; - Angle operator*(T scalar) const; - Angle operator/(T divider) const; + constexpr Angle operator+(const Angle& other) const; + constexpr Angle operator-(const Angle& other) const; + constexpr Angle operator*(T scalar) const; + constexpr Angle operator/(T divider) const; - Angle& operator+=(const Angle& other); - Angle& operator-=(const Angle& other); - Angle& operator*=(T scalar); - Angle& operator/=(T divider); + constexpr Angle& operator+=(const Angle& other); + constexpr Angle& operator-=(const Angle& other); + constexpr Angle& operator*=(T scalar); + constexpr Angle& operator/=(T divider); - bool operator==(const Angle& other) const; - bool operator!=(const Angle& other) const; + constexpr bool operator==(const Angle& other) const; + constexpr bool operator!=(const Angle& other) const; - static Angle FromDegrees(T ang); - static Angle FromRadians(T ang); - static Angle Zero(); + static constexpr Angle FromDegrees(T ang); + static constexpr Angle FromRadians(T ang); + static constexpr Angle Zero(); T value; }; diff --git a/include/Nazara/Math/Angle.inl b/include/Nazara/Math/Angle.inl index 55ac418d9..eee5d084d 100644 --- a/include/Nazara/Math/Angle.inl +++ b/include/Nazara/Math/Angle.inl @@ -32,22 +32,22 @@ namespace Nz return 180; } - template static T FromDegrees(T degrees) + template static constexpr T FromDegrees(T degrees) { return degrees; } - template static T FromRadians(T radians) + template static constexpr T FromRadians(T radians) { return RadianToDegree(radians); } - template static T ToDegrees(T degrees) + template static constexpr T ToDegrees(T degrees) { return degrees; } - template static T ToRadians(T degrees) + template static constexpr T ToRadians(T degrees) { return DegreeToRadian(degrees); } @@ -71,22 +71,22 @@ namespace Nz return T(M_PI); } - template static T FromDegrees(T degrees) + template static constexpr T FromDegrees(T degrees) { return DegreeToRadian(degrees); } - template static T FromRadians(T radians) + template static constexpr T FromRadians(T radians) { return radians; } - template static T ToDegrees(T radians) + template static constexpr T ToDegrees(T radians) { return RadianToDegree(radians); } - template static T ToRadians(T radians) + template static constexpr T ToRadians(T radians) { return radians; } @@ -141,7 +141,7 @@ namespace Nz * \param value value of the angle */ template - Angle::Angle(T angle) : + constexpr Angle::Angle(T angle) : value(angle) { } @@ -152,7 +152,7 @@ namespace Nz * \param value Angle object to copy */ template - Angle::Angle(const Angle& angle) : + constexpr Angle::Angle(const Angle& angle) : value(Detail::AngleUtils::FromDegrees(angle.value)) { } @@ -163,7 +163,7 @@ namespace Nz * \param value Angle object to copy */ template - Angle::Angle(const Angle& angle) : + constexpr Angle::Angle(const Angle& angle) : value(Detail::AngleUtils::FromRadians(angle.value)) { } @@ -225,7 +225,7 @@ namespace Nz * \brief Changes the angle value to zero */ template - Angle& Angle::MakeZero() + constexpr Angle& Angle::MakeZero() { value = T(0); return *this; @@ -239,7 +239,7 @@ namespace Nz * For radian angles, local limits are [-M_PI, M_PI] */ template - void Angle::Normalize() + constexpr Angle& Angle::Normalize() { constexpr T limit = Detail::AngleUtils::template GetLimit(); constexpr T twoLimit = limit * T(2); @@ -247,6 +247,8 @@ namespace Nz value = std::fmod(value, twoLimit); if (value < T(0)) value += twoLimit; + + return *this; } /*! @@ -255,7 +257,7 @@ namespace Nz * \param Angle Angle which will be copied */ template - Angle& Angle::Set(const Angle& ang) + constexpr Angle& Angle::Set(const Angle& ang) { value = ang.value; return *this; @@ -270,7 +272,7 @@ namespace Nz */ template template - Angle& Angle::Set(const Angle& ang) + constexpr Angle& Angle::Set(const Angle& ang) { value = static_cast(ang.value); return *this; @@ -281,7 +283,7 @@ namespace Nz * \return Equivalent degree angle value */ template - T Angle::ToDegrees() const + constexpr T Angle::ToDegrees() const { return Detail::AngleUtils::ToDegrees(value); } @@ -291,7 +293,7 @@ namespace Nz * \return Equivalent degree angle */ template - Angle Angle::ToDegreeAngle() const + constexpr Angle Angle::ToDegreeAngle() const { return DegreeAngle(ToDegrees()); } @@ -329,7 +331,7 @@ namespace Nz * \return Equivalent radian angle value */ template - T Angle::ToRadians() const + constexpr T Angle::ToRadians() const { return Detail::AngleUtils::ToRadians(value); } @@ -339,7 +341,7 @@ namespace Nz * \return Equivalent radian angle */ template - Angle Angle::ToRadianAngle() const + constexpr Angle Angle::ToRadianAngle() const { return RadianAngle(ToRadians()); } @@ -386,7 +388,7 @@ namespace Nz * \param other Angle to add */ template - Angle Angle::operator+(const Angle& other) const + constexpr Angle Angle::operator+(const Angle& other) const { return Angle(value + other.value); } @@ -398,7 +400,7 @@ namespace Nz * \param other Angle to subtract */ template - Angle Angle::operator-(const Angle& other) const + constexpr Angle Angle::operator-(const Angle& other) const { return Angle(value - other.value); } @@ -410,7 +412,7 @@ namespace Nz * \param scalar Multiplier */ template - Angle Angle::operator*(T scalar) const + constexpr Angle Angle::operator*(T scalar) const { return Angle(value * scalar); } @@ -422,7 +424,7 @@ namespace Nz * \param divider Divider */ template - Angle Angle::operator/(T divider) const + constexpr Angle Angle::operator/(T divider) const { return Angle(value / divider); } @@ -434,7 +436,7 @@ namespace Nz * \param other Angle to add */ template - Angle& Angle::operator+=(const Angle& other) + constexpr Angle& Angle::operator+=(const Angle& other) { value += other.value; return *this; @@ -447,7 +449,7 @@ namespace Nz * \param other Angle to subtract */ template - Angle& Angle::operator-=(const Angle& other) + constexpr Angle& Angle::operator-=(const Angle& other) { value -= other.value; return *this; @@ -460,7 +462,7 @@ namespace Nz * \param scalar Multiplier */ template - Angle& Angle::operator*=(T scalar) + constexpr Angle& Angle::operator*=(T scalar) { value *= scalar; return *this; @@ -473,7 +475,7 @@ namespace Nz * \param divider Divider */ template - Angle& Angle::operator/=(T divider) + constexpr Angle& Angle::operator/=(T divider) { value /= divider; return *this; @@ -486,7 +488,7 @@ namespace Nz * \param other The other angle to compare to */ template - bool Angle::operator==(const Angle& other) const + constexpr bool Angle::operator==(const Angle& other) const { return NumberEquals(value, other.value, Detail::AngleUtils::template GetEpsilon()); } @@ -498,7 +500,7 @@ namespace Nz * \param other The other angle to compare to */ template - bool Angle::operator!=(const Angle& other) const + constexpr bool Angle::operator!=(const Angle& other) const { return !NumberEquals(value, other.value, Detail::AngleUtils::template GetEpsilon()); } @@ -510,7 +512,7 @@ namespace Nz * \param ang Degree angle */ template - Angle Angle::FromDegrees(T ang) + constexpr Angle Angle::FromDegrees(T ang) { return Angle(Detail::AngleUtils::FromDegrees(ang)); } @@ -522,7 +524,7 @@ namespace Nz * \param ang Radian angle */ template - Angle Angle::FromRadians(T ang) + constexpr Angle Angle::FromRadians(T ang) { return Angle(Detail::AngleUtils::FromRadians(ang)); } @@ -532,7 +534,7 @@ namespace Nz * \return Zero angle */ template - Angle Angle::Zero() + constexpr Angle Angle::Zero() { Angle angle; angle.MakeZero(); diff --git a/include/Nazara/Math/Config.hpp b/include/Nazara/Math/Config.hpp index a4891a18a..37f9c0de8 100644 --- a/include/Nazara/Math/Config.hpp +++ b/include/Nazara/Math/Config.hpp @@ -35,9 +35,6 @@ /// Each modification of a paramater of the module needs a recompilation of the unit -// Define the radian as unit for angles -#define NAZARA_MATH_ANGLE_RADIAN 0 - // Optimize automatically the operation on affine matrices (Ask several comparisons to determine if the matrix is affine) #define NAZARA_MATH_MATRIX4_CHECK_AFFINE 0 diff --git a/include/Nazara/Math/EulerAngles.hpp b/include/Nazara/Math/EulerAngles.hpp index 4e13e0b8c..07101db0a 100644 --- a/include/Nazara/Math/EulerAngles.hpp +++ b/include/Nazara/Math/EulerAngles.hpp @@ -21,8 +21,8 @@ namespace Nz { public: EulerAngles() = default; - EulerAngles(T P, T Y, T R); - EulerAngles(const T angles[3]); + EulerAngles(DegreeAngle P, DegreeAngle Y, DegreeAngle R); + EulerAngles(const DegreeAngle angles[3]); template EulerAngles(const Angle& angle); //EulerAngles(const Matrix3& mat); EulerAngles(const Quaternion& quat); @@ -34,8 +34,8 @@ namespace Nz EulerAngles& Normalize(); - EulerAngles& Set(T P, T Y, T R); - EulerAngles& Set(const T angles[3]); + EulerAngles& Set(DegreeAngle P, DegreeAngle Y, DegreeAngle R); + EulerAngles& Set(const DegreeAngle angles[3]); template EulerAngles& Set(const Angle& angles); //EulerAngles& Set(const Matrix3& mat); EulerAngles& Set(const Quaternion& quat); @@ -61,7 +61,7 @@ namespace Nz static EulerAngles Zero(); - T pitch, yaw, roll; + DegreeAngle pitch, yaw, roll; }; using EulerAnglesd = EulerAngles; diff --git a/include/Nazara/Math/EulerAngles.inl b/include/Nazara/Math/EulerAngles.inl index 67aa909d5..fccda5f72 100644 --- a/include/Nazara/Math/EulerAngles.inl +++ b/include/Nazara/Math/EulerAngles.inl @@ -32,7 +32,7 @@ namespace Nz */ template - EulerAngles::EulerAngles(T P, T Y, T R) + EulerAngles::EulerAngles(DegreeAngle P, DegreeAngle Y, DegreeAngle R) { Set(P, Y, R); } @@ -44,7 +44,7 @@ namespace Nz */ template - EulerAngles::EulerAngles(const T angles[3]) + EulerAngles::EulerAngles(const DegreeAngle angles[3]) { Set(angles); } @@ -101,17 +101,15 @@ namespace Nz * \brief Normalizes the euler angle * \return A reference to this euler angle with has been normalized * - * \remark Normalization depends on NAZARA_MATH_ANGLE_RADIAN, between 0..2*pi - * * \see NormalizeAngle */ template EulerAngles& EulerAngles::Normalize() { - pitch = NormalizeAngle(pitch); - yaw = NormalizeAngle(yaw); - roll = NormalizeAngle(roll); + pitch.Normalize(); + yaw.Normalize(); + roll.Normalize(); return *this; } @@ -126,7 +124,7 @@ namespace Nz */ template - EulerAngles& EulerAngles::Set(T P, T Y, T R) + EulerAngles& EulerAngles::Set(DegreeAngle P, DegreeAngle Y, DegreeAngle R) { pitch = P; yaw = Y; @@ -143,7 +141,7 @@ namespace Nz */ template - EulerAngles& EulerAngles::Set(const T angles[3]) + EulerAngles& EulerAngles::Set(const DegreeAngle angles[3]) { pitch = angles[0]; yaw = angles[1]; @@ -192,9 +190,9 @@ namespace Nz template EulerAngles& EulerAngles::Set(const EulerAngles& angles) { - pitch = T(angles.pitch); - yaw = T(angles.yaw); - roll = T(angles.roll); + pitch.Set(angles.pitch); + yaw.Set(angles.yaw); + roll.Set(angles.roll); return *this; } @@ -208,13 +206,13 @@ namespace Nz Quaternion EulerAngles::ToQuaternion() const { // XYZ - T c1 = std::cos(ToRadians(yaw) / T(2.0)); - T c2 = std::cos(ToRadians(roll) / T(2.0)); - T c3 = std::cos(ToRadians(pitch) / T(2.0)); + T c1 = (yaw / T(2.0)).GetCos(); + T c2 = (roll / T(2.0)).GetCos(); + T c3 = (pitch / T(2.0)).GetCos(); - T s1 = std::sin(ToRadians(yaw) / T(2.0)); - T s2 = std::sin(ToRadians(roll) / T(2.0)); - T s3 = std::sin(ToRadians(pitch) / T(2.0)); + T s1 = (yaw / T(2.0)).GetSin(); + T s2 = (roll / T(2.0)).GetSin(); + T s3 = (pitch / T(2.0)).GetSin(); return Quaternion(c1 * c2 * c3 - s1 * s2 * s3, s1 * s2 * c3 + c1 * c2 * s3, @@ -310,9 +308,7 @@ namespace Nz template bool EulerAngles::operator==(const EulerAngles& angles) const { - return NumberEquals(pitch, angles.pitch) && - NumberEquals(yaw, angles.yaw) && - NumberEquals(roll, angles.roll); + return pitch == angles.pitch && yaw == angles.yaw && roll == angles.roll; } /*! diff --git a/include/Nazara/Math/Frustum.hpp b/include/Nazara/Math/Frustum.hpp index dce528dc1..f676603c7 100644 --- a/include/Nazara/Math/Frustum.hpp +++ b/include/Nazara/Math/Frustum.hpp @@ -7,6 +7,7 @@ #ifndef NAZARA_FRUSTUM_HPP #define NAZARA_FRUSTUM_HPP +#include #include #include #include @@ -29,7 +30,7 @@ namespace Nz Frustum(const Frustum& frustum) = default; ~Frustum() = default; - Frustum& Build(T angle, T ratio, T zNear, T zFar, const Vector3& eye, const Vector3& target, const Vector3& up = Vector3::Up()); + Frustum& Build(RadianAngle angle, T ratio, T zNear, T zFar, const Vector3& eye, const Vector3& target, const Vector3& up = Vector3::Up()); bool Contains(const BoundingVolume& volume) const; bool Contains(const Box& box) const; diff --git a/include/Nazara/Math/Frustum.inl b/include/Nazara/Math/Frustum.inl index 3dfab07a1..80472e3db 100644 --- a/include/Nazara/Math/Frustum.inl +++ b/include/Nazara/Math/Frustum.inl @@ -40,7 +40,7 @@ namespace Nz * \brief Builds the frustum object * \return A reference to this frustum which is the build up camera's field of view * - * \param angle Unit depends on NAZARA_MATH_ANGLE_RADIAN + * \param angle FOV angle * \param ratio Rendering ratio (typically 16/9 or 4/3) * \param zNear Distance where 'vision' begins * \param zFar Distance where 'vision' ends @@ -50,15 +50,11 @@ namespace Nz */ template - Frustum& Frustum::Build(T angle, T ratio, T zNear, T zFar, const Vector3& eye, const Vector3& target, const Vector3& up) + Frustum& Frustum::Build(RadianAngle angle, T ratio, T zNear, T zFar, const Vector3& eye, const Vector3& target, const Vector3& up) { - #if NAZARA_MATH_ANGLE_RADIAN angle /= T(2.0); - #else - angle = DegreeToRadian(angle / T(2.0)); - #endif - T tangent = std::tan(angle); + T tangent = angle.GetTan(); T nearH = zNear * tangent; T nearW = nearH * ratio; T farH = zFar * tangent; diff --git a/include/Nazara/Math/Matrix4.hpp b/include/Nazara/Math/Matrix4.hpp index f2c0be4ca..ac0253acb 100644 --- a/include/Nazara/Math/Matrix4.hpp +++ b/include/Nazara/Math/Matrix4.hpp @@ -10,6 +10,7 @@ ///FIXME: Matrices column-major, difficile de bosser avec (Tout passer en row-major et transposer dans les shaders ?) #include +#include #include #include @@ -72,7 +73,7 @@ namespace Nz Matrix4& MakeIdentity(); Matrix4& MakeLookAt(const Vector3& eye, const Vector3& target, const Vector3& up = Vector3::Up()); Matrix4& MakeOrtho(T left, T right, T top, T bottom, T zNear = -1.0, T zFar = 1.0); - Matrix4& MakePerspective(T angle, T ratio, T zNear, T zFar); + Matrix4& MakePerspective(RadianAngle angle, T ratio, T zNear, T zFar); Matrix4& MakeRotation(const Quaternion& rotation); Matrix4& MakeScale(const Vector3& scale); Matrix4& MakeTranslation(const Vector3& translation); @@ -124,7 +125,7 @@ namespace Nz static Matrix4 Identity(); static Matrix4 LookAt(const Vector3& eye, const Vector3& target, const Vector3& up = Vector3::Up()); static Matrix4 Ortho(T left, T right, T top, T bottom, T zNear = -1.0, T zFar = 1.0); - static Matrix4 Perspective(T angle, T ratio, T zNear, T zFar); + static Matrix4 Perspective(RadianAngle angle, T ratio, T zNear, T zFar); static Matrix4 Rotate(const Quaternion& rotation); static Matrix4 Scale(const Vector3& scale); static Matrix4 Translate(const Vector3& translation); diff --git a/include/Nazara/Math/Matrix4.inl b/include/Nazara/Math/Matrix4.inl index e1482511c..ce0370d8c 100644 --- a/include/Nazara/Math/Matrix4.inl +++ b/include/Nazara/Math/Matrix4.inl @@ -903,7 +903,7 @@ namespace Nz * \brief Makes the matrix a 'perspective matrix' * \return A reference to this matrix transformed in 'perspective matrix' * - * \param angle Unit depends on NAZARA_MATH_ANGLE_RADIAN + * \param angle FOV angle * \param ratio Rendering ratio (typically 16/9 or 4/3) * \param zNear Distance where 'vision' begins * \param zFar Distance where 'vision' ends @@ -912,21 +912,17 @@ namespace Nz */ template - Matrix4& Matrix4::MakePerspective(T angle, T ratio, T zNear, T zFar) + Matrix4& Matrix4::MakePerspective(RadianAngle angle, T ratio, T zNear, T zFar) { - // http://msdn.microsoft.com/en-us/library/windows/desktop/bb204945(v=vs.85).aspx - #if NAZARA_MATH_ANGLE_RADIAN - angle /= T(2.0); - #else - angle = DegreeToRadian(angle / T(2.0)); - #endif + // https://docs.microsoft.com/fr-fr/windows/win32/direct3d10/d3d10-d3dxmatrixperspectivefovrh + angle = RadianAngle(M_PI_2) - angle / T(2.0); - T yScale = std::tan(static_cast(M_PI_2) - angle); + T yScale = angle.GetTan(); - Set(yScale / ratio, T(0.0), T(0.0), T(0.0), - T(0.0), yScale, T(0.0), T(0.0), - T(0.0), T(0.0), - (zFar + zNear) / (zFar - zNear), T(-1.0), - T(0.0), T(0.0), T(-2.0) * (zNear * zFar) / (zFar - zNear), T(0.0)); + Set(yScale / ratio, T(0.0), T(0.0), T(0.0), + T(0.0), yScale, T(0.0), T(0.0), + T(0.0), T(0.0), zFar / (zNear - zFar), T(-1.0), + T(0.0), T(0.0), zNear * zFar / (zNear - zFar), T(0.0)); return *this; } @@ -1598,7 +1594,7 @@ namespace Nz * \brief Shorthand for the 'perspective' matrix * \return A Matrix4 which is the 'perspective' matrix * - * \param angle Unit depends on NAZARA_MATH_ANGLE_RADIAN + * \param angle FOV angle * \param ratio Rendering ratio (typically 16/9 or 4/3) * \param zNear Distance where 'vision' begins * \param zFar Distance where 'vision' ends @@ -1607,7 +1603,7 @@ namespace Nz */ template - Matrix4 Matrix4::Perspective(T angle, T ratio, T zNear, T zFar) + Matrix4 Matrix4::Perspective(RadianAngle angle, T ratio, T zNear, T zFar) { Matrix4 matrix; matrix.MakePerspective(angle, ratio, zNear, zFar); diff --git a/include/Nazara/Math/Quaternion.hpp b/include/Nazara/Math/Quaternion.hpp index 96af1dbfd..c8f112d4f 100644 --- a/include/Nazara/Math/Quaternion.hpp +++ b/include/Nazara/Math/Quaternion.hpp @@ -24,7 +24,7 @@ namespace Nz Quaternion(T W, T X, T Y, T Z); template Quaternion(const Angle& angle); Quaternion(const EulerAngles& angles); - Quaternion(T angle, const Vector3& axis); + Quaternion(RadianAngle angle, const Vector3& axis); Quaternion(const T quat[4]); //Quaternion(const Matrix3& mat); template explicit Quaternion(const Quaternion& quat); @@ -53,7 +53,7 @@ namespace Nz Quaternion& Set(T W, T X, T Y, T Z); template Quaternion& Set(const Angle& angle); Quaternion& Set(const EulerAngles& angles); - Quaternion& Set(T angle, const Vector3& normalizedAxis); + Quaternion& Set(RadianAngle angle, const Vector3& normalizedAxis); Quaternion& Set(const T quat[4]); //Quaternion& Set(const Matrix3& mat); template Quaternion& Set(const Quaternion& quat); diff --git a/include/Nazara/Math/Quaternion.inl b/include/Nazara/Math/Quaternion.inl index abba22e7c..aa46bbd7c 100644 --- a/include/Nazara/Math/Quaternion.inl +++ b/include/Nazara/Math/Quaternion.inl @@ -66,12 +66,12 @@ namespace Nz /*! * \brief Constructs a Quaternion object from an angle and a direction * - * \param angle Unit depends of NAZARA_MATH_ANGLE_RADIAN + * \param angle Angle to rotate along the axis * \param axis Vector3 which represents a direction, no need to be normalized */ template - Quaternion::Quaternion(T angle, const Vector3& axis) + Quaternion::Quaternion(RadianAngle angle, const Vector3& axis) { Set(angle, axis); } @@ -386,27 +386,23 @@ namespace Nz * \brief Sets this quaternion from rotation specified by axis and angle * \return A reference to this quaternion * - * \param angle Unit depends of NAZARA_MATH_ANGLE_RADIAN + * \param angle Angle to rotate along the axis * \param axis Vector3 which represents a direction, no need to be normalized */ template - Quaternion& Quaternion::Set(T angle, const Vector3& axis) + Quaternion& Quaternion::Set(RadianAngle angle, const Vector3& axis) { - #if !NAZARA_MATH_ANGLE_RADIAN - angle = DegreeToRadian(angle); - #endif - angle /= T(2.0); Vector3 normalizedAxis = axis.GetNormal(); - T sinAngle = std::sin(angle); + auto sincos = angle.GetSinCos(); - w = std::cos(angle); - x = normalizedAxis.x * sinAngle; - y = normalizedAxis.y * sinAngle; - z = normalizedAxis.z * sinAngle; + w = sincos.second; + x = normalizedAxis.x * sincos.first; + y = normalizedAxis.y * sincos.first; + z = normalizedAxis.z * sincos.first; return Normalize(); } @@ -488,15 +484,15 @@ namespace Nz T test = x * y + z * w; if (test > T(0.499)) // singularity at north pole - return EulerAngles(T(0.0), FromRadians(T(2.0) * std::atan2(x, w)), FromDegrees(T(90.0))); + return EulerAngles(DegreeAngle(T(0.0)), RadianAngle(T(2.0) * std::atan2(x, w)), DegreeAngle(T(90.0))); if (test < T(-0.499)) // singularity at south pole - return EulerAngles(T(0.0), FromRadians(T(-2.0) * std::atan2(x, w)), FromDegrees(T(-90.0))); + return EulerAngles(DegreeAngle(T(0.0)), RadianAngle(T(-2.0) * std::atan2(x, w)), DegreeAngle(T(-90.0))); - return EulerAngles(FromRadians(std::atan2(T(2.0) * x * w - T(2.0) * y * z, T(1.0) - T(2.0) * x * x - T(2.0) * z * z)), - FromRadians(std::atan2(T(2.0) * y * w - T(2.0) * x * z, T(1.0) - T(2.0) * y * y - T(2.0) * z * z)), - FromRadians(std::asin(T(2.0) * test))); + return EulerAngles(RadianAngle(std::atan2(T(2.0) * x * w - T(2.0) * y * z, T(1.0) - T(2.0) * x * x - T(2.0) * z * z)), + RadianAngle(std::atan2(T(2.0) * y * w - T(2.0) * x * z, T(1.0) - T(2.0) * y * y - T(2.0) * z * z)), + RadianAngle(std::asin(T(2.0) * test))); } /*! diff --git a/include/Nazara/Math/Vector2.hpp b/include/Nazara/Math/Vector2.hpp index bc0d6c9fb..35136fc31 100644 --- a/include/Nazara/Math/Vector2.hpp +++ b/include/Nazara/Math/Vector2.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -33,7 +34,7 @@ namespace Nz ~Vector2() = default; T AbsDotProduct(const Vector2& vec) const; - T AngleBetween(const Vector2& vec) const; + RadianAngle AngleBetween(const Vector2& vec) const; template U Distance(const Vector2& vec) const; diff --git a/include/Nazara/Math/Vector2.inl b/include/Nazara/Math/Vector2.inl index 1ecb7cebf..d9dfe492a 100644 --- a/include/Nazara/Math/Vector2.inl +++ b/include/Nazara/Math/Vector2.inl @@ -97,7 +97,7 @@ namespace Nz /*! * \brief Calculates the angle between two vectors in orthonormal basis - * \return The angle unit depends of NAZARA_MATH_ANGLE_RADIAN, you may want to normalize it to the range 0..2*pi with NormalizeAngle + * \return The angle * * \param vec The other vector to measure the angle with * @@ -107,9 +107,9 @@ namespace Nz */ template - T Vector2::AngleBetween(const Vector2& vec) const + RadianAngle Vector2::AngleBetween(const Vector2& vec) const { - return FromRadians(std::atan2(vec.y, vec.x) - std::atan2(y, x)); + return std::atan2(vec.y, vec.x) - std::atan2(y, x); } /*! diff --git a/include/Nazara/Math/Vector3.hpp b/include/Nazara/Math/Vector3.hpp index 9f02cffd7..19777949e 100644 --- a/include/Nazara/Math/Vector3.hpp +++ b/include/Nazara/Math/Vector3.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -34,7 +35,7 @@ namespace Nz ~Vector3() = default; T AbsDotProduct(const Vector3& vec) const; - T AngleBetween(const Vector3& vec) const; + RadianAngle AngleBetween(const Vector3& vec) const; Vector3 CrossProduct(const Vector3& vec) const; diff --git a/include/Nazara/Math/Vector3.inl b/include/Nazara/Math/Vector3.inl index 5c73a33d0..245d0dd48 100644 --- a/include/Nazara/Math/Vector3.inl +++ b/include/Nazara/Math/Vector3.inl @@ -107,7 +107,7 @@ namespace Nz /*! * \brief Calculates the angle between two vectors in orthonormal basis - * \return The angle unit depends of NAZARA_MATH_ANGLE_RADIAN in the range 0..pi + * \return The angle * * \param vec The other vector to measure the angle with * @@ -118,7 +118,7 @@ namespace Nz * \see NormalizeAngle */ template - T Vector3::AngleBetween(const Vector3& vec) const + RadianAngle Vector3::AngleBetween(const Vector3& vec) const { // sqrt(a) * sqrt(b) = sqrt(a*b) T divisor = std::sqrt(GetSquaredLength() * vec.GetSquaredLength()); @@ -134,7 +134,7 @@ namespace Nz #endif T alpha = DotProduct(vec) / divisor; - return FromRadians(std::acos(Clamp(alpha, T(-1.0), T(1.0)))); + return std::acos(Clamp(alpha, T(-1.0), T(1.0))); } /*! diff --git a/include/Nazara/Network/Algorithm.hpp b/include/Nazara/Network/Algorithm.hpp index 1b28fb747..9f8140385 100644 --- a/include/Nazara/Network/Algorithm.hpp +++ b/include/Nazara/Network/Algorithm.hpp @@ -16,8 +16,8 @@ namespace Nz { - NAZARA_NETWORK_API const char* ErrorToString(Nz::ResolveError resolveError); - NAZARA_NETWORK_API const char* ErrorToString(Nz::SocketError socketError); + NAZARA_NETWORK_API const char* ErrorToString(ResolveError resolveError); + NAZARA_NETWORK_API const char* ErrorToString(SocketError socketError); NAZARA_NETWORK_API bool ParseIPAddress(const char* addressPtr, UInt8 result[16], UInt16* port = nullptr, bool* isIPv6 = nullptr, const char** endOfRead = nullptr); diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index bfac8fd1c..6e0924f31 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -51,7 +51,7 @@ namespace Nz bool CheckEvents(ENetEvent* event); ENetPeer* Connect(const IpAddress& remoteAddress, std::size_t channelCount = 0, UInt32 data = 0); - ENetPeer* Connect(const std::string& hostName, NetProtocol protocol = NetProtocol_Any, const std::string& service = "http", ResolveError* error = nullptr, std::size_t channelCount = 0, UInt32 data = 0); + ENetPeer* Connect(const std::string& hostName, NetProtocol protocol = NetProtocol::Any, const std::string& service = "http", ResolveError* error = nullptr, std::size_t channelCount = 0, UInt32 data = 0); inline bool Create(NetProtocol protocol, UInt16 port, std::size_t peerCount, std::size_t channelCount = 0); bool Create(const IpAddress& listenAddress, std::size_t peerCount, std::size_t channelCount = 0); diff --git a/include/Nazara/Network/ENetHost.inl b/include/Nazara/Network/ENetHost.inl index 283d55059..faacd5c16 100644 --- a/include/Nazara/Network/ENetHost.inl +++ b/include/Nazara/Network/ENetHost.inl @@ -29,23 +29,23 @@ namespace Nz inline bool ENetHost::Create(NetProtocol protocol, UInt16 port, std::size_t peerCount, std::size_t channelCount) { - NazaraAssert(protocol != NetProtocol_Unknown, "Invalid protocol"); + NazaraAssert(protocol != NetProtocol::Unknown, "Invalid protocol"); IpAddress any; switch (protocol) { - case NetProtocol_Unknown: + case NetProtocol::Unknown: NazaraInternalError("Invalid protocol"); return false; - case NetProtocol_IPv4: + case NetProtocol::IPv4: any = IpAddress::AnyIpV4; break; - case NetProtocol_Any: + case NetProtocol::Any: m_isUsingDualStack = true; // fallthrough - case NetProtocol_IPv6: + case NetProtocol::IPv6: any = IpAddress::AnyIpV6; break; } diff --git a/include/Nazara/Network/Enums.hpp b/include/Nazara/Network/Enums.hpp index 7a7348407..d7c6feb58 100644 --- a/include/Nazara/Network/Enums.hpp +++ b/include/Nazara/Network/Enums.hpp @@ -11,123 +11,114 @@ namespace Nz { - enum NetCode : UInt16 + enum class NetProtocol { - NetCode_Acknowledge = 0x9A4E, - NetCode_AcknowledgeConnection = 0xC108, - NetCode_Ping = 0x96AC, - NetCode_Pong = 0x974C, - NetCode_RequestConnection = 0xF27D, + Any, + IPv4, + IPv6, + Unknown, - NetCode_Invalid = 0x0000 + Max = Unknown }; - enum NetProtocol - { - NetProtocol_Any, - NetProtocol_IPv4, - NetProtocol_IPv6, - NetProtocol_Unknown, + constexpr std::size_t NetProtocolCount = static_cast(NetProtocol::Max) + 1; - NetProtocol_Max = NetProtocol_Unknown + enum class PacketReliability + { + Reliable, //< Packet will be resent if lost + ReliableOrdered, //< Packet will be resent if lost and will only arrive in order + Unreliable, //< Packet won't be resent if lost + + Max = Unreliable }; - enum PacketPriority - { - PacketPriority_High = 1, //< High-priority packet, will be sent quickly - PacketPriority_Immediate = 0, //< Immediate priority, will be sent immediately - PacketPriority_Medium = 2, //< Medium-priority packet, will be sent as regular - PacketPriority_Low = 3, //< Low-priority packet, may take some time to be sent + constexpr std::size_t PacketReliabilityCount = static_cast(PacketReliability::Max) + 1; - PacketPriority_Lowest = PacketPriority_Low, - PacketPriority_Highest = PacketPriority_Immediate, - PacketPriority_Max = PacketPriority_Low + enum class ResolveError + { + NoError, + + Internal, //< An internal error occurred + ResourceError, //< The operating system lacks the resources to proceed (insufficient memory) + NonRecoverable, //< An nonrecoverable error occurred + NotFound, //< No such host is known + NotInitialized, //< Nazara network has not been initialized + ProtocolNotSupported, //< A specified protocol is not supported by the server + TemporaryFailure, //< A temporary failure occurred, try again + Unknown, //< The last operation failed with an unlisted error code + + Max = Unknown }; - enum PacketReliability - { - PacketReliability_Reliable, //< Packet will be resent if lost - PacketReliability_ReliableOrdered, //< Packet will be resent if lost and will only arrive in order - PacketReliability_Unreliable, //< Packet won't be resent if lost + constexpr std::size_t ResolveErrorCount = static_cast(ResolveError::Max) + 1; - PacketReliability_Max = PacketReliability_Unreliable + enum class SocketError + { + NoError, + + AddressNotAvailable, //< The address is already in use (when binding/listening) + ConnectionClosed, //< The connection has been closed + ConnectionRefused, //< The connection attempt was refused + DatagramSize, //< The datagram size is over the system limit + Internal, //< The error is coming from the engine + Interrupted, //< The operation was interrupted by a signal + Packet, //< The packet encoding/decoding failed, probably because of corrupted data + NetworkError, //< The network system has failed (maybe network is down) + NotInitialized, //< Nazara network has not been initialized + NotSupported, //< The operation is not supported (e.g. creating a bluetooth socket on a system without any bluetooth adapter) + ResolveError, //< The hostname couldn't be resolved (more information in ResolveError code) + ResourceError, //< The operating system lacks the resources to proceed (e.g. memory/socket descriptor) + TimedOut, //< The operation timed out + Unknown, //< The last operation failed with an unlisted error code + UnreachableHost, //< The host is not reachable + + Max = UnreachableHost }; - enum ResolveError + constexpr std::size_t SocketErrorCount = static_cast(SocketError::Max) + 1; + + enum class SocketPollEvent { - ResolveError_NoError, + Read, //< One or more sockets is ready for a read operation + Write, //< One or more sockets is ready for a write operation - ResolveError_Internal, //< An internal error occurred - ResolveError_ResourceError, //< The operating system lacks the resources to proceed (insufficient memory) - ResolveError_NonRecoverable, //< An nonrecoverable error occurred - ResolveError_NotFound, //< No such host is known - ResolveError_NotInitialized, //< Nazara network has not been initialized - ResolveError_ProtocolNotSupported, //< A specified protocol is not supported by the server - ResolveError_TemporaryFailure, //< A temporary failure occurred, try again - ResolveError_Unknown, //< The last operation failed with an unlisted error code - - ResolveError_Max = ResolveError_Unknown + Max = Write }; - enum SocketError - { - SocketError_NoError, - - SocketError_AddressNotAvailable, //< The address is already in use (when binding/listening) - SocketError_ConnectionClosed, //< The connection has been closed - SocketError_ConnectionRefused, //< The connection attempt was refused - SocketError_DatagramSize, //< The datagram size is over the system limit - SocketError_Internal, //< The error is coming from the engine - SocketError_Interrupted, //< The operation was interrupted by a signal - SocketError_Packet, //< The packet encoding/decoding failed, probably because of corrupted data - SocketError_NetworkError, //< The network system has failed (maybe network is down) - SocketError_NotInitialized, //< Nazara network has not been initialized - SocketError_NotSupported, //< The operation is not supported (e.g. creating a bluetooth socket on a system without any bluetooth adapter) - SocketError_ResolveError, //< The hostname couldn't be resolved (more information in ResolveError code) - SocketError_ResourceError, //< The operating system lacks the resources to proceed (e.g. memory/socket descriptor) - SocketError_TimedOut, //< The operation timed out - SocketError_Unknown, //< The last operation failed with an unlisted error code - SocketError_UnreachableHost, //< The host is not reachable - - SocketError_Max = SocketError_UnreachableHost - }; - - enum SocketPollEvent - { - SocketPollEvent_Read, //< One or more sockets is ready for a read operation - SocketPollEvent_Write, //< One or more sockets is ready for a write operation - - SocketPollEvent_Max = SocketPollEvent_Write - }; + constexpr std::size_t SocketPollEventCount = static_cast(SocketPollEvent::Max) + 1; template<> struct EnumAsFlags { - static constexpr SocketPollEvent max = SocketPollEvent_Max; + static constexpr SocketPollEvent max = SocketPollEvent::Max; }; using SocketPollEventFlags = Flags; - enum SocketState + enum class SocketState { - SocketState_Bound, //< The socket is currently bound - SocketState_Connecting, //< The socket is currently connecting - SocketState_Connected, //< The socket is currently connected - SocketState_NotConnected, //< The socket is not connected (or has been disconnected) - SocketState_Resolving, //< The socket is currently resolving a host name + Bound, //< The socket is currently bound + Connecting, //< The socket is currently connecting + Connected, //< The socket is currently connected + NotConnected, //< The socket is not connected (or has been disconnected) + Resolving, //< The socket is currently resolving a host name - SocketState_Max = SocketState_Resolving + Max = Resolving }; - enum SocketType - { - SocketType_Raw, - SocketType_TCP, - SocketType_UDP, - SocketType_Unknown, + constexpr std::size_t SocketStateCount = static_cast(SocketState::Max) + 1; - SocketType_Max = SocketType_Unknown + enum class SocketType + { + Raw, + TCP, + UDP, + Unknown, + + Max = Unknown }; + + constexpr std::size_t SocketTypeCount = static_cast(SocketType::Max) + 1; } #endif // NAZARA_ENUMS_NETWORK_HPP diff --git a/include/Nazara/Network/IpAddress.inl b/include/Nazara/Network/IpAddress.inl index ee31cd405..4e822cc9f 100644 --- a/include/Nazara/Network/IpAddress.inl +++ b/include/Nazara/Network/IpAddress.inl @@ -27,7 +27,7 @@ namespace Nz inline IpAddress::IpAddress(const IPv4& ip, UInt16 port) : m_ipv4(ip), - m_protocol(NetProtocol_IPv4), + m_protocol(NetProtocol::IPv4), m_port(port), m_isValid(true) { @@ -42,7 +42,7 @@ namespace Nz inline IpAddress::IpAddress(const IPv6& ip, UInt16 port) : m_ipv6(ip), - m_protocol(NetProtocol_IPv6), + m_protocol(NetProtocol::IPv6), m_port(port), m_isValid(true) { @@ -149,7 +149,7 @@ namespace Nz inline IpAddress::IPv4 IpAddress::ToIPv4() const { - NazaraAssert(m_isValid && m_protocol == NetProtocol_IPv4, "Address is not a valid IPv4"); + NazaraAssert(m_isValid && m_protocol == NetProtocol::IPv4, "Address is not a valid IPv4"); return m_ipv4; } @@ -163,7 +163,7 @@ namespace Nz inline IpAddress::IPv6 IpAddress::ToIPv6() const { - NazaraAssert(m_isValid && m_protocol == NetProtocol_IPv6, "IP is not a valid IPv6"); + NazaraAssert(m_isValid && m_protocol == NetProtocol::IPv6, "IP is not a valid IPv6"); return m_ipv6; } @@ -177,7 +177,7 @@ namespace Nz inline UInt32 IpAddress::ToUInt32() const { - NazaraAssert(m_isValid && m_protocol == NetProtocol_IPv4, "Address is not a valid IPv4"); + NazaraAssert(m_isValid && m_protocol == NetProtocol::IPv4, "Address is not a valid IPv4"); return UInt32(m_ipv4[0]) << 24 | UInt32(m_ipv4[1]) << 16 | @@ -231,11 +231,11 @@ namespace Nz // Each protocol has its variables to compare switch (first.m_protocol) { - case NetProtocol_Any: - case NetProtocol_Unknown: + case NetProtocol::Any: + case NetProtocol::Unknown: break; - case NetProtocol_IPv4: + case NetProtocol::IPv4: { if (first.m_ipv4 != second.m_ipv4) return false; @@ -243,7 +243,7 @@ namespace Nz break; } - case NetProtocol_IPv6: + case NetProtocol::IPv6: { if (first.m_ipv6 != second.m_ipv6) return false; @@ -297,11 +297,11 @@ namespace Nz // Compare IP (thanks to std::array comparison operator) switch (first.m_protocol) { - case NetProtocol_Any: - case NetProtocol_Unknown: + case NetProtocol::Any: + case NetProtocol::Unknown: break; - case NetProtocol_IPv4: + case NetProtocol::IPv4: { if (first.m_ipv4 != second.m_ipv4) return first.m_ipv4 < second.m_ipv4; @@ -309,7 +309,7 @@ namespace Nz break; } - case NetProtocol_IPv6: + case NetProtocol::IPv6: { if (first.m_ipv6 != second.m_ipv6) return first.m_ipv6 < second.m_ipv6; @@ -387,16 +387,16 @@ namespace std std::size_t h = 0; switch (ip.GetProtocol()) { - case Nz::NetProtocol_Any: - case Nz::NetProtocol_Unknown: + case Nz::NetProtocol::Any: + case Nz::NetProtocol::Unknown: return std::numeric_limits::max(); - case Nz::NetProtocol_IPv4: + case Nz::NetProtocol::IPv4: { h = ip.ToUInt32() + (h << 6) + (h << 16) - h; break; } - case Nz::NetProtocol_IPv6: + case Nz::NetProtocol::IPv6: { Nz::IpAddress::IPv6 v6 = ip.ToIPv6(); for (std::size_t i = 0; i < v6.size(); i++) diff --git a/include/Nazara/Network/NetPacket.inl b/include/Nazara/Network/NetPacket.inl index abd75bd14..84ded62ab 100644 --- a/include/Nazara/Network/NetPacket.inl +++ b/include/Nazara/Network/NetPacket.inl @@ -12,9 +12,8 @@ namespace Nz /*! * \brief Constructs a NetPacket object by default */ - inline NetPacket::NetPacket() : - m_netCode(NetCode_Invalid) + m_netCode(0) { } @@ -156,7 +155,7 @@ namespace Nz inline void NetPacket::Reset(UInt16 netCode, const void* ptr, std::size_t size) { - InitStream(HeaderSize + size, HeaderSize, OpenMode_ReadOnly); + InitStream(HeaderSize + size, HeaderSize, OpenMode::ReadOnly); m_buffer->Resize(HeaderSize + size); if (ptr) diff --git a/include/Nazara/Network/RUdpConnection.hpp b/include/Nazara/Network/RUdpConnection.hpp deleted file mode 100644 index 4a8a19118..000000000 --- a/include/Nazara/Network/RUdpConnection.hpp +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Network module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_RUDPSERVER_HPP -#define NAZARA_RUDPSERVER_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Nz -{ - class NAZARA_NETWORK_API RUdpConnection - { - friend class Network; - - public: - using SequenceIndex = UInt16; - - RUdpConnection(); - RUdpConnection(const RUdpConnection&) = delete; - RUdpConnection(RUdpConnection&&) = default; - ~RUdpConnection() = default; - - inline void Close(); - - bool Connect(const IpAddress& remoteAddress); - bool Connect(const std::string& hostName, NetProtocol protocol = NetProtocol_Any, const std::string& service = "http", ResolveError* error = nullptr); - inline void Disconnect(); - - inline IpAddress GetBoundAddress() const; - inline UInt16 GetBoundPort() const; - inline SocketError GetLastError() const; - - inline bool Listen(NetProtocol protocol, UInt16 port = 64266); - bool Listen(const IpAddress& address); - - bool PollMessage(RUdpMessage* message); - - bool Send(const IpAddress& clientIp, PacketPriority priority, PacketReliability reliability, const NetPacket& packet); - - inline void SetProtocolId(UInt32 protocolId); - inline void SetTimeBeforeAck(UInt32 ms); - - inline void SimulateNetwork(double packetLoss); - - void Update(); - - RUdpConnection& operator=(const RUdpConnection&) = delete; - RUdpConnection& operator=(RUdpConnection&&) = default; - - static constexpr std::size_t MessageHeader = sizeof(UInt16) + 2 * sizeof(SequenceIndex) + sizeof(UInt32); //< Protocol ID (begin) + Sequence ID + Remote Sequence ID + Ack bitfield - static constexpr std::size_t MessageFooter = sizeof(UInt16); //< Protocol ID (end) - - // Signals: - NazaraSignal(OnConnectedToPeer, RUdpConnection* /*connection*/); - NazaraSignal(OnPeerAcknowledged, RUdpConnection* /*connection*/, const IpAddress& /*adress*/); - NazaraSignal(OnPeerConnection, RUdpConnection* /*connection*/, const IpAddress& /*adress*/); - NazaraSignal(OnPeerDisconnected, RUdpConnection* /*connection*/, const IpAddress& /*adress*/); - - private: - struct PeerData; - struct PendingAckPacket; - struct PendingPacket; - - enum PeerState - { - PeerState_Aknowledged, //< A connection request from this peer has been received, we're waiting for another packet to validate - PeerState_Connected, //< Connection is working in both-ways - PeerState_Connecting, //< A connection request has been made - PeerState_WillAck //< Connected, received one or more packets and has no packets to send, waiting before sending an empty ack packet - }; - - void DisconnectPeer(std::size_t peerIndex); - void EnqueuePacket(PeerData& peer, PacketPriority priority, PacketReliability reliability, const NetPacket& packet); - void EnqueuePacketInternal(PeerData& peer, PacketPriority priority, PacketReliability reliability, NetPacket&& data); - bool InitSocket(NetProtocol protocol); - void ProcessAcks(PeerData& peer, SequenceIndex lastAck, UInt32 ackBits); - PeerData& RegisterPeer(const IpAddress& address, PeerState state); - void OnClientRequestingConnection(const IpAddress& address, SequenceIndex sequenceId, UInt64 token); - void OnPacketLost(PeerData& peer, PendingAckPacket&& packet); - void OnPacketReceived(const IpAddress& peerIp, NetPacket&& packet); - void SendPacket(PeerData& peer, PendingPacket&& packet); - - static inline unsigned int ComputeSequenceDifference(SequenceIndex sequence, SequenceIndex sequence2); - static inline bool HasPendingPackets(PeerData& peer); - static bool Initialize(); - static inline bool IsAckMoreRecent(SequenceIndex ack, SequenceIndex ack2); - static inline bool IsReliable(PacketReliability reliability); - static void Uninitialize(); - - struct PendingPacket - { - PacketPriority priority; - PacketReliability reliability; - NetPacket data; - }; - - struct PendingAckPacket - { - PacketPriority priority; - PacketReliability reliability; - NetPacket data; - SequenceIndex sequenceId; - UInt64 timeSent; - }; - - struct PeerData //TODO: Move this to RUdpClient - { - PeerData() = default; - PeerData(PeerData&& other) = default; - PeerData& operator=(PeerData&& other) = default; - - std::array, PacketPriority_Max + 1> pendingPackets; - std::deque pendingAckQueue; - std::set receivedQueue; - std::size_t index; - PeerState state; - IpAddress address; - SequenceIndex localSequence; - SequenceIndex remoteSequence; - UInt32 roundTripTime; - UInt64 lastPacketTime; - UInt64 lastPingTime; - UInt64 stateData1; - }; - - std::bernoulli_distribution m_packetLossProbability; - std::queue m_receivedMessages; - std::size_t m_peerIterator; - std::unordered_map m_peerByIP; - std::vector m_peers; - Bitset m_activeClients; - Clock m_clock; - SocketError m_lastError; - UdpSocket m_socket; - UInt32 m_forceAckSendTime; - UInt32 m_pingInterval; - UInt32 m_protocol; - UInt32 m_timeBeforePing; - UInt32 m_timeBeforeTimeOut; - UInt64 m_currentTime; - bool m_isSimulationEnabled; - bool m_shouldAcceptConnections; - - static std::mt19937_64 s_randomGenerator; - }; -} - -#include - -#endif // NAZARA_RUDPSERVER_HPP diff --git a/include/Nazara/Network/RUdpConnection.inl b/include/Nazara/Network/RUdpConnection.inl deleted file mode 100644 index d1b1e0705..000000000 --- a/include/Nazara/Network/RUdpConnection.inl +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Network module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include - -namespace Nz -{ - /*! - * \brief Closes the connection - */ - - inline void RUdpConnection::Close() - { - m_socket.Close(); - } - - /*! - * \brief Disconnects the connection - * - * \see Close - */ - - inline void RUdpConnection::Disconnect() - { - Close(); - } - - /*! - * \brief Gets the bound address - * \return IpAddress we are linked to - */ - - inline IpAddress RUdpConnection::GetBoundAddress() const - { - return m_socket.GetBoundAddress(); - } - - /*! - * \brief Gets the port of the bound address - * \return Port we are linked to - */ - - inline UInt16 RUdpConnection::GetBoundPort() const - { - return m_socket.GetBoundPort(); - } - - /*! - * \brief Gets the last error - * \return Socket error - */ - - inline SocketError RUdpConnection::GetLastError() const - { - return m_lastError; - } - - /*! - * \brief Listens to a socket - * \return true If successfully bound - * - * \param protocol Net protocol to listen to - * \param port Port to listen to - * - * \remark Produces a NazaraAssert if protocol is unknown or any - */ - - inline bool RUdpConnection::Listen(NetProtocol protocol, UInt16 port) - { - NazaraAssert(protocol != NetProtocol_Any, "Any protocol not supported for Listen"); //< TODO - NazaraAssert(protocol != NetProtocol_Unknown, "Invalid protocol"); - - IpAddress any; - switch (protocol) - { - case NetProtocol_Any: - case NetProtocol_Unknown: - NazaraInternalError("Invalid protocol Any at this point"); - return false; - - case NetProtocol_IPv4: - any = IpAddress::AnyIpV4; - break; - - case NetProtocol_IPv6: - any = IpAddress::AnyIpV6; - break; - } - - any.SetPort(port); - return Listen(any); - } - - /*! - * \brief Sets the protocol id - * - * \param protocolId Protocol ID like NNet - */ - - inline void RUdpConnection::SetProtocolId(UInt32 protocolId) - { - m_protocol = protocolId; - } - - /*! - * \brief Sets the time before ack - * - * \param Time before acking to send many together (in ms) - */ - - inline void RUdpConnection::SetTimeBeforeAck(UInt32 ms) - { - m_forceAckSendTime = ms * 1000; //< Store in microseconds for easier handling - } - - /*! - * \brief Computes the difference of sequence - * \return Delta between the two sequences - * - * \param sequence First sequence - * \param sequence2 Second sequence - */ - - inline unsigned int RUdpConnection::ComputeSequenceDifference(SequenceIndex sequence, SequenceIndex sequence2) - { - unsigned int difference; - if (sequence2 > sequence) - difference = std::numeric_limits::max() - sequence2 + sequence; - else - difference = sequence - sequence2; - - return difference; - } - - /*! - * \brief Checks whether the peer has pending packets - * \return true If it is the case - * - * \param peer Data relative to the peer - */ - - inline bool RUdpConnection::HasPendingPackets(PeerData& peer) - { - for (unsigned int priority = PacketPriority_Highest; priority <= PacketPriority_Lowest; ++priority) - { - std::vector& pendingPackets = peer.pendingPackets[priority]; - if (!pendingPackets.empty()) - return true; - } - - return false; - } - - /*! - * \brief Checks whether the ack is more recent - * \return true If it is the case - * - * \param ack First sequence - * \param ack2 Second sequence - */ - - inline bool RUdpConnection::IsAckMoreRecent(SequenceIndex ack, SequenceIndex ack2) - { - constexpr SequenceIndex maxDifference = std::numeric_limits::max() / 2; - - if (ack > ack2) - return ack - ack2 <= maxDifference; - else if (ack2 > ack) - return ack2 - ack > maxDifference; - else - return false; ///< Same ack - } - - /*! - * \brief Checks whether the connection is reliable - * \return true If it is the case - * - * \remark Produces a NazaraError if enumeration is invalid - */ - - inline bool RUdpConnection::IsReliable(PacketReliability reliability) - { - switch (reliability) - { - case PacketReliability_Reliable: - case PacketReliability_ReliableOrdered: - return true; - - case PacketReliability_Unreliable: - return false; - } - - NazaraError("PacketReliability not handled (0x" + NumberToString(reliability, 16) + ')'); - return false; - } - - /*! - * \brief Simulates the loss of packets on network - * - * \param packetLoss Ratio of packet loss according to bernoulli distribution - * - * \remark Produces a NazaraAssert if packetLoss is not in between 0.0 and 1.0 - */ - - inline void RUdpConnection::SimulateNetwork(double packetLoss) - { - NazaraAssert(packetLoss >= 0.0 && packetLoss <= 1.0, "Packet loss must be in range [0..1]"); - - if (packetLoss > 0.0) - { - m_isSimulationEnabled = true; - m_packetLossProbability = std::bernoulli_distribution(packetLoss); - } - else - m_isSimulationEnabled = false; - } -} - -#include diff --git a/include/Nazara/Network/RUdpMessage.hpp b/include/Nazara/Network/RUdpMessage.hpp deleted file mode 100644 index ce1c57771..000000000 --- a/include/Nazara/Network/RUdpMessage.hpp +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Network module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_RUDMESSAGE_HPP -#define NAZARA_RUDMESSAGE_HPP - -#include -#include -#include - -namespace Nz -{ - struct RUdpMessage - { - IpAddress from; - NetPacket data; - }; -} - -#endif // NAZARA_RUDMESSAGE_HPP \ No newline at end of file diff --git a/include/Nazara/Network/TcpClient.hpp b/include/Nazara/Network/TcpClient.hpp index 6dc5ac4d2..235f4f76b 100644 --- a/include/Nazara/Network/TcpClient.hpp +++ b/include/Nazara/Network/TcpClient.hpp @@ -29,7 +29,7 @@ namespace Nz ~TcpClient() = default; SocketState Connect(const IpAddress& remoteAddress); - SocketState Connect(const std::string& hostName, NetProtocol protocol = NetProtocol_Any, const std::string& service = "http", ResolveError* error = nullptr); + SocketState Connect(const std::string& hostName, NetProtocol protocol = NetProtocol::Any, const std::string& service = "http", ResolveError* error = nullptr); inline void Disconnect(); void EnableLowDelay(bool lowDelay); diff --git a/include/Nazara/Network/TcpClient.inl b/include/Nazara/Network/TcpClient.inl index ca559e72f..a5fe2d64f 100644 --- a/include/Nazara/Network/TcpClient.inl +++ b/include/Nazara/Network/TcpClient.inl @@ -11,8 +11,8 @@ namespace Nz */ inline TcpClient::TcpClient() : - AbstractSocket(SocketType_TCP), - Stream(StreamOption_Sequential), + AbstractSocket(SocketType::TCP), + Stream(StreamOption::Sequential), m_keepAliveInterval(1000), //TODO: Query OS default value m_keepAliveTime(7'200'000), //TODO: Query OS default value m_isKeepAliveEnabled(false), //TODO: Query OS default value diff --git a/include/Nazara/Network/TcpServer.inl b/include/Nazara/Network/TcpServer.inl index 759ff0b80..02422ecec 100644 --- a/include/Nazara/Network/TcpServer.inl +++ b/include/Nazara/Network/TcpServer.inl @@ -12,7 +12,7 @@ namespace Nz */ inline TcpServer::TcpServer() : - AbstractSocket(SocketType_TCP) + AbstractSocket(SocketType::TCP) { } @@ -61,22 +61,22 @@ namespace Nz inline SocketState TcpServer::Listen(NetProtocol protocol, UInt16 port, unsigned int queueSize) { - NazaraAssert(protocol != NetProtocol_Any, "Any protocol not supported for Listen"); //< TODO - NazaraAssert(protocol != NetProtocol_Unknown, "Invalid protocol"); + NazaraAssert(protocol != NetProtocol::Any, "Any protocol not supported for Listen"); //< TODO + NazaraAssert(protocol != NetProtocol::Unknown, "Invalid protocol"); IpAddress any; switch (protocol) { - case NetProtocol_Any: - case NetProtocol_Unknown: + case NetProtocol::Any: + case NetProtocol::Unknown: NazaraInternalError("Invalid protocol Any at this point"); - return SocketState_NotConnected; + return SocketState::NotConnected; - case NetProtocol_IPv4: + case NetProtocol::IPv4: any = IpAddress::AnyIpV4; break; - case NetProtocol_IPv6: + case NetProtocol::IPv6: any = IpAddress::AnyIpV6; break; } diff --git a/include/Nazara/Network/UdpSocket.inl b/include/Nazara/Network/UdpSocket.inl index 93fe841cf..6380fb8be 100644 --- a/include/Nazara/Network/UdpSocket.inl +++ b/include/Nazara/Network/UdpSocket.inl @@ -11,7 +11,7 @@ namespace Nz */ inline UdpSocket::UdpSocket() : - AbstractSocket(SocketType_UDP) + AbstractSocket(SocketType::UDP) { } @@ -51,16 +51,16 @@ namespace Nz IpAddress any; switch (m_protocol) { - case NetProtocol_Unknown: + case NetProtocol::Unknown: NazaraInternalError("Invalid protocol"); - return SocketState_NotConnected; + return SocketState::NotConnected; - case NetProtocol_IPv4: + case NetProtocol::IPv4: any = IpAddress::AnyIpV4; break; - case NetProtocol_Any: - case NetProtocol_IPv6: + case NetProtocol::Any: + case NetProtocol::IPv6: any = IpAddress::AnyIpV6; break; } @@ -78,7 +78,7 @@ namespace Nz bool UdpSocket::Create(NetProtocol protocol) { - NazaraAssert(protocol != NetProtocol_Unknown, "Invalid protocol"); + NazaraAssert(protocol != NetProtocol::Unknown, "Invalid protocol"); return Open(protocol); } diff --git a/include/Nazara/OpenGLRenderer.hpp b/include/Nazara/OpenGLRenderer.hpp index f60b0ee85..da8bf0c08 100644 --- a/include/Nazara/OpenGLRenderer.hpp +++ b/include/Nazara/OpenGLRenderer.hpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -44,7 +45,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.hpp b/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.hpp index cc9ac019c..6e8e8fad1 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.hpp @@ -24,6 +24,7 @@ namespace Nz { class OpenGLCommandPool; class OpenGLFramebuffer; + class OpenGLRenderPass; class NAZARA_OPENGLRENDERER_API OpenGLCommandBuffer final : public CommandBuffer { @@ -55,7 +56,7 @@ namespace Nz inline std::size_t GetPoolIndex() const; inline const OpenGLCommandPool& GetOwner() const; - inline void SetFramebuffer(const OpenGLFramebuffer& framebuffer, const RenderPass& renderPass, std::initializer_list clearValues); + inline void SetFramebuffer(const OpenGLFramebuffer& framebuffer, const OpenGLRenderPass& renderPass, const CommandBufferBuilder::ClearValues* clearValues, std::size_t clearValueCount); inline void SetScissor(Nz::Recti scissorRegion); inline void SetViewport(Nz::Recti viewportRegion); @@ -103,9 +104,10 @@ namespace Nz const OpenGLRenderPipeline* pipeline = nullptr; const OpenGLShaderBinding* shaderBindings = nullptr; UInt64 indexBufferOffset; - std::optional scissorRegion; - std::optional viewportRegion; + std::optional scissorRegion; + std::optional viewportRegion; std::vector vertexBuffers; + bool shouldFlipY = false; }; struct DrawData @@ -132,7 +134,9 @@ namespace Nz struct SetFrameBufferData { + std::array clearValues; //< TODO: Remove hard limit? const OpenGLFramebuffer* framebuffer; + const OpenGLRenderPass* renderpass; }; using CommandData = std::variant< @@ -147,6 +151,7 @@ namespace Nz DrawStates m_currentStates; std::size_t m_bindingIndex; + std::size_t m_maxColorBufferCount; std::size_t m_poolIndex; std::vector m_commands; OpenGLCommandPool* m_owner; diff --git a/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.inl b/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.inl index bec54f598..334b6af1f 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.inl +++ b/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.inl @@ -11,12 +11,14 @@ namespace Nz { inline OpenGLCommandBuffer::OpenGLCommandBuffer() : + m_maxColorBufferCount(0), m_owner(nullptr) { } inline OpenGLCommandBuffer::OpenGLCommandBuffer(OpenGLCommandPool& owner, std::size_t poolIndex, std::size_t bindingIndex) : m_bindingIndex(bindingIndex), + m_maxColorBufferCount(0), m_poolIndex(poolIndex), m_owner(&owner) { @@ -133,12 +135,20 @@ namespace Nz return *m_owner; } - inline void OpenGLCommandBuffer::SetFramebuffer(const OpenGLFramebuffer& framebuffer, const RenderPass& /*renderPass*/, std::initializer_list clearValues) + inline void OpenGLCommandBuffer::SetFramebuffer(const OpenGLFramebuffer& framebuffer, const OpenGLRenderPass& renderPass, const CommandBufferBuilder::ClearValues* clearValues, std::size_t clearValueCount) { + m_maxColorBufferCount = std::max(m_maxColorBufferCount, framebuffer.GetColorBufferCount()); + SetFrameBufferData setFramebuffer; setFramebuffer.framebuffer = &framebuffer; + setFramebuffer.renderpass = &renderPass; + + assert(clearValueCount < setFramebuffer.clearValues.size()); + std::copy(clearValues, clearValues + clearValueCount, setFramebuffer.clearValues.begin()); m_commands.emplace_back(std::move(setFramebuffer)); + + m_currentStates.shouldFlipY = (framebuffer.GetType() == OpenGLFramebuffer::Type::Window); } inline void OpenGLCommandBuffer::SetScissor(Nz::Recti scissorRegion) diff --git a/include/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.hpp b/include/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.hpp index 14199c665..fc590989b 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.hpp @@ -24,7 +24,7 @@ namespace Nz ~OpenGLCommandBufferBuilder() = default; void BeginDebugRegion(const std::string_view& regionName, const Nz::Color& color) override; - void BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect, std::initializer_list clearValues) override; + void BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect, const ClearValues* clearValues, std::size_t clearValueCount) override; void BindIndexBuffer(AbstractBuffer* indexBuffer, UInt64 offset = 0) override; void BindPipeline(const RenderPipeline& pipeline) override; @@ -40,12 +40,16 @@ namespace Nz void EndDebugRegion() override; void EndRenderPass() override; + void NextSubpass() override; + void PreTransferBarrier() override; void PostTransferBarrier() override; void SetScissor(Nz::Recti scissorRegion) override; void SetViewport(Nz::Recti viewportRegion) override; + void TextureBarrier(PipelineStageFlags srcStageMask, PipelineStageFlags dstStageMask, MemoryAccessFlags srcAccessMask, MemoryAccessFlags dstAccessMask, TextureLayout oldLayout, TextureLayout newLayout, const Texture& texture) override; + OpenGLCommandBufferBuilder& operator=(const OpenGLCommandBufferBuilder&) = delete; OpenGLCommandBufferBuilder& operator=(OpenGLCommandBufferBuilder&&) = delete; diff --git a/include/Nazara/OpenGLRenderer/OpenGLDevice.hpp b/include/Nazara/OpenGLRenderer/OpenGLDevice.hpp index a75140840..9950dbe64 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLDevice.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLDevice.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -30,17 +31,24 @@ namespace Nz std::unique_ptr CreateContext(const GL::ContextParams& params) const; std::unique_ptr CreateContext(const GL::ContextParams& params, WindowHandle handle) const; + const RenderDeviceInfo& GetDeviceInfo() const override; inline const GL::Context& GetReferenceContext() const; std::shared_ptr InstantiateBuffer(BufferType type) override; std::shared_ptr InstantiateCommandPool(QueueType queueType) override; + std::shared_ptr InstantiateFramebuffer(unsigned int width, unsigned int height, const std::shared_ptr& renderPass, const std::vector>& attachments) override; + std::shared_ptr InstantiateRenderPass(std::vector attachments, std::vector subpassDescriptions, std::vector subpassDependencies) override; std::shared_ptr InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) override; std::shared_ptr InstantiateRenderPipelineLayout(RenderPipelineLayoutInfo pipelineLayoutInfo) override; - std::shared_ptr InstantiateShaderStage(ShaderStageType type, ShaderLanguage lang, const void* source, std::size_t sourceSize) override; + std::shared_ptr InstantiateShaderModule(ShaderStageTypeFlags shaderStages, ShaderAst::StatementPtr& shaderAst, const ShaderWriter::States& states) override; + std::shared_ptr InstantiateShaderModule(ShaderStageTypeFlags shaderStages, ShaderLanguage lang, const void* source, std::size_t sourceSize, const ShaderWriter::States& states) override; std::shared_ptr InstantiateTexture(const TextureInfo& params) override; std::shared_ptr InstantiateTextureSampler(const TextureSamplerInfo& params) override; + bool IsTextureFormatSupported(PixelFormat format, TextureUsage usage) const override; + inline void NotifyBufferDestruction(GLuint buffer) const; + inline void NotifyFramebufferDestruction(GLuint fbo) const; inline void NotifyProgramDestruction(GLuint program) const; inline void NotifySamplerDestruction(GLuint sampler) const; inline void NotifyTextureDestruction(GLuint texture) const; @@ -53,6 +61,7 @@ namespace Nz std::unique_ptr m_referenceContext; mutable std::unordered_set m_contexts; + RenderDeviceInfo m_deviceInfo; GL::Loader& m_loader; }; } diff --git a/include/Nazara/OpenGLRenderer/OpenGLDevice.inl b/include/Nazara/OpenGLRenderer/OpenGLDevice.inl index a9c823a7e..e995edbb9 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLDevice.inl +++ b/include/Nazara/OpenGLRenderer/OpenGLDevice.inl @@ -18,6 +18,12 @@ namespace Nz context->NotifyBufferDestruction(buffer); } + inline void OpenGLDevice::NotifyFramebufferDestruction(GLuint fbo) const + { + for (const GL::Context* context : m_contexts) + context->NotifyFramebufferDestruction(fbo); + } + inline void OpenGLDevice::NotifyProgramDestruction(GLuint program) const { for (const GL::Context* context : m_contexts) diff --git a/include/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.hpp b/include/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.hpp new file mode 100644 index 000000000..215012e04 --- /dev/null +++ b/include/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.hpp @@ -0,0 +1,45 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_OPENGLRENDERER_OPENGLFBOFRAMEBUFFER_HPP +#define NAZARA_OPENGLRENDERER_OPENGLFBOFRAMEBUFFER_HPP + +#include +#include +#include +#include +#include + +namespace Nz +{ + class OpenGLDevice; + class RenderPass; + class Texture; + + class NAZARA_OPENGLRENDERER_API OpenGLFboFramebuffer : public OpenGLFramebuffer + { + public: + OpenGLFboFramebuffer(OpenGLDevice& device, const std::vector>& attachments); + OpenGLFboFramebuffer(const OpenGLFboFramebuffer&) = delete; + OpenGLFboFramebuffer(OpenGLFboFramebuffer&&) noexcept = default; + ~OpenGLFboFramebuffer() = default; + + void Activate() const override; + + std::size_t GetColorBufferCount() const override; + + OpenGLFboFramebuffer& operator=(const OpenGLFboFramebuffer&) = delete; + OpenGLFboFramebuffer& operator=(OpenGLFboFramebuffer&&) = delete; + + private: + GL::Framebuffer m_framebuffer; + std::size_t m_colorAttachmentCount; + }; +} + +#include + +#endif diff --git a/include/Nazara/OpenGLRenderer/OpenGLShaderStage.inl b/include/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.inl similarity index 66% rename from include/Nazara/OpenGLRenderer/OpenGLShaderStage.inl rename to include/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.inl index 6d1ccb62f..c629eb72a 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLShaderStage.inl +++ b/include/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.inl @@ -2,15 +2,11 @@ // This file is part of the "Nazara Engine - OpenGL Renderer" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include namespace Nz { - inline const GL::Shader& OpenGLShaderStage::GetShader() const - { - return m_shader; - } } #include diff --git a/include/Nazara/OpenGLRenderer/OpenGLFramebuffer.hpp b/include/Nazara/OpenGLRenderer/OpenGLFramebuffer.hpp index d6bc34dee..e5228039b 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLFramebuffer.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLFramebuffer.hpp @@ -30,6 +30,8 @@ namespace Nz virtual void Activate() const = 0; + virtual std::size_t GetColorBufferCount() const = 0; + inline Type GetType() const; OpenGLFramebuffer& operator=(const OpenGLFramebuffer&) = delete; diff --git a/include/Nazara/OpenGLRenderer/OpenGLRenderImage.hpp b/include/Nazara/OpenGLRenderer/OpenGLRenderImage.hpp index 2c8507e7f..b9c4056cf 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLRenderImage.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLRenderImage.hpp @@ -29,10 +29,10 @@ namespace Nz OpenGLUploadPool& GetUploadPool() override; - void SubmitCommandBuffer(CommandBuffer* commandBuffer, QueueTypeFlags queueTypeFlags) override; - void Present() override; + void SubmitCommandBuffer(CommandBuffer* commandBuffer, QueueTypeFlags queueTypeFlags) override; + OpenGLRenderImage& operator=(const OpenGLRenderImage&) = delete; OpenGLRenderImage& operator=(OpenGLRenderImage&&) = delete; diff --git a/include/Nazara/OpenGLRenderer/OpenGLRenderPass.hpp b/include/Nazara/OpenGLRenderer/OpenGLRenderPass.hpp index 8c4ff18cd..d60870578 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLRenderPass.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLRenderPass.hpp @@ -17,7 +17,7 @@ namespace Nz class NAZARA_OPENGLRENDERER_API OpenGLRenderPass final : public RenderPass { public: - OpenGLRenderPass() = default; + using RenderPass::RenderPass; OpenGLRenderPass(const OpenGLRenderPass&) = delete; OpenGLRenderPass(OpenGLRenderPass&&) noexcept = default; ~OpenGLRenderPass() = default; diff --git a/include/Nazara/OpenGLRenderer/OpenGLRenderPipeline.hpp b/include/Nazara/OpenGLRenderer/OpenGLRenderPipeline.hpp index ddc6526af..fa3b227ee 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLRenderPipeline.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLRenderPipeline.hpp @@ -22,13 +22,15 @@ namespace Nz OpenGLRenderPipeline(OpenGLDevice& device, RenderPipelineInfo pipelineInfo); ~OpenGLRenderPipeline() = default; - void Apply(const GL::Context& context) const; + void Apply(const GL::Context& context, bool flipViewport) const; - inline const RenderPipelineInfo& GetPipelineInfo() const; + inline const RenderPipelineInfo& GetPipelineInfo() const override; private: RenderPipelineInfo m_pipelineInfo; GL::Program m_program; + GLint m_flipYUniformLocation; + mutable bool m_isViewportFlipped; }; } diff --git a/include/Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.hpp b/include/Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.hpp index 30ceb101c..0340f43ae 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.hpp @@ -52,9 +52,11 @@ namespace Nz void Release(ShaderBinding& binding); inline void TryToShrink(); + static constexpr UInt32 InvalidIndex = 0xFFFFFFFF; + struct TextureDescriptor { - UInt32 bindingIndex; + UInt32 bindingIndex = InvalidIndex; GLuint texture; GLuint sampler; GL::TextureTarget textureTarget; @@ -62,7 +64,7 @@ namespace Nz struct UniformBufferDescriptor { - UInt32 bindingIndex; + UInt32 bindingIndex = InvalidIndex; GLuint buffer; GLintptr offset; GLsizeiptr size; diff --git a/include/Nazara/OpenGLRenderer/OpenGLRenderWindow.hpp b/include/Nazara/OpenGLRenderer/OpenGLRenderWindow.hpp index 2a74d2ff8..01a62fd89 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLRenderWindow.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLRenderWindow.hpp @@ -37,16 +37,13 @@ namespace Nz const OpenGLFramebuffer& GetFramebuffer() const override; const OpenGLRenderPass& GetRenderPass() const override; - std::shared_ptr GetRenderDevice() override; - void Present(); private: + std::optional m_renderPass; std::size_t m_currentFrame; - std::shared_ptr m_device; - std::vector m_renderImage; + std::vector> m_renderImage; std::unique_ptr m_context; - OpenGLRenderPass m_renderPass; OpenGLWindowFramebuffer m_framebuffer; RenderWindow& m_owner; Vector2ui m_size; diff --git a/include/Nazara/OpenGLRenderer/OpenGLRenderer.hpp b/include/Nazara/OpenGLRenderer/OpenGLRenderer.hpp index 8a6570283..4ca7ee683 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLRenderer.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLRenderer.hpp @@ -19,7 +19,7 @@ namespace Nz class NAZARA_OPENGLRENDERER_API OpenGLRenderer : public RendererImpl { public: - OpenGLRenderer() = default; + OpenGLRenderer(); ~OpenGLRenderer(); std::unique_ptr CreateRenderSurfaceImpl() override; @@ -30,7 +30,7 @@ namespace Nz RenderAPI QueryAPI() const override; std::string QueryAPIString() const override; UInt32 QueryAPIVersion() const override; - std::vector QueryRenderDevices() const override; + const std::vector& QueryRenderDevices() const override; bool Prepare(const ParameterList& parameters) override; @@ -39,6 +39,7 @@ namespace Nz std::shared_ptr m_device; std::unique_ptr m_loader; + std::vector m_deviceInfos; }; } diff --git a/include/Nazara/OpenGLRenderer/OpenGLShaderBinding.hpp b/include/Nazara/OpenGLRenderer/OpenGLShaderBinding.hpp index 33fb89f40..dc7d144ef 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLShaderBinding.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLShaderBinding.hpp @@ -30,7 +30,7 @@ namespace Nz inline std::size_t GetPoolIndex() const; inline const OpenGLRenderPipelineLayout& GetOwner() const; - void Update(std::initializer_list bindings) override; + void Update(const Binding* bindings, std::size_t bindingCount) override; OpenGLShaderBinding& operator=(const OpenGLShaderBinding&) = delete; OpenGLShaderBinding& operator=(OpenGLShaderBinding&&) = delete; diff --git a/include/Nazara/OpenGLRenderer/OpenGLShaderModule.hpp b/include/Nazara/OpenGLRenderer/OpenGLShaderModule.hpp new file mode 100644 index 000000000..e39746eb0 --- /dev/null +++ b/include/Nazara/OpenGLRenderer/OpenGLShaderModule.hpp @@ -0,0 +1,53 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - OpenGL Renderer" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_OPENGLRENDERER_OPENGLSHADERMODULE_HPP +#define NAZARA_OPENGLRENDERER_OPENGLSHADERMODULE_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_OPENGLRENDERER_API OpenGLShaderModule : public ShaderModule + { + public: + struct Shader; + + OpenGLShaderModule(OpenGLDevice& device, ShaderStageTypeFlags shaderStages, ShaderAst::StatementPtr& shaderAst, const ShaderWriter::States& states = {}); + OpenGLShaderModule(OpenGLDevice& device, ShaderStageTypeFlags shaderStages, ShaderLanguage lang, const void* source, std::size_t sourceSize, const ShaderWriter::States& states = {}); + OpenGLShaderModule(const OpenGLShaderModule&) = delete; + OpenGLShaderModule(OpenGLShaderModule&&) noexcept = default; + ~OpenGLShaderModule() = default; + + inline const std::vector& GetShaders() const; + + OpenGLShaderModule& operator=(const OpenGLShaderModule&) = delete; + OpenGLShaderModule& operator=(OpenGLShaderModule&&) noexcept = default; + + struct Shader + { + ShaderStageType stage; + GL::Shader shader; + }; + + private: + void Create(OpenGLDevice& device, ShaderStageTypeFlags shaderStages, ShaderAst::StatementPtr& shaderAst, const ShaderWriter::States& states); + + static void CheckCompilationStatus(GL::Shader& shader); + + std::vector m_shaders; + }; +} + +#include + +#endif // NAZARA_OPENGLRENDERER_OPENGLSHADERSTAGE_HPP diff --git a/include/Nazara/OpenGLRenderer/OpenGLShaderModule.inl b/include/Nazara/OpenGLRenderer/OpenGLShaderModule.inl new file mode 100644 index 000000000..afc50af68 --- /dev/null +++ b/include/Nazara/OpenGLRenderer/OpenGLShaderModule.inl @@ -0,0 +1,16 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - OpenGL Renderer" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + inline auto OpenGLShaderModule::GetShaders() const -> const std::vector& + { + return m_shaders; + } +} + +#include diff --git a/include/Nazara/OpenGLRenderer/OpenGLShaderStage.hpp b/include/Nazara/OpenGLRenderer/OpenGLShaderStage.hpp deleted file mode 100644 index 8768befb7..000000000 --- a/include/Nazara/OpenGLRenderer/OpenGLShaderStage.hpp +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - OpenGL Renderer" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_OPENGLRENDERER_OPENGLSHADERSTAGE_HPP -#define NAZARA_OPENGLRENDERER_OPENGLSHADERSTAGE_HPP - -#include -#include -#include -#include -#include -#include - -namespace Nz -{ - class NAZARA_OPENGLRENDERER_API OpenGLShaderStage : public ShaderStageImpl - { - public: - OpenGLShaderStage(OpenGLDevice& device, ShaderStageType type, ShaderLanguage lang, const void* source, std::size_t sourceSize); - OpenGLShaderStage(const OpenGLShaderStage&) = delete; - OpenGLShaderStage(OpenGLShaderStage&&) noexcept = default; - ~OpenGLShaderStage() = default; - - inline const GL::Shader& GetShader() const; - - OpenGLShaderStage& operator=(const OpenGLShaderStage&) = delete; - OpenGLShaderStage& operator=(OpenGLShaderStage&&) noexcept = default; - - private: - GL::Shader m_shader; - }; -} - -#include - -#endif // NAZARA_OPENGLRENDERER_OPENGLSHADERSTAGE_HPP diff --git a/include/Nazara/OpenGLRenderer/OpenGLTexture.hpp b/include/Nazara/OpenGLRenderer/OpenGLTexture.hpp index d3d66cb12..0b97585a8 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLTexture.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLTexture.hpp @@ -34,6 +34,8 @@ namespace Nz OpenGLTexture& operator=(const OpenGLTexture&) = delete; OpenGLTexture& operator=(OpenGLTexture&&) = delete; + static inline GL::TextureTarget ToTextureTarget(ImageType imageType); + private: GL::Texture m_texture; TextureInfo m_params; diff --git a/include/Nazara/OpenGLRenderer/OpenGLTexture.inl b/include/Nazara/OpenGLRenderer/OpenGLTexture.inl index a9c2cfec4..85a41a988 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLTexture.inl +++ b/include/Nazara/OpenGLRenderer/OpenGLTexture.inl @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include namespace Nz @@ -11,6 +12,22 @@ namespace Nz { return m_texture; } + + inline GL::TextureTarget OpenGLTexture::ToTextureTarget(ImageType imageType) + { + switch (imageType) + { + case ImageType::E2D: return GL::TextureTarget::Target2D; + case ImageType::E2D_Array: return GL::TextureTarget::Target2D_Array; + case ImageType::E3D: return GL::TextureTarget::Target3D; + case ImageType::Cubemap: return GL::TextureTarget::Cubemap; + + case ImageType::E1D: + case ImageType::E1D_Array: + default: + throw std::runtime_error("unsupported texture type"); + } + } } #include diff --git a/include/Nazara/OpenGLRenderer/OpenGLUploadPool.hpp b/include/Nazara/OpenGLRenderer/OpenGLUploadPool.hpp index cd7a71db3..6147bd970 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLUploadPool.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLUploadPool.hpp @@ -11,7 +11,8 @@ #include #include #include -#include +#include +#include #include namespace Nz @@ -33,14 +34,20 @@ namespace Nz OpenGLUploadPool& operator=(OpenGLUploadPool&&) = delete; private: + static constexpr std::size_t AllocationPerBlock = 2048; + + using AllocationBlock = std::array; + struct Block { std::vector memory; UInt64 freeOffset = 0; + UInt64 size; }; + std::size_t m_nextAllocationIndex; + std::vector> m_allocationBlocks; std::vector m_blocks; - std::vector m_allocations; UInt64 m_blockSize; }; } diff --git a/include/Nazara/OpenGLRenderer/OpenGLUploadPool.inl b/include/Nazara/OpenGLRenderer/OpenGLUploadPool.inl index afb35ba5f..2eb508b5b 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLUploadPool.inl +++ b/include/Nazara/OpenGLRenderer/OpenGLUploadPool.inl @@ -8,7 +8,8 @@ namespace Nz { inline OpenGLUploadPool::OpenGLUploadPool(UInt64 blockSize) : - m_blockSize(blockSize) + m_blockSize(blockSize), + m_nextAllocationIndex(0) { } } diff --git a/include/Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.hpp b/include/Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.hpp index 0e702f98c..e97c66ff4 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.hpp @@ -24,6 +24,8 @@ namespace Nz void Activate() const override; + std::size_t GetColorBufferCount() const override; + OpenGLWindowFramebuffer& operator=(const OpenGLWindowFramebuffer&) = delete; OpenGLWindowFramebuffer& operator=(OpenGLWindowFramebuffer&&) = delete; @@ -34,4 +36,4 @@ namespace Nz #include -#endif // NAZARA_OPENGLRENDERER_OpenGLWindowFramebuffer_HPP +#endif diff --git a/include/Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.inl b/include/Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.inl index 9549a0467..033d596da 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.inl +++ b/include/Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.inl @@ -2,7 +2,7 @@ // This file is part of the "Nazara Engine - OpenGL Renderer" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include namespace Nz diff --git a/include/Nazara/OpenGLRenderer/Utils.hpp b/include/Nazara/OpenGLRenderer/Utils.hpp index 8c28d2419..a51cafc93 100644 --- a/include/Nazara/OpenGLRenderer/Utils.hpp +++ b/include/Nazara/OpenGLRenderer/Utils.hpp @@ -29,8 +29,11 @@ namespace Nz inline std::optional DescribeTextureFormat(PixelFormat pixelFormat); + inline GLenum ToOpenGL(BlendEquation blendEquation); inline GLenum ToOpenGL(BlendFunc blendFunc); - inline GLenum ToOpenGL(FaceSide filter); + inline GLenum ToOpenGL(FaceSide side); + inline GLenum ToOpenGL(FrontFace face); + inline GLenum ToOpenGL(PrimitiveMode primitiveMode); inline GLenum ToOpenGL(SamplerFilter filter); inline GLenum ToOpenGL(SamplerFilter minFilter, SamplerMipmapMode mipmapFilter); inline GLenum ToOpenGL(SamplerWrap wrapMode); diff --git a/include/Nazara/OpenGLRenderer/Utils.inl b/include/Nazara/OpenGLRenderer/Utils.inl index bd44b5e13..a9585d88a 100644 --- a/include/Nazara/OpenGLRenderer/Utils.inl +++ b/include/Nazara/OpenGLRenderer/Utils.inl @@ -12,11 +12,23 @@ namespace Nz { inline std::optional DescribeTextureFormat(PixelFormat pixelFormat) { + // TODO: Fill this switch switch (pixelFormat) { - case PixelFormat_A8: return GLTextureFormat { GL_R8, GL_RED, GL_UNSIGNED_BYTE, GL_ZERO, GL_ZERO, GL_ZERO, GL_RED }; - case PixelFormat_RGB8: return GLTextureFormat { GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE, GL_RED, GL_GREEN, GL_BLUE, GL_ZERO }; - case PixelFormat_RGBA8: return GLTextureFormat { GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA }; + case PixelFormat::A8: return GLTextureFormat{ GL_R8, GL_RED, GL_UNSIGNED_BYTE, GL_ZERO, GL_ZERO, GL_ZERO, GL_RED }; + case PixelFormat::BGR8: return GLTextureFormat{ GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, GL_BLUE, GL_GREEN, GL_RED, GL_ONE }; + case PixelFormat::BGR8_SRGB: return GLTextureFormat{ GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE, GL_BLUE, GL_GREEN, GL_RED, GL_ONE }; + case PixelFormat::BGRA8: return GLTextureFormat{ GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA }; + case PixelFormat::BGRA8_SRGB: return GLTextureFormat{ GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA }; + case PixelFormat::Depth16: return GLTextureFormat{ GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, GL_RED, GL_ZERO, GL_ZERO, GL_ZERO }; + case PixelFormat::Depth24Stencil8: return GLTextureFormat{ GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, GL_RED, GL_GREEN, GL_ZERO, GL_ZERO }; + case PixelFormat::Depth32F: return GLTextureFormat{ GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, GL_RED, GL_ZERO, GL_ZERO, GL_ZERO }; + case PixelFormat::Depth32FStencil8: return GLTextureFormat{ GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, GL_RED, GL_GREEN, GL_ZERO, GL_ZERO }; + case PixelFormat::RGB8: return GLTextureFormat{ GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, GL_RED, GL_GREEN, GL_BLUE, GL_ONE }; + case PixelFormat::RGB8_SRGB: return GLTextureFormat{ GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE, GL_RED, GL_GREEN, GL_BLUE, GL_ONE }; + case PixelFormat::RGBA8: return GLTextureFormat{ GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA }; + case PixelFormat::RGBA8_SRGB: return GLTextureFormat{ GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA }; + case PixelFormat::RGBA32F: return GLTextureFormat{ GL_RGBA32F, GL_RGBA, GL_FLOAT, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA }; default: break; } @@ -24,39 +36,86 @@ namespace Nz return {}; } + inline GLenum ToOpenGL(BlendEquation blendEquation) + { + switch (blendEquation) + { + case BlendEquation::Add: return GL_FUNC_ADD; + case BlendEquation::Max: return GL_MAX; + case BlendEquation::Min: return GL_MIN; + case BlendEquation::ReverseSubtract: return GL_FUNC_REVERSE_SUBTRACT; + case BlendEquation::Subtract: return GL_FUNC_SUBTRACT; + } + + NazaraError("Unhandled BlendEquation 0x" + NumberToString(UnderlyingCast(blendEquation), 16)); + return {}; + } + inline GLenum ToOpenGL(BlendFunc blendFunc) { switch (blendFunc) { - case BlendFunc_DestAlpha: return GL_DST_ALPHA; - case BlendFunc_DestColor: return GL_DST_COLOR; - case BlendFunc_SrcAlpha: return GL_SRC_ALPHA; - case BlendFunc_SrcColor: return GL_SRC_COLOR; - case BlendFunc_InvDestAlpha: return GL_ONE_MINUS_DST_ALPHA; - case BlendFunc_InvDestColor: return GL_ONE_MINUS_DST_COLOR; - case BlendFunc_InvSrcAlpha: return GL_ONE_MINUS_SRC_ALPHA; - case BlendFunc_InvSrcColor: return GL_ONE_MINUS_SRC_COLOR; - case BlendFunc_One: return GL_ONE; - case BlendFunc_Zero: return GL_ZERO; + case BlendFunc::ConstantAlpha: return GL_CONSTANT_ALPHA; + case BlendFunc::ConstantColor: return GL_CONSTANT_COLOR; + case BlendFunc::DstAlpha: return GL_DST_ALPHA; + case BlendFunc::DstColor: return GL_DST_COLOR; + case BlendFunc::InvConstantAlpha: return GL_ONE_MINUS_CONSTANT_ALPHA; + case BlendFunc::InvConstantColor: return GL_ONE_MINUS_CONSTANT_COLOR; + case BlendFunc::InvDstAlpha: return GL_ONE_MINUS_DST_ALPHA; + case BlendFunc::InvDstColor: return GL_ONE_MINUS_DST_COLOR; + case BlendFunc::InvSrcAlpha: return GL_ONE_MINUS_SRC_ALPHA; + case BlendFunc::InvSrcColor: return GL_ONE_MINUS_SRC_COLOR; + case BlendFunc::SrcAlpha: return GL_SRC_ALPHA; + case BlendFunc::SrcColor: return GL_SRC_COLOR; + case BlendFunc::One: return GL_ONE; + case BlendFunc::Zero: return GL_ZERO; } NazaraError("Unhandled BlendFunc 0x" + NumberToString(UnderlyingCast(blendFunc), 16)); return {}; } - inline GLenum ToOpenGL(FaceSide filter) + inline GLenum ToOpenGL(FaceSide side) { - switch (filter) + switch (side) { - case FaceSide_None: + case FaceSide::None: break; - case FaceSide_Back: return GL_BACK; - case FaceSide_Front: return GL_FRONT; - case FaceSide_FrontAndBack: return GL_FRONT_AND_BACK; + case FaceSide::Back: return GL_BACK; + case FaceSide::Front: return GL_FRONT; + case FaceSide::FrontAndBack: return GL_FRONT_AND_BACK; } - NazaraError("Unhandled FaceSide 0x" + NumberToString(UnderlyingCast(filter), 16)); + NazaraError("Unhandled FaceSide 0x" + NumberToString(UnderlyingCast(side), 16)); + return {}; + } + + inline GLenum ToOpenGL(FrontFace face) + { + switch (face) + { + case FrontFace::Clockwise: return GL_CW; + case FrontFace::CounterClockwise: return GL_CCW; + } + + NazaraError("Unhandled FrontFace 0x" + NumberToString(UnderlyingCast(face), 16)); + return {}; + } + + inline GLenum ToOpenGL(PrimitiveMode primitiveMode) + { + switch (primitiveMode) + { + case PrimitiveMode::LineList: return GL_LINES; + case PrimitiveMode::LineStrip: return GL_LINE_STRIP; + case PrimitiveMode::PointList: return GL_POINTS; + case PrimitiveMode::TriangleList: return GL_TRIANGLES; + case PrimitiveMode::TriangleStrip: return GL_TRIANGLE_STRIP; + case PrimitiveMode::TriangleFan: return GL_TRIANGLE_FAN; + } + + NazaraError("Unhandled PrimitiveMode 0x" + NumberToString(UnderlyingCast(primitiveMode), 16)); return {}; } @@ -64,14 +123,14 @@ namespace Nz { switch (comparison) { - case RendererComparison_Always: return GL_ALWAYS; - case RendererComparison_Equal: return GL_EQUAL; - case RendererComparison_Greater: return GL_GREATER; - case RendererComparison_GreaterOrEqual: return GL_GEQUAL; - case RendererComparison_Less: return GL_LESS; - case RendererComparison_LessOrEqual: return GL_LEQUAL; - case RendererComparison_Never: return GL_NEVER; - case RendererComparison_NotEqual: return GL_NOTEQUAL; + case RendererComparison::Always: return GL_ALWAYS; + case RendererComparison::Equal: return GL_EQUAL; + case RendererComparison::Greater: return GL_GREATER; + case RendererComparison::GreaterOrEqual: return GL_GEQUAL; + case RendererComparison::Less: return GL_LESS; + case RendererComparison::LessOrEqual: return GL_LEQUAL; + case RendererComparison::Never: return GL_NEVER; + case RendererComparison::NotEqual: return GL_NOTEQUAL; } NazaraError("Unhandled RendererComparison 0x" + NumberToString(UnderlyingCast(comparison), 16)); @@ -82,8 +141,8 @@ namespace Nz { switch (filter) { - case SamplerFilter::SamplerFilter_Linear: return GL_LINEAR; - case SamplerFilter::SamplerFilter_Nearest: return GL_NEAREST; + case SamplerFilter::Linear: return GL_LINEAR; + case SamplerFilter::Nearest: return GL_NEAREST; } NazaraError("Unhandled SamplerFilter 0x" + NumberToString(UnderlyingCast(filter), 16)); @@ -94,24 +153,24 @@ namespace Nz { switch (minFilter) { - case SamplerFilter::SamplerFilter_Linear: + case SamplerFilter::Linear: { switch (mipmapFilter) { - case SamplerMipmapMode_Linear: return GL_LINEAR_MIPMAP_LINEAR; - case SamplerMipmapMode_Nearest: return GL_LINEAR_MIPMAP_NEAREST; + case SamplerMipmapMode::Linear: return GL_LINEAR_MIPMAP_LINEAR; + case SamplerMipmapMode::Nearest: return GL_LINEAR_MIPMAP_NEAREST; } NazaraError("Unhandled SamplerFilter 0x" + NumberToString(UnderlyingCast(mipmapFilter), 16)); return {}; } - case SamplerFilter::SamplerFilter_Nearest: + case SamplerFilter::Nearest: { switch (mipmapFilter) { - case SamplerMipmapMode_Linear: return GL_NEAREST_MIPMAP_LINEAR; - case SamplerMipmapMode_Nearest: return GL_NEAREST_MIPMAP_NEAREST; + case SamplerMipmapMode::Linear: return GL_NEAREST_MIPMAP_LINEAR; + case SamplerMipmapMode::Nearest: return GL_NEAREST_MIPMAP_NEAREST; } NazaraError("Unhandled SamplerFilter 0x" + NumberToString(UnderlyingCast(mipmapFilter), 16)); @@ -127,9 +186,9 @@ namespace Nz { switch (wrapMode) { - case SamplerWrap::SamplerWrap_Clamp: return GL_CLAMP_TO_EDGE; - case SamplerWrap::SamplerWrap_MirroredRepeat: return GL_MIRRORED_REPEAT; - case SamplerWrap::SamplerWrap_Repeat: return GL_REPEAT; + case SamplerWrap::Clamp: return GL_CLAMP_TO_EDGE; + case SamplerWrap::MirroredRepeat: return GL_MIRRORED_REPEAT; + case SamplerWrap::Repeat: return GL_REPEAT; } NazaraError("Unhandled SamplerWrap 0x" + NumberToString(UnderlyingCast(wrapMode), 16)); @@ -152,14 +211,14 @@ namespace Nz { switch (stencilOp) { - case StencilOperation_Decrement: return GL_DECR; - case StencilOperation_DecrementNoClamp: return GL_DECR_WRAP; - case StencilOperation_Increment: return GL_INCR; - case StencilOperation_IncrementNoClamp: return GL_INCR_WRAP; - case StencilOperation_Invert: return GL_INVERT; - case StencilOperation_Keep: return GL_KEEP; - case StencilOperation_Replace: return GL_REPLACE; - case StencilOperation_Zero: return GL_ZERO; + case StencilOperation::Decrement: return GL_DECR; + case StencilOperation::DecrementNoClamp: return GL_DECR_WRAP; + case StencilOperation::Increment: return GL_INCR; + case StencilOperation::IncrementNoClamp: return GL_INCR_WRAP; + case StencilOperation::Invert: return GL_INVERT; + case StencilOperation::Keep: return GL_KEEP; + case StencilOperation::Replace: return GL_REPLACE; + case StencilOperation::Zero: return GL_ZERO; } NazaraError("Unhandled StencilOperation 0x" + NumberToString(UnderlyingCast(stencilOp), 16)); @@ -188,10 +247,16 @@ namespace Nz { switch (textureTarget) { - case GL::TextureTarget::Cubemap: return GL_TEXTURE_CUBE_MAP; - case GL::TextureTarget::Target2D: return GL_TEXTURE_2D; - case GL::TextureTarget::Target2D_Array: return GL_TEXTURE_2D_ARRAY; - case GL::TextureTarget::Target3D: return GL_TEXTURE_3D; + case GL::TextureTarget::Cubemap: return GL_TEXTURE_CUBE_MAP; + case GL::TextureTarget::CubemapNegativeX: return GL_TEXTURE_CUBE_MAP_NEGATIVE_X; + case GL::TextureTarget::CubemapNegativeY: return GL_TEXTURE_CUBE_MAP_NEGATIVE_Y; + case GL::TextureTarget::CubemapNegativeZ: return GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; + case GL::TextureTarget::CubemapPositiveX: return GL_TEXTURE_CUBE_MAP_POSITIVE_X; + case GL::TextureTarget::CubemapPositiveY: return GL_TEXTURE_CUBE_MAP_POSITIVE_Y; + case GL::TextureTarget::CubemapPositiveZ: return GL_TEXTURE_CUBE_MAP_POSITIVE_Z; + case GL::TextureTarget::Target2D: return GL_TEXTURE_2D; + case GL::TextureTarget::Target2D_Array: return GL_TEXTURE_2D_ARRAY; + case GL::TextureTarget::Target3D: return GL_TEXTURE_3D; } NazaraError("Unhandled GL::TextureTarget 0x" + NumberToString(UnderlyingCast(textureTarget), 16)); diff --git a/include/Nazara/OpenGLRenderer/Wrapper.hpp b/include/Nazara/OpenGLRenderer/Wrapper.hpp new file mode 100644 index 000000000..dd2753244 --- /dev/null +++ b/include/Nazara/OpenGLRenderer/Wrapper.hpp @@ -0,0 +1,21 @@ +// This file was automatically generated + +#pragma once + +#ifndef NAZARA_GLOBAL_OPENGLRENDERER_WRAPPER_HPP +#define NAZARA_GLOBAL_OPENGLRENDERER_WRAPPER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // NAZARA_GLOBAL_OPENGLRENDERER_WRAPPER_HPP diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp b/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp index 4f95b5c21..29ed1227d 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp +++ b/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp @@ -49,6 +49,7 @@ namespace Nz::GL enum class Extension { SpirV, + TextureCompressionS3tc, TextureFilterAnisotropic, Max = TextureFilterAnisotropic @@ -72,6 +73,12 @@ namespace Nz::GL enum class TextureTarget { Cubemap, + CubemapNegativeX, + CubemapNegativeY, + CubemapNegativeZ, + CubemapPositiveX, + CubemapPositiveY, + CubemapPositiveZ, Target2D, Target2D_Array, Target3D, @@ -126,6 +133,7 @@ namespace Nz::GL bool Initialize(const ContextParams& params); inline void NotifyBufferDestruction(GLuint buffer) const; + inline void NotifyFramebufferDestruction(GLuint fbo) const; inline void NotifyProgramDestruction(GLuint program) const; inline void NotifySamplerDestruction(GLuint sampler) const; inline void NotifyTextureDestruction(GLuint texture) const; @@ -133,13 +141,17 @@ namespace Nz::GL bool ProcessErrorStack() const; + inline void ResetColorWriteMasks() const; + inline void ResetDepthWriteMasks() const; + inline void ResetStencilWriteMasks() const; + void SetCurrentTextureUnit(UInt32 textureUnit) const; void SetScissorBox(GLint x, GLint y, GLsizei width, GLsizei height) const; void SetViewport(GLint x, GLint y, GLsizei width, GLsizei height) const; virtual void SwapBuffers() = 0; - void UpdateStates(const RenderStates& renderStates) const; + void UpdateStates(const RenderStates& renderStates, bool isViewportFlipped) const; #define NAZARA_OPENGLRENDERER_FUNC(name, sig) sig name = nullptr; NAZARA_OPENGLRENDERER_FOREACH_GLES_FUNC(NAZARA_OPENGLRENDERER_FUNC, NAZARA_OPENGLRENDERER_FUNC) diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Context.inl b/include/Nazara/OpenGLRenderer/Wrapper/Context.inl index 8c675cea7..6b27ce8f3 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Context.inl +++ b/include/Nazara/OpenGLRenderer/Wrapper/Context.inl @@ -58,6 +58,15 @@ namespace Nz::GL } } + inline void Context::NotifyFramebufferDestruction(GLuint fbo) const + { + if (m_state.boundDrawFBO == fbo) + m_state.boundDrawFBO = 0; + + if (m_state.boundReadFBO == fbo) + m_state.boundReadFBO = 0; + } + inline void Context::NotifyProgramDestruction(GLuint program) const { if (m_state.boundProgram == program) @@ -90,6 +99,35 @@ namespace Nz::GL if (m_state.boundVertexArray == vao) m_state.boundVertexArray = 0; } + + inline void Context::ResetColorWriteMasks() const + { + if (!m_state.renderStates.colorWrite) + { + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + m_state.renderStates.colorWrite = true; + } + } + + inline void Context::ResetDepthWriteMasks() const + { + if (!m_state.renderStates.depthWrite) + { + glDepthMask(GL_TRUE); + m_state.renderStates.depthWrite = true; + } + } + + inline void Context::ResetStencilWriteMasks() const + { + if (m_state.renderStates.stencilBack.writeMask != 0xFFFFFFFF || m_state.renderStates.stencilFront.writeMask != 0xFFFFFFFF) + { + glStencilMaskSeparate(GL_FRONT_AND_BACK, 0xFFFFFFFF); + m_state.renderStates.stencilBack.writeMask = 0xFFFFFFFF; + m_state.renderStates.stencilFront.writeMask = 0xFFFFFFFF; + } + } + } #include diff --git a/include/Nazara/OpenGLRenderer/Wrapper/CoreFunctions.hpp b/include/Nazara/OpenGLRenderer/Wrapper/CoreFunctions.hpp index 1996b8e4f..851d482e4 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/CoreFunctions.hpp +++ b/include/Nazara/OpenGLRenderer/Wrapper/CoreFunctions.hpp @@ -29,24 +29,27 @@ typedef void (GL_APIENTRYP PFNGLSPECIALIZESHADERARBPROC) (GLuint shader, const G cb(glBindSampler, PFNGLBINDSAMPLERPROC) \ cb(glBindTexture, PFNGLBINDTEXTUREPROC) \ cb(glBindVertexArray, PFNGLBINDVERTEXARRAYPROC) \ - cb(glBlendFunc, PFNGLBLENDFUNCPROC) \ + cb(glBlendEquationSeparate, PFNGLBLENDEQUATIONSEPARATEPROC) \ cb(glBlendFuncSeparate, PFNGLBLENDFUNCSEPARATEPROC) \ cb(glBlitFramebuffer, PFNGLBLITFRAMEBUFFERPROC) \ cb(glBufferData, PFNGLBUFFERDATAPROC) \ cb(glBufferSubData, PFNGLBUFFERSUBDATAPROC) \ + cb(glCheckFramebufferStatus, PFNGLCHECKFRAMEBUFFERSTATUSPROC) \ cb(glClear, PFNGLCLEARPROC) \ + cb(glClearBufferfi, PFNGLCLEARBUFFERFIPROC) \ + cb(glClearBufferfv, PFNGLCLEARBUFFERFVPROC) \ + cb(glClearBufferuiv, PFNGLCLEARBUFFERUIVPROC) \ cb(glClearColor, PFNGLCLEARCOLORPROC) \ cb(glClearDepthf, PFNGLCLEARDEPTHFPROC) \ cb(glClearStencil, PFNGLCLEARSTENCILPROC) \ - cb(glCreateProgram, PFNGLCREATEPROGRAMPROC) \ - cb(glCreateShader, PFNGLCREATESHADERPROC) \ - cb(glCheckFramebufferStatus, PFNGLCHECKFRAMEBUFFERSTATUSPROC) \ cb(glColorMask, PFNGLCOLORMASKPROC) \ + cb(glCompileShader, PFNGLCOMPILESHADERPROC) \ cb(glCompressedTexSubImage2D, PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) \ cb(glCompressedTexSubImage3D, PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) \ - cb(glCompileShader, PFNGLCOMPILESHADERPROC) \ cb(glCopyBufferSubData, PFNGLCOPYBUFFERSUBDATAPROC) \ cb(glCopyTexSubImage2D, PFNGLCOPYTEXSUBIMAGE2DPROC) \ + cb(glCreateProgram, PFNGLCREATEPROGRAMPROC) \ + cb(glCreateShader, PFNGLCREATESHADERPROC) \ cb(glCullFace, PFNGLCULLFACEPROC) \ cb(glDeleteBuffers, PFNGLDELETEBUFFERSPROC) \ cb(glDeleteFramebuffers, PFNGLDELETEFRAMEBUFFERSPROC) \ @@ -73,35 +76,40 @@ typedef void (GL_APIENTRYP PFNGLSPECIALIZESHADERARBPROC) (GLuint shader, const G cb(glFramebufferRenderbuffer, PFNGLFRAMEBUFFERRENDERBUFFERPROC) \ cb(glFramebufferTexture2D, PFNGLFRAMEBUFFERTEXTURE2DPROC) \ cb(glFramebufferTextureLayer, PFNGLFRAMEBUFFERTEXTURELAYERPROC) \ - cb(glGenerateMipmap, PFNGLGENERATEMIPMAPPROC) \ + cb(glFrontFace, PFNGLFRONTFACEPROC) \ cb(glGenBuffers, PFNGLGENBUFFERSPROC) \ cb(glGenFramebuffers, PFNGLGENFRAMEBUFFERSPROC) \ - cb(glGenRenderbuffers, PFNGLGENRENDERBUFFERSPROC) \ cb(glGenQueries, PFNGLGENQUERIESPROC) \ + cb(glGenRenderbuffers, PFNGLGENRENDERBUFFERSPROC) \ cb(glGenSamplers, PFNGLGENSAMPLERSPROC) \ cb(glGenTextures, PFNGLGENTEXTURESPROC) \ cb(glGenVertexArrays, PFNGLGENVERTEXARRAYSPROC) \ + cb(glGenerateMipmap, PFNGLGENERATEMIPMAPPROC) \ cb(glGetActiveUniform, PFNGLGETACTIVEUNIFORMPROC) \ + cb(glGetActiveUniformsiv, PFNGLGETACTIVEUNIFORMSIVPROC) \ + cb(glGetActiveUniformBlockiv, PFNGLGETACTIVEUNIFORMBLOCKIVPROC) \ + cb(glGetActiveUniformBlockName, PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) \ cb(glGetBooleanv, PFNGLGETBOOLEANVPROC) \ cb(glGetBufferParameteriv, PFNGLGETBUFFERPARAMETERIVPROC) \ cb(glGetError, PFNGLGETERRORPROC) \ cb(glGetFloatv, PFNGLGETFLOATVPROC) \ cb(glGetIntegerv, PFNGLGETINTEGERVPROC) \ cb(glGetProgramBinary, PFNGLGETPROGRAMBINARYPROC) \ - cb(glGetProgramiv, PFNGLGETPROGRAMIVPROC) \ cb(glGetProgramInfoLog, PFNGLGETPROGRAMINFOLOGPROC) \ - cb(glGetQueryiv, PFNGLGETQUERYIVPROC) \ + cb(glGetProgramiv, PFNGLGETPROGRAMIVPROC) \ cb(glGetQueryObjectuiv, PFNGLGETQUERYOBJECTUIVPROC) \ + cb(glGetQueryiv, PFNGLGETQUERYIVPROC) \ cb(glGetShaderInfoLog, PFNGLGETSHADERINFOLOGPROC) \ - cb(glGetShaderiv, PFNGLGETSHADERIVPROC) \ cb(glGetShaderSource, PFNGLGETSHADERSOURCEPROC) \ + cb(glGetShaderiv, PFNGLGETSHADERIVPROC) \ cb(glGetString, PFNGLGETSTRINGPROC) \ cb(glGetStringi, PFNGLGETSTRINGIPROC) \ cb(glGetTexParameterfv, PFNGLGETTEXPARAMETERFVPROC) \ cb(glGetTexParameteriv, PFNGLGETTEXPARAMETERIVPROC) \ + cb(glGetUniformLocation, PFNGLGETUNIFORMLOCATIONPROC) \ cb(glGetUniformfv, PFNGLGETUNIFORMFVPROC) \ cb(glGetUniformiv, PFNGLGETUNIFORMIVPROC) \ - cb(glGetUniformLocation, PFNGLGETUNIFORMLOCATIONPROC) \ + cb(glGetUniformBlockIndex, PFNGLGETUNIFORMBLOCKINDEXPROC) \ cb(glIsEnabled, PFNGLISENABLEDPROC) \ cb(glLineWidth, PFNGLLINEWIDTHPROC) \ cb(glLinkProgram, PFNGLLINKPROGRAMPROC) \ @@ -122,6 +130,7 @@ typedef void (GL_APIENTRYP PFNGLSPECIALIZESHADERARBPROC) (GLuint shader, const G cb(glStencilFuncSeparate, PFNGLSTENCILFUNCSEPARATEPROC) \ cb(glStencilOp, PFNGLSTENCILOPPROC) \ cb(glStencilOpSeparate, PFNGLSTENCILOPSEPARATEPROC) \ + cb(glStencilMaskSeparate, PFNGLSTENCILMASKSEPARATEPROC) \ cb(glTexImage2D, PFNGLTEXIMAGE2DPROC) \ cb(glTexImage3D, PFNGLTEXIMAGE3DPROC) \ cb(glTexParameterf, PFNGLTEXPARAMETERFPROC) \ @@ -133,8 +142,8 @@ typedef void (GL_APIENTRYP PFNGLSPECIALIZESHADERARBPROC) (GLuint shader, const G cb(glTexSubImage2D, PFNGLTEXSUBIMAGE2DPROC) \ cb(glTexSubImage3D, PFNGLTEXSUBIMAGE3DPROC) \ cb(glUniform1f, PFNGLUNIFORM1FPROC) \ - cb(glUniform1i, PFNGLUNIFORM1IPROC) \ cb(glUniform1fv, PFNGLUNIFORM1FVPROC) \ + cb(glUniform1i, PFNGLUNIFORM1IPROC) \ cb(glUniform1iv, PFNGLUNIFORM1IVPROC) \ cb(glUniform2fv, PFNGLUNIFORM2FVPROC) \ cb(glUniform2iv, PFNGLUNIFORM2IVPROC) \ @@ -148,14 +157,19 @@ typedef void (GL_APIENTRYP PFNGLSPECIALIZESHADERARBPROC) (GLuint shader, const G cb(glValidateProgram, PFNGLVALIDATEPROGRAMPROC) \ cb(glVertexAttrib4f, PFNGLVERTEXATTRIB4FPROC) \ cb(glVertexAttribDivisor, PFNGLVERTEXATTRIBDIVISORPROC) \ - cb(glVertexAttribPointer, PFNGLVERTEXATTRIBPOINTERPROC) \ cb(glVertexAttribIPointer, PFNGLVERTEXATTRIBIPOINTERPROC) \ + cb(glVertexAttribPointer, PFNGLVERTEXATTRIBPOINTERPROC) \ cb(glViewport, PFNGLVIEWPORTPROC) \ \ - extCb(glObjectLabel, PFNGLOBJECTLABELPROC) \ - \ extCb(glDebugMessageCallback, PFNGLDEBUGMESSAGECALLBACKPROC) \ \ + extCb(glMemoryBarrier, PFNGLMEMORYBARRIERPROC) \ + extCb(glMemoryBarrierByRegion, PFNGLMEMORYBARRIERBYREGIONPROC) \ + \ + extCb(glObjectLabel, PFNGLOBJECTLABELPROC) \ + extCb(glPopDebugGroup, PFNGLPOPDEBUGGROUPPROC) \ + extCb(glPushDebugGroup, PFNGLPUSHDEBUGGROUPPROC) \ + \ extCb(glSpecializeShaderARB, PFNGLSPECIALIZESHADERARBPROC) \ #endif diff --git a/include/Nazara/OpenGLRenderer/Wrapper/DeviceObject.hpp b/include/Nazara/OpenGLRenderer/Wrapper/DeviceObject.hpp index e9a241ad4..9f7063875 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/DeviceObject.hpp +++ b/include/Nazara/OpenGLRenderer/Wrapper/DeviceObject.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -26,6 +27,8 @@ namespace Nz::GL bool Create(OpenGLDevice& device, CreateArgs... args); void Destroy(); + const Context& EnsureDeviceContext() const; + bool IsValid() const; OpenGLDevice* GetDevice() const; @@ -39,8 +42,6 @@ namespace Nz::GL static constexpr GLuint InvalidObject = 0; protected: - const Context& EnsureDeviceContext(); - MovablePtr m_device; MovableValue m_objectId; }; diff --git a/include/Nazara/OpenGLRenderer/Wrapper/DeviceObject.inl b/include/Nazara/OpenGLRenderer/Wrapper/DeviceObject.inl index 08d029c79..c92a83c61 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/DeviceObject.inl +++ b/include/Nazara/OpenGLRenderer/Wrapper/DeviceObject.inl @@ -46,6 +46,24 @@ namespace Nz::GL } } + template + const Context& DeviceObject::EnsureDeviceContext() const + { + assert(m_device); + + const Context* activeContext = Context::GetCurrentContext(); + if (!activeContext || activeContext->GetDevice() != m_device) + { + const Context& referenceContext = m_device->GetReferenceContext(); + if (!Context::SetCurrentContext(&referenceContext)) + throw std::runtime_error("failed to activate context"); + + return referenceContext; + } + + return *activeContext; + } + template bool DeviceObject::IsValid() const { @@ -72,24 +90,6 @@ namespace Nz::GL if (context.glObjectLabel) context.glObjectLabel(ObjectType, m_objectId, name.size(), name.data()); } - - template - const Context& DeviceObject::EnsureDeviceContext() - { - assert(m_device); - - const Context* activeContext = Context::GetCurrentContext(); - if (!activeContext || activeContext->GetDevice() != m_device) - { - const Context& referenceContext = m_device->GetReferenceContext(); - if (!Context::SetCurrentContext(&referenceContext)) - throw std::runtime_error("failed to activate context"); - - return referenceContext; - } - - return *activeContext; - } } #include diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Framebuffer.hpp b/include/Nazara/OpenGLRenderer/Wrapper/Framebuffer.hpp index dcfe84546..4d9c27ad1 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Framebuffer.hpp +++ b/include/Nazara/OpenGLRenderer/Wrapper/Framebuffer.hpp @@ -4,36 +4,38 @@ #pragma once -#ifndef NAZARA_OPENGLRENDERER_VKFRAMEBUFFER_HPP -#define NAZARA_OPENGLRENDERER_VKFRAMEBUFFER_HPP +#ifndef NAZARA_OPENGLRENDERER_GLFRAMEBUFFER_HPP +#define NAZARA_OPENGLRENDERER_GLFRAMEBUFFER_HPP #include #include -namespace Nz +namespace Nz::GL { - namespace Vk + class Framebuffer : public DeviceObject { - class Framebuffer : public DeviceObject - { - friend DeviceObject; + friend DeviceObject; - public: - Framebuffer() = default; - Framebuffer(const Framebuffer&) = delete; - Framebuffer(Framebuffer&&) = default; - ~Framebuffer() = default; + public: + Framebuffer() = default; + Framebuffer(const Framebuffer&) = delete; + Framebuffer(Framebuffer&&) noexcept = default; + ~Framebuffer() = default; - Framebuffer& operator=(const Framebuffer&) = delete; - Framebuffer& operator=(Framebuffer&&) = delete; + inline GLenum Check() const; - private: - static inline VkResult CreateHelper(Device& device, const VkFramebufferCreateInfo* createInfo, const VkAllocationCallbacks* allocator, VkFramebuffer* handle); - static inline void DestroyHelper(Device& device, VkFramebuffer handle, const VkAllocationCallbacks* allocator); - }; - } + inline void Renderbuffer(GLenum attachment, GLenum renderbuffer); + inline void Texture2D(GLenum attachment, GLenum textarget, GLuint texture, GLint level = 0); + + Framebuffer& operator=(const Framebuffer&) = delete; + Framebuffer& operator=(Framebuffer&&) noexcept = default; + + private: + static inline GLuint CreateHelper(OpenGLDevice& device, const Context& context); + static inline void DestroyHelper(OpenGLDevice& device, const Context& context, GLuint objectId); + }; } #include -#endif // NAZARA_OPENGLRENDERER_VKFRAMEBUFFER_HPP +#endif diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Framebuffer.inl b/include/Nazara/OpenGLRenderer/Wrapper/Framebuffer.inl index 3656d27f8..54017a96a 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Framebuffer.inl +++ b/include/Nazara/OpenGLRenderer/Wrapper/Framebuffer.inl @@ -3,21 +3,51 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include -namespace Nz +namespace Nz::GL { - namespace Vk + inline GLenum Framebuffer::Check() const { - inline VkResult Framebuffer::CreateHelper(Device& device, const VkFramebufferCreateInfo* createInfo, const VkAllocationCallbacks* allocator, VkFramebuffer* handle) - { - return device.vkCreateFramebuffer(device, createInfo, allocator, handle); - } + assert(m_objectId); - inline void Framebuffer::DestroyHelper(Device& device, VkFramebuffer handle, const VkAllocationCallbacks* allocator) - { - return device.vkDestroyFramebuffer(device, handle, allocator); - } + const Context& context = EnsureDeviceContext(); + context.BindFramebuffer(m_objectId); + return context.glCheckFramebufferStatus(GL_FRAMEBUFFER); + } + + inline void Framebuffer::Renderbuffer(GLenum attachment, GLenum renderbuffer) + { + assert(m_objectId); + + const Context& context = EnsureDeviceContext(); + context.BindFramebuffer(m_objectId); + context.glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, renderbuffer); + } + + inline void Framebuffer::Texture2D(GLenum attachment, GLenum textarget, GLuint texture, GLint level) + { + assert(m_objectId); + + const Context& context = EnsureDeviceContext(); + context.BindFramebuffer(m_objectId); + context.glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, textarget, texture, level); + } + + inline GLuint Framebuffer::CreateHelper(OpenGLDevice& /*device*/, const Context& context) + { + GLuint fbo = 0; + context.glGenFramebuffers(1U, &fbo); + + return fbo; + } + + inline void Framebuffer::DestroyHelper(OpenGLDevice& device, const Context& context, GLuint objectId) + { + context.glDeleteFramebuffers(1U, &objectId); + + device.NotifyFramebufferDestruction(objectId); } } diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Linux/EGLContextX11.hpp b/include/Nazara/OpenGLRenderer/Wrapper/Linux/EGLContextX11.hpp index 7949514be..3f91abcb2 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Linux/EGLContextX11.hpp +++ b/include/Nazara/OpenGLRenderer/Wrapper/Linux/EGLContextX11.hpp @@ -21,13 +21,9 @@ namespace Nz::GL ~EGLContextX11() = default; bool Create(const ContextParams& params, WindowHandle window, const EGLContextBase* shareContext = nullptr) override; - void Destroy() override; EGLContextX11& operator=(const EGLContextX11&) = delete; EGLContextX11& operator=(EGLContextX11&&) = delete; - - private: - ::Display* m_xdisplay = nullptr; }; } diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Program.hpp b/include/Nazara/OpenGLRenderer/Wrapper/Program.hpp index 6acc1eb7b..199c1d51b 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Program.hpp +++ b/include/Nazara/OpenGLRenderer/Wrapper/Program.hpp @@ -26,10 +26,25 @@ namespace Nz::GL inline void AttachShader(GLuint shader); - inline bool GetLinkStatus(std::string* error = nullptr); + inline void Get(GLenum pname, GLint* params) const; + inline void GetActiveUniform(GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) const; + inline void GetActiveUniformBlock(GLuint uniformBlockIndex, GLenum pname, GLint* params) const; + inline std::vector GetActiveUniformBlockUniformIndices(GLuint uniformBlockIndex) const; + inline void GetActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName) const; + inline std::string GetActiveUniformBlockName(GLuint uniformBlockIndex) const; + inline std::string GetActiveUniformName(GLuint index) const; + inline std::vector GetActiveUniforms(GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname) const; + inline void GetActiveUniforms(GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params) const; + inline bool GetLinkStatus(std::string* error = nullptr) const; + inline GLuint GetUniformBlockIndex(const char* uniformBlockName) const; + inline GLuint GetUniformBlockIndex(const std::string& uniformBlockName) const; + inline GLint GetUniformLocation(const char* uniformName) const; + inline GLint GetUniformLocation(const std::string& uniformName) const; inline void Link(); + inline void Uniform(GLint uniformLocation, float value) const; + Program& operator=(const Program&) = delete; Program& operator=(Program&&) noexcept = default; diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Program.inl b/include/Nazara/OpenGLRenderer/Wrapper/Program.inl index ca8795d70..63e6d77e1 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Program.inl +++ b/include/Nazara/OpenGLRenderer/Wrapper/Program.inl @@ -11,12 +11,127 @@ namespace Nz::GL inline void Program::AttachShader(GLuint shader) { assert(m_objectId); - const Context& context = EnsureDeviceContext(); + context.glAttachShader(m_objectId, shader); } - inline bool Program::GetLinkStatus(std::string* error) + inline void Program::Get(GLenum pname, GLint* params) const + { + assert(m_objectId); + const Context& context = EnsureDeviceContext(); + + return context.glGetProgramiv(m_objectId, pname, params); + } + + inline void Program::GetActiveUniform(GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) const + { + assert(m_objectId); + const Context& context = EnsureDeviceContext(); + + return context.glGetActiveUniform(m_objectId, index, bufSize, length, size, type, name); + } + + inline void Program::GetActiveUniformBlock(GLuint uniformBlockIndex, GLenum pname, GLint* params) const + { + assert(m_objectId); + const Context& context = EnsureDeviceContext(); + + return context.glGetActiveUniformBlockiv(m_objectId, uniformBlockIndex, pname, params); + } + + inline std::vector Program::GetActiveUniformBlockUniformIndices(GLuint uniformBlockIndex) const + { + assert(m_objectId); + const Context& context = EnsureDeviceContext(); + + std::vector uniformIndices; + + GLint activeUniformCount = 0; + context.glGetActiveUniformBlockiv(m_objectId, uniformBlockIndex, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &activeUniformCount); + + if (activeUniformCount > 0) + { + uniformIndices.resize(static_cast(activeUniformCount)); + context.glGetActiveUniformBlockiv(m_objectId, uniformBlockIndex, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, uniformIndices.data()); + } + + return uniformIndices; + } + + inline void Program::GetActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName) const + { + assert(m_objectId); + const Context& context = EnsureDeviceContext(); + + return context.glGetActiveUniformBlockName(m_objectId, uniformBlockIndex, bufSize, length, uniformBlockName); + } + + inline std::vector Program::GetActiveUniforms(GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname) const + { + assert(m_objectId); + const Context& context = EnsureDeviceContext(); + + std::vector values(uniformCount); + context.glGetActiveUniformsiv(m_objectId, uniformCount, uniformIndices, pname, values.data()); + + return values; + } + + inline void Program::GetActiveUniforms(GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params) const + { + assert(m_objectId); + const Context& context = EnsureDeviceContext(); + + return context.glGetActiveUniformsiv(m_objectId, uniformCount, uniformIndices, pname, params); + } + + inline std::string Program::GetActiveUniformBlockName(GLuint uniformBlockIndex) const + { + assert(m_objectId); + const Context& context = EnsureDeviceContext(); + + std::string name; + + GLint nameLength = 0; + context.glGetActiveUniformBlockiv(m_objectId, uniformBlockIndex, GL_UNIFORM_BLOCK_NAME_LENGTH, &nameLength); + + if (nameLength > 0) + { + name.resize(nameLength); + + context.glGetActiveUniformBlockName(m_objectId, uniformBlockIndex, nameLength + 1, nullptr, name.data()); + } + + return name; + } + + inline std::string Program::GetActiveUniformName(GLuint index) const + { + assert(m_objectId); + const Context& context = EnsureDeviceContext(); + + std::string name; + + GLint maxNameLength = 0; + context.glGetProgramiv(m_objectId, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxNameLength); + + if (maxNameLength > 0) + { + name.resize(maxNameLength); + + GLsizei length; + GLint size; + GLenum type; + context.glGetActiveUniform(m_objectId, index, maxNameLength, &length, &size, &type, name.data()); + + name.resize(length); + } + + return name; + } + + inline bool Program::GetLinkStatus(std::string* error) const { assert(m_objectId); const Context& context = EnsureDeviceContext(); @@ -45,6 +160,32 @@ namespace Nz::GL return true; } + inline GLuint Program::GetUniformBlockIndex(const char* uniformBlockName) const + { + assert(m_objectId); + const Context& context = EnsureDeviceContext(); + + return context.glGetUniformBlockIndex(m_objectId, uniformBlockName); + } + + inline GLuint Program::GetUniformBlockIndex(const std::string& uniformBlockName) const + { + return GetUniformBlockIndex(uniformBlockName.c_str()); + } + + inline GLint Program::GetUniformLocation(const char* uniformName) const + { + assert(m_objectId); + const Context& context = EnsureDeviceContext(); + + return context.glGetUniformLocation(m_objectId, uniformName); + } + + inline GLint Program::GetUniformLocation(const std::string& uniformName) const + { + return GetUniformLocation(uniformName.c_str()); + } + inline void Program::Link() { assert(m_objectId); @@ -53,6 +194,15 @@ namespace Nz::GL context.glLinkProgram(m_objectId); } + inline void Program::Uniform(GLint uniformLocation, float value) const + { + assert(m_objectId); + + const Context& context = EnsureDeviceContext(); + context.BindProgram(m_objectId); + context.glUniform1f(uniformLocation, value); + } + inline GLuint Program::CreateHelper(OpenGLDevice& /*device*/, const Context& context) { return context.glCreateProgram(); diff --git a/include/Nazara/OpenGLRenderer/Wrapper/RenderBuffer.hpp b/include/Nazara/OpenGLRenderer/Wrapper/RenderBuffer.hpp deleted file mode 100644 index 1dfbd2b62..000000000 --- a/include/Nazara/OpenGLRenderer/Wrapper/RenderBuffer.hpp +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - OpenGL Renderer" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_OPENGLRENDERER_VKFENCE_HPP -#define NAZARA_OPENGLRENDERER_VKFENCE_HPP - -#include -#include - -namespace Nz -{ - namespace Vk - { - class Fence : public DeviceObject - { - friend DeviceObject; - - public: - Fence() = default; - Fence(const Fence&) = delete; - Fence(Fence&&) = default; - ~Fence() = default; - - using DeviceObject::Create; - inline bool Create(Device& device, VkFenceCreateFlags flags = 0, const VkAllocationCallbacks* allocator = nullptr); - - inline bool Reset(); - - inline bool Wait(); - inline bool Wait(UInt64 timeout, bool* didTimeout = nullptr); - - Fence& operator=(const Fence&) = delete; - Fence& operator=(Fence&&) = delete; - - private: - static inline VkResult CreateHelper(Device& device, const VkFenceCreateInfo* createInfo, const VkAllocationCallbacks* allocator, VkFence* handle); - static inline void DestroyHelper(Device& device, VkFence handle, const VkAllocationCallbacks* allocator); - }; - } -} - -#include - -#endif // NAZARA_OPENGLRENDERER_VKFENCE_HPP diff --git a/include/Nazara/OpenGLRenderer/Wrapper/RenderBuffer.inl b/include/Nazara/OpenGLRenderer/Wrapper/RenderBuffer.inl deleted file mode 100644 index 855472b58..000000000 --- a/include/Nazara/OpenGLRenderer/Wrapper/RenderBuffer.inl +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - OpenGL Renderer" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include - -namespace Nz -{ - namespace Vk - { - inline bool Fence::Create(Device& device, VkFenceCreateFlags flags, const VkAllocationCallbacks* allocator) - { - VkFenceCreateInfo createInfo = - { - VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, - nullptr, - flags - }; - - return Create(device, createInfo, allocator); - } - - inline bool Fence::Reset() - { - m_lastErrorCode = m_device->vkResetFences(*m_device, 1U, &m_handle); - if (m_lastErrorCode != VK_SUCCESS) - { - NazaraError("Failed to reset fence: " + TranslateOpenGLError(m_lastErrorCode)); - return false; - } - - return true; - } - - inline bool Fence::Wait() - { - return Wait(std::numeric_limits::max()); - } - - inline bool Fence::Wait(UInt64 timeout, bool* didTimeout) - { - m_lastErrorCode = m_device->vkWaitForFences(*m_device, 1U, &m_handle, VK_TRUE, timeout); - if (m_lastErrorCode != VK_SUCCESS && m_lastErrorCode != VK_TIMEOUT) - { - NazaraError("Failed to wait for fence: " + TranslateOpenGLError(m_lastErrorCode)); - return false; - } - - if (didTimeout) - *didTimeout = (m_lastErrorCode == VK_TIMEOUT); - - return true; - } - - inline VkResult Fence::CreateHelper(Device& device, const VkFenceCreateInfo* createInfo, const VkAllocationCallbacks* allocator, VkFence* handle) - { - return device.vkCreateFence(device, createInfo, allocator, handle); - } - - inline void Fence::DestroyHelper(Device& device, VkFence handle, const VkAllocationCallbacks* allocator) - { - return device.vkDestroyFence(device, handle, allocator); - } - } -} - -#include diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Texture.hpp b/include/Nazara/OpenGLRenderer/Wrapper/Texture.hpp index 0b04a5e4a..e27392d08 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Texture.hpp +++ b/include/Nazara/OpenGLRenderer/Wrapper/Texture.hpp @@ -29,9 +29,14 @@ namespace Nz::GL inline void SetParameterfv(GLenum pname, const GLfloat* param); inline void SetParameteriv(GLenum pname, const GLint* param); - inline void TexImage2D(GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type); - inline void TexImage2D(GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* data); - inline void TexSubImage2D(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* data); + inline void TexImage2D(TextureTarget target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type); + inline void TexImage2D(TextureTarget target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* data); + inline void TexImage3D(TextureTarget target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type); + inline void TexImage3D(TextureTarget target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void* data); + inline void TexStorage2D(TextureTarget target, GLint levels, GLint internalFormat, GLsizei width, GLsizei height); + inline void TexStorage3D(TextureTarget target, GLint levels, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth); + inline void TexSubImage2D(TextureTarget target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* data); + inline void TexSubImage3D(TextureTarget target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* data); Texture& operator=(const Texture&) = delete; Texture& operator=(Texture&&) noexcept = default; diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Texture.inl b/include/Nazara/OpenGLRenderer/Wrapper/Texture.inl index 62de24b8d..eb3e4f778 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Texture.inl +++ b/include/Nazara/OpenGLRenderer/Wrapper/Texture.inl @@ -44,26 +44,65 @@ namespace Nz::GL context.glTexParameteriv(ToOpenGL(m_target), pname, param); } - inline void Texture::TexImage2D(GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type) + inline void Texture::TexImage2D(TextureTarget target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type) { - return TexImage2D(level, internalFormat, width, height, border, format, type, nullptr); + return TexImage2D(target, level, internalFormat, width, height, border, format, type, nullptr); } - inline void Texture::TexImage2D(GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* data) + inline void Texture::TexImage2D(TextureTarget target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* data) { - m_target = TextureTarget::Target2D; + m_target = target; const Context& context = EnsureDeviceContext(); context.BindTexture(m_target, m_objectId); context.glTexImage2D(ToOpenGL(m_target), level, internalFormat, width, height, border, format, type, data); - //< TODO: Handle errors } - inline void Texture::TexSubImage2D(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* data) + inline void Texture::TexImage3D(TextureTarget target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type) + { + return TexImage3D(target, level, internalFormat, width, height, depth, border, format, type, nullptr); + } + + inline void Texture::TexImage3D(TextureTarget target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void* data) + { + m_target = target; + + const Context& context = EnsureDeviceContext(); + context.BindTexture(m_target, m_objectId); + context.glTexImage3D(ToOpenGL(m_target), level, internalFormat, width, height, depth, border, format, type, data); + } + + inline void Texture::TexStorage2D(TextureTarget target, GLint levels, GLint internalFormat, GLsizei width, GLsizei height) + { + m_target = target; + + const Context& context = EnsureDeviceContext(); + context.BindTexture(m_target, m_objectId); + context.glTexStorage2D(ToOpenGL(m_target), levels, internalFormat, width, height); + } + + inline void Texture::TexStorage3D(TextureTarget target, GLint levels, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth) + { + m_target = target; + + const Context& context = EnsureDeviceContext(); + context.BindTexture(m_target, m_objectId); + context.glTexStorage3D(ToOpenGL(m_target), levels, internalFormat, width, height, depth); + } + + inline void Texture::TexSubImage2D(TextureTarget target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* data) { const Context& context = EnsureDeviceContext(); context.BindTexture(m_target, m_objectId); - context.glTexSubImage2D(ToOpenGL(m_target), level, xoffset, yoffset, width, height, format, type, data); + context.glTexSubImage2D(ToOpenGL(target), level, xoffset, yoffset, width, height, format, type, data); + //< TODO: Handle errors + } + + inline void Texture::TexSubImage3D(TextureTarget target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* data) + { + const Context& context = EnsureDeviceContext(); + context.BindTexture(m_target, m_objectId); + context.glTexSubImage3D(ToOpenGL(target), level, xoffset, yoffset, zoffset, width, height, depth, format, type, data); //< TODO: Handle errors } diff --git a/include/Nazara/OpenGLRenderer/Wrapper/WGL/WGLContext.inl b/include/Nazara/OpenGLRenderer/Wrapper/WGL/WGLContext.inl index d6ca768d4..f21ceb1e2 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/WGL/WGLContext.inl +++ b/include/Nazara/OpenGLRenderer/Wrapper/WGL/WGLContext.inl @@ -9,7 +9,8 @@ namespace Nz::GL { inline GL::WGLContext::WGLContext(const OpenGLDevice* device, const WGLLoader& loader) : Context(device), - m_loader(loader) + m_loader(loader), + m_handle(nullptr) { } diff --git a/include/Nazara/OpenGLRenderer/Wrapper/WGL/WGLLoader.hpp b/include/Nazara/OpenGLRenderer/Wrapper/WGL/WGLLoader.hpp index 01680f760..3047bf1c1 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/WGL/WGLLoader.hpp +++ b/include/Nazara/OpenGLRenderer/Wrapper/WGL/WGLLoader.hpp @@ -12,10 +12,8 @@ #include #include #include -#include - -#undef WIN32_LEAN_AND_MEAN //< Redefined by OpenGL header (ty Khronos) #include +#include namespace Nz::GL { diff --git a/include/Nazara/Physics2D/Collider2D.hpp b/include/Nazara/Physics2D/Collider2D.hpp index b713e510d..4710f3ea1 100644 --- a/include/Nazara/Physics2D/Collider2D.hpp +++ b/include/Nazara/Physics2D/Collider2D.hpp @@ -8,7 +8,6 @@ #define NAZARA_COLLIDER2D_HPP #include -#include #include #include #include @@ -18,20 +17,15 @@ #include #include +struct cpBody; struct cpShape; namespace Nz { - class Collider2D; class RigidBody2D; - using Collider2DConstRef = ObjectRef; - using Collider2DLibrary = ObjectLibrary; - using Collider2DRef = ObjectRef; - - class NAZARA_PHYSICS2D_API Collider2D : public RefCounted + class NAZARA_PHYSICS2D_API Collider2D { - friend Collider2DLibrary; friend RigidBody2D; friend class CompoundCollider2D; //< See CompoundCollider2D::CreateShapes @@ -74,7 +68,7 @@ namespace Nz NazaraSignal(OnColliderRelease, const Collider2D* /*collider*/); protected: - virtual std::size_t CreateShapes(RigidBody2D* body, std::vector* shapes) const = 0; + virtual std::size_t CreateShapes(cpBody* body, std::vector* shapes) const = 0; UInt32 m_categoryMask; UInt32 m_collisionGroup; @@ -86,16 +80,9 @@ namespace Nz unsigned int m_collisionId; private: - virtual std::size_t GenerateShapes(RigidBody2D* body, std::vector* shapes) const; - - static Collider2DLibrary::LibraryMap s_library; + virtual std::size_t GenerateShapes(cpBody* body, std::vector* shapes) const; }; - class BoxCollider2D; - - using BoxCollider2DConstRef = ObjectRef; - using BoxCollider2DRef = ObjectRef; - class NAZARA_PHYSICS2D_API BoxCollider2D : public Collider2D { public: @@ -110,20 +97,13 @@ namespace Nz inline Vector2f GetSize() const; ColliderType2D GetType() const override; - template static BoxCollider2DRef New(Args&&... args); - private: - std::size_t CreateShapes(RigidBody2D* body, std::vector* shapes) const override; + std::size_t CreateShapes(cpBody* body, std::vector* shapes) const override; Rectf m_rect; float m_radius; }; - class CircleCollider2D; - - using CircleCollider2DConstRef = ObjectRef; - using CircleCollider2DRef = ObjectRef; - class NAZARA_PHYSICS2D_API CircleCollider2D : public Collider2D { public: @@ -136,50 +116,36 @@ namespace Nz inline float GetRadius() const; ColliderType2D GetType() const override; - template static CircleCollider2DRef New(Args&&... args); - private: - std::size_t CreateShapes(RigidBody2D* body, std::vector* shapes) const override; + std::size_t CreateShapes(cpBody* body, std::vector* shapes) const override; Vector2f m_offset; float m_radius; }; - class CompoundCollider2D; - - using CompoundCollider2DConstRef = ObjectRef; - using CompoundCollider2DRef = ObjectRef; - class NAZARA_PHYSICS2D_API CompoundCollider2D : public Collider2D { public: - CompoundCollider2D(std::vector geoms); + CompoundCollider2D(std::vector> geoms); Nz::Vector2f ComputeCenterOfMass() const override; float ComputeMomentOfInertia(float mass) const override; inline bool DoesOverrideCollisionProperties() const; - inline const std::vector& GetGeoms() const; + inline const std::vector>& GetGeoms() const; ColliderType2D GetType() const override; inline void OverridesCollisionProperties(bool shouldOverride); - template static CompoundCollider2DRef New(Args&&... args); - private: - std::size_t CreateShapes(RigidBody2D* body, std::vector* shapes) const override; - std::size_t GenerateShapes(RigidBody2D* body, std::vector* shapes) const override; + std::size_t CreateShapes(cpBody* body, std::vector* shapes) const override; + std::size_t GenerateShapes(cpBody* body, std::vector* shapes) const override; - std::vector m_geoms; + std::vector> m_geoms; bool m_doesOverrideCollisionProperties; }; - class ConvexCollider2D; - - using ConvexCollider2DConstRef = ObjectRef; - using ConvexCollider2DRef = ObjectRef; - class NAZARA_PHYSICS2D_API ConvexCollider2D : public Collider2D { public: @@ -191,20 +157,13 @@ namespace Nz ColliderType2D GetType() const override; inline const std::vector& GetVertices() const; - template static ConvexCollider2DRef New(Args&&... args); - private: - std::size_t CreateShapes(RigidBody2D* body, std::vector* shapes) const override; + std::size_t CreateShapes(cpBody* body, std::vector* shapes) const override; std::vector m_vertices; float m_radius; }; - class NullCollider2D; - - using NullCollider2DConstRef = ObjectRef; - using NullCollider2DRef = ObjectRef; - class NAZARA_PHYSICS2D_API NullCollider2D : public Collider2D { public: @@ -215,17 +174,10 @@ namespace Nz ColliderType2D GetType() const override; - template static NullCollider2DRef New(Args&&... args); - private: - std::size_t CreateShapes(RigidBody2D* body, std::vector* shapes) const override; + std::size_t CreateShapes(cpBody* body, std::vector* shapes) const override; }; - class SegmentCollider2D; - - using SegmentCollider2DConstRef = ObjectRef; - using SegmentCollider2DRef = ObjectRef; - class NAZARA_PHYSICS2D_API SegmentCollider2D : public Collider2D { public: @@ -243,10 +195,8 @@ namespace Nz inline float GetThickness() const; ColliderType2D GetType() const override; - template static SegmentCollider2DRef New(Args&&... args); - private: - std::size_t CreateShapes(RigidBody2D* body, std::vector* shapes) const override; + std::size_t CreateShapes(cpBody* body, std::vector* shapes) const override; Vector2f m_first; Vector2f m_firstNeighbor; diff --git a/include/Nazara/Physics2D/Collider2D.inl b/include/Nazara/Physics2D/Collider2D.inl index ad85b0304..478d034aa 100644 --- a/include/Nazara/Physics2D/Collider2D.inl +++ b/include/Nazara/Physics2D/Collider2D.inl @@ -115,14 +115,6 @@ namespace Nz return m_rect.GetLengths(); } - template - BoxCollider2DRef BoxCollider2D::New(Args&&... args) - { - std::unique_ptr object(new BoxCollider2D(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); - } inline const Vector2f& CircleCollider2D::GetOffset() const { @@ -134,21 +126,13 @@ namespace Nz return m_radius; } - template - CircleCollider2DRef CircleCollider2D::New(Args&&... args) - { - std::unique_ptr object(new CircleCollider2D(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); - } inline bool Nz::CompoundCollider2D::DoesOverrideCollisionProperties() const { return m_doesOverrideCollisionProperties; } - inline const std::vector& CompoundCollider2D::GetGeoms() const + inline const std::vector>& CompoundCollider2D::GetGeoms() const { return m_geoms; } @@ -158,37 +142,12 @@ namespace Nz m_doesOverrideCollisionProperties = shouldOverride; } - template - CompoundCollider2DRef CompoundCollider2D::New(Args&&... args) - { - std::unique_ptr object(new CompoundCollider2D(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); - } inline const std::vector& ConvexCollider2D::GetVertices() const { return m_vertices; } - template - ConvexCollider2DRef ConvexCollider2D::New(Args&&... args) - { - std::unique_ptr object(new ConvexCollider2D(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); - } - - template - NullCollider2DRef NullCollider2D::New(Args&&... args) - { - std::unique_ptr object(new NullCollider2D(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); - } SegmentCollider2D::SegmentCollider2D(const Vector2f& first, const Vector2f& second, float thickness) : SegmentCollider2D(first, first, second, second, thickness) @@ -233,15 +192,6 @@ namespace Nz { return m_thickness; } - - template - SegmentCollider2DRef SegmentCollider2D::New(Args&&... args) - { - std::unique_ptr object(new SegmentCollider2D(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); - } } #include diff --git a/include/Nazara/Physics2D/Constraint2D.hpp b/include/Nazara/Physics2D/Constraint2D.hpp index 337ef63e3..155bc2a94 100644 --- a/include/Nazara/Physics2D/Constraint2D.hpp +++ b/include/Nazara/Physics2D/Constraint2D.hpp @@ -104,8 +104,7 @@ namespace Nz class GearConstraint2D; using GearConstraint2DHandle = ObjectHandle; - using GearConstraint2DRef = ObjectRef; - + class NAZARA_PHYSICS2D_API GearConstraint2D : public Constraint2D { public: @@ -117,8 +116,6 @@ namespace Nz void SetPhase(float phase); void SetRatio(float ratio); - - template static GearConstraint2DRef New(Args&&... args); }; class MotorConstraint2D; diff --git a/include/Nazara/Physics2D/Enums.hpp b/include/Nazara/Physics2D/Enums.hpp index e92d63e02..adf615165 100644 --- a/include/Nazara/Physics2D/Enums.hpp +++ b/include/Nazara/Physics2D/Enums.hpp @@ -9,16 +9,16 @@ namespace Nz { - enum ColliderType2D + enum class ColliderType2D { - ColliderType2D_Box, - ColliderType2D_Compound, - ColliderType2D_Convex, - ColliderType2D_Circle, - ColliderType2D_Null, - ColliderType2D_Segment, + Box, + Compound, + Convex, + Circle, + Null, + Segment, - ColliderType2D_Max = ColliderType2D_Segment + Max = Segment }; } diff --git a/include/Nazara/Physics2D/RigidBody2D.hpp b/include/Nazara/Physics2D/RigidBody2D.hpp index 1fd826da1..e98812a07 100644 --- a/include/Nazara/Physics2D/RigidBody2D.hpp +++ b/include/Nazara/Physics2D/RigidBody2D.hpp @@ -30,15 +30,15 @@ namespace Nz using VelocityFunc = std::function; RigidBody2D(PhysWorld2D* world, float mass); - RigidBody2D(PhysWorld2D* world, float mass, Collider2DRef geom); + RigidBody2D(PhysWorld2D* world, float mass, std::shared_ptr geom); RigidBody2D(const RigidBody2D& object); RigidBody2D(RigidBody2D&& object) noexcept; ~RigidBody2D(); - void AddForce(const Vector2f& force, CoordSys coordSys = CoordSys_Global); - void AddForce(const Vector2f& force, const Vector2f& point, CoordSys coordSys = CoordSys_Global); - void AddImpulse(const Vector2f& impulse, CoordSys coordSys = CoordSys_Global); - void AddImpulse(const Vector2f& impulse, const Vector2f& point, CoordSys coordSys = CoordSys_Global); + void AddForce(const Vector2f& force, CoordSys coordSys = CoordSys::Global); + void AddForce(const Vector2f& force, const Vector2f& point, CoordSys coordSys = CoordSys::Global); + void AddImpulse(const Vector2f& impulse, CoordSys coordSys = CoordSys::Global); + void AddImpulse(const Vector2f& impulse, const Vector2f& point, CoordSys coordSys = CoordSys::Global); void AddTorque(const RadianAnglef& torque); bool ClosestPointQuery(const Nz::Vector2f& position, Nz::Vector2f* closestPoint = nullptr, float* closestDistance = nullptr) const; @@ -52,13 +52,13 @@ namespace Nz inline float GetAngularDamping() const; RadianAnglef GetAngularVelocity() const; NAZARA_DEPRECATED("Name error, please use GetMassCenter") - inline Vector2f GetCenterOfGravity(CoordSys coordSys = CoordSys_Local) const; + inline Vector2f GetCenterOfGravity(CoordSys coordSys = CoordSys::Local) const; float GetElasticity(std::size_t shapeIndex = 0) const; float GetFriction(std::size_t shapeIndex = 0) const; - const Collider2DRef& GetGeom() const; + const std::shared_ptr& GetGeom() const; cpBody* GetHandle() const; float GetMass() const; - Vector2f GetMassCenter(CoordSys coordSys = CoordSys_Local) const; + Vector2f GetMassCenter(CoordSys coordSys = CoordSys::Local) const; float GetMomentOfInertia() const; Vector2f GetPosition() const; inline const Vector2f& GetPositionOffset() const; @@ -84,9 +84,9 @@ namespace Nz void SetElasticity(std::size_t shapeIndex, float elasticity); void SetFriction(float friction); void SetFriction(std::size_t shapeIndex, float friction); - void SetGeom(Collider2DRef geom, bool recomputeMoment = true, bool recomputeMassCenter = true); + void SetGeom(std::shared_ptr geom, bool recomputeMoment = true, bool recomputeMassCenter = true); void SetMass(float mass, bool recomputeMoment = true); - void SetMassCenter(const Vector2f& center, CoordSys coordSys = CoordSys_Local); + void SetMassCenter(const Vector2f& center, CoordSys coordSys = CoordSys::Local); void SetMomentOfInertia(float moment); void SetPosition(const Vector2f& position); void SetPositionOffset(const Vector2f& offset); @@ -122,7 +122,7 @@ namespace Nz Vector2f m_positionOffset; VelocityFunc m_velocityFunc; std::vector m_shapes; - Collider2DRef m_geom; + std::shared_ptr m_geom; cpBody* m_handle; void* m_userData; PhysWorld2D* m_world; diff --git a/include/Nazara/Physics3D/Collider3D.hpp b/include/Nazara/Physics3D/Collider3D.hpp index 7c96fca8a..519f9871b 100644 --- a/include/Nazara/Physics3D/Collider3D.hpp +++ b/include/Nazara/Physics3D/Collider3D.hpp @@ -9,8 +9,6 @@ #include #include -#include -#include #include #include #include @@ -30,17 +28,11 @@ namespace Nz ///TODO: SceneGeom ///TODO: TreeGeom - class Collider3D; class PrimitiveList; class PhysWorld3D; - using Collider3DConstRef = ObjectRef; - using Collider3DLibrary = ObjectLibrary; - using Collider3DRef = ObjectRef; - - class NAZARA_PHYSICS3D_API Collider3D : public RefCounted + class NAZARA_PHYSICS3D_API Collider3D { - friend Collider3DLibrary; friend class Physics3D; public: @@ -62,7 +54,7 @@ namespace Nz Collider3D& operator=(const Collider3D&) = delete; Collider3D& operator=(Collider3D&&) = delete; - static Collider3DRef Build(const PrimitiveList& list); + static std::shared_ptr Build(const PrimitiveList& list); // Signals: NazaraSignal(OnColliderRelease, const Collider3D* /*collider*/); @@ -70,19 +62,9 @@ namespace Nz protected: virtual NewtonCollision* CreateHandle(PhysWorld3D* world) const = 0; - static bool Initialize(); - static void Uninitialize(); - mutable std::unordered_map m_handles; - - static Collider3DLibrary::LibraryMap s_library; }; - class BoxCollider3D; - - using BoxCollider3DConstRef = ObjectRef; - using BoxCollider3DRef = ObjectRef; - class NAZARA_PHYSICS3D_API BoxCollider3D : public Collider3D { public: @@ -95,8 +77,6 @@ namespace Nz Vector3f GetLengths() const; ColliderType3D GetType() const override; - template static BoxCollider3DRef New(Args&&... args); - private: NewtonCollision* CreateHandle(PhysWorld3D* world) const override; @@ -104,11 +84,6 @@ namespace Nz Vector3f m_lengths; }; - class CapsuleCollider3D; - - using CapsuleCollider3DConstRef = ObjectRef; - using CapsuleCollider3DRef = ObjectRef; - class NAZARA_PHYSICS3D_API CapsuleCollider3D : public Collider3D { public: @@ -119,8 +94,6 @@ namespace Nz float GetRadius() const; ColliderType3D GetType() const override; - template static CapsuleCollider3DRef New(Args&&... args); - private: NewtonCollision* CreateHandle(PhysWorld3D* world) const override; @@ -129,32 +102,20 @@ namespace Nz float m_radius; }; - class CompoundCollider3D; - - using CompoundCollider3DConstRef = ObjectRef; - using CompoundCollider3DRef = ObjectRef; - class NAZARA_PHYSICS3D_API CompoundCollider3D : public Collider3D { public: - CompoundCollider3D(std::vector geoms); + CompoundCollider3D(std::vector> geoms); - const std::vector& GetGeoms() const; + const std::vector>& GetGeoms() const; ColliderType3D GetType() const override; - template static CompoundCollider3DRef New(Args&&... args); - private: NewtonCollision* CreateHandle(PhysWorld3D* world) const override; - std::vector m_geoms; + std::vector> m_geoms; }; - class ConeCollider3D; - - using ConeCollider3DConstRef = ObjectRef; - using ConeCollider3DRef = ObjectRef; - class NAZARA_PHYSICS3D_API ConeCollider3D : public Collider3D { public: @@ -165,8 +126,6 @@ namespace Nz float GetRadius() const; ColliderType3D GetType() const override; - template static ConeCollider3DRef New(Args&&... args); - private: NewtonCollision* CreateHandle(PhysWorld3D* world) const override; @@ -175,11 +134,6 @@ namespace Nz float m_radius; }; - class ConvexCollider3D; - - using ConvexCollider3DConstRef = ObjectRef; - using ConvexCollider3DRef = ObjectRef; - class NAZARA_PHYSICS3D_API ConvexCollider3D : public Collider3D { public: @@ -188,8 +142,6 @@ namespace Nz ColliderType3D GetType() const override; - template static ConvexCollider3DRef New(Args&&... args); - private: NewtonCollision* CreateHandle(PhysWorld3D* world) const override; @@ -198,11 +150,6 @@ namespace Nz float m_tolerance; }; - class CylinderCollider3D; - - using CylinderCollider3DConstRef = ObjectRef; - using CylinderCollider3DRef = ObjectRef; - class NAZARA_PHYSICS3D_API CylinderCollider3D : public Collider3D { public: @@ -213,8 +160,6 @@ namespace Nz float GetRadius() const; ColliderType3D GetType() const override; - template static CylinderCollider3DRef New(Args&&... args); - private: NewtonCollision* CreateHandle(PhysWorld3D* world) const override; @@ -223,11 +168,6 @@ namespace Nz float m_radius; }; - class NullCollider3D; - - using NullCollider3DConstRef = ObjectRef; - using NullCollider3DRef = ObjectRef; - class NAZARA_PHYSICS3D_API NullCollider3D : public Collider3D { public: @@ -237,17 +177,10 @@ namespace Nz ColliderType3D GetType() const override; - template static NullCollider3DRef New(Args&&... args); - private: NewtonCollision* CreateHandle(PhysWorld3D* world) const override; }; - class SphereCollider3D; - - using SphereCollider3DConstRef = ObjectRef; - using SphereCollider3DRef = ObjectRef; - class NAZARA_PHYSICS3D_API SphereCollider3D : public Collider3D { public: @@ -260,8 +193,6 @@ namespace Nz float GetRadius() const; ColliderType3D GetType() const override; - template static SphereCollider3DRef New(Args&&... args); - private: NewtonCollision* CreateHandle(PhysWorld3D* world) const override; diff --git a/include/Nazara/Physics3D/Collider3D.inl b/include/Nazara/Physics3D/Collider3D.inl index 4caa926f1..01c3c4266 100644 --- a/include/Nazara/Physics3D/Collider3D.inl +++ b/include/Nazara/Physics3D/Collider3D.inl @@ -2,82 +2,12 @@ // This file is part of the "Nazara Engine - Physics 3D module" // For conditions of distribution and use, see copyright notice in Config.hpp +#include #include #include namespace Nz { - template - BoxCollider3DRef BoxCollider3D::New(Args&&... args) - { - std::unique_ptr object(new BoxCollider3D(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); - } - - template - CapsuleCollider3DRef CapsuleCollider3D::New(Args&&... args) - { - std::unique_ptr object(new CapsuleCollider3D(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); - } - - template - CompoundCollider3DRef CompoundCollider3D::New(Args&&... args) - { - std::unique_ptr object(new CompoundCollider3D(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); - } - - template - ConeCollider3DRef ConeCollider3D::New(Args&&... args) - { - std::unique_ptr object(new ConeCollider3D(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); - } - - template - ConvexCollider3DRef ConvexCollider3D::New(Args&&... args) - { - std::unique_ptr object(new ConvexCollider3D(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); - } - - template - CylinderCollider3DRef CylinderCollider3D::New(Args&&... args) - { - std::unique_ptr object(new CylinderCollider3D(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); - } - - template - NullCollider3DRef NullCollider3D::New(Args&&... args) - { - std::unique_ptr object(new NullCollider3D(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); - } - - template - SphereCollider3DRef SphereCollider3D::New(Args&&... args) - { - std::unique_ptr object(new SphereCollider3D(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); - } } #include diff --git a/include/Nazara/Physics3D/Enums.hpp b/include/Nazara/Physics3D/Enums.hpp index 68b93454b..ec78ee304 100644 --- a/include/Nazara/Physics3D/Enums.hpp +++ b/include/Nazara/Physics3D/Enums.hpp @@ -9,21 +9,21 @@ namespace Nz { - enum ColliderType3D + enum class ColliderType3D { - ColliderType3D_Box, - ColliderType3D_Capsule, - ColliderType3D_Cone, - ColliderType3D_Compound, - ColliderType3D_ConvexHull, - ColliderType3D_Cylinder, - ColliderType3D_Heightfield, - ColliderType3D_Null, - ColliderType3D_Scene, - ColliderType3D_Sphere, - ColliderType3D_Tree, + Box, + Capsule, + Cone, + Compound, + ConvexHull, + Cylinder, + Heightfield, + Null, + Scene, + Sphere, + Tree, - ColliderType3D_Max = ColliderType3D_Tree + Max = Tree }; } diff --git a/include/Nazara/Physics3D/Physics3D.hpp b/include/Nazara/Physics3D/Physics3D.hpp index 0a1dac109..242bd2c75 100644 --- a/include/Nazara/Physics3D/Physics3D.hpp +++ b/include/Nazara/Physics3D/Physics3D.hpp @@ -23,7 +23,7 @@ namespace Nz struct Config {}; Physics3D(Config /*config*/); - ~Physics3D(); + ~Physics3D() = default; unsigned int GetMemoryUsed(); diff --git a/include/Nazara/Physics3D/RigidBody3D.hpp b/include/Nazara/Physics3D/RigidBody3D.hpp index 6b9bce67c..f185fa3c4 100644 --- a/include/Nazara/Physics3D/RigidBody3D.hpp +++ b/include/Nazara/Physics3D/RigidBody3D.hpp @@ -25,14 +25,14 @@ namespace Nz { public: RigidBody3D(PhysWorld3D* world, const Matrix4f& mat = Matrix4f::Identity()); - RigidBody3D(PhysWorld3D* world, Collider3DRef geom, const Matrix4f& mat = Matrix4f::Identity()); + RigidBody3D(PhysWorld3D* world, std::shared_ptr geom, const Matrix4f& mat = Matrix4f::Identity()); RigidBody3D(const RigidBody3D& object); RigidBody3D(RigidBody3D&& object); ~RigidBody3D(); - void AddForce(const Vector3f& force, CoordSys coordSys = CoordSys_Global); - void AddForce(const Vector3f& force, const Vector3f& point, CoordSys coordSys = CoordSys_Global); - void AddTorque(const Vector3f& torque, CoordSys coordSys = CoordSys_Global); + void AddForce(const Vector3f& force, CoordSys coordSys = CoordSys::Global); + void AddForce(const Vector3f& force, const Vector3f& point, CoordSys coordSys = CoordSys::Global); + void AddTorque(const Vector3f& torque, CoordSys coordSys = CoordSys::Global); void EnableAutoSleep(bool autoSleep); void EnableSimulation(bool simulation); @@ -40,13 +40,13 @@ namespace Nz Boxf GetAABB() const; Vector3f GetAngularDamping() const; Vector3f GetAngularVelocity() const; - const Collider3DRef& GetGeom() const; + const std::shared_ptr& GetGeom() const; float GetGravityFactor() const; NewtonBody* GetHandle() const; float GetLinearDamping() const; Vector3f GetLinearVelocity() const; float GetMass() const; - Vector3f GetMassCenter(CoordSys coordSys = CoordSys_Local) const; + Vector3f GetMassCenter(CoordSys coordSys = CoordSys::Local) const; int GetMaterial() const; const Matrix4f& GetMatrix() const; Vector3f GetPosition() const; @@ -61,7 +61,7 @@ namespace Nz void SetAngularDamping(const Vector3f& angularDamping); void SetAngularVelocity(const Vector3f& angularVelocity); - void SetGeom(Collider3DRef geom); + void SetGeom(std::shared_ptr geom); void SetGravityFactor(float gravityFactor); void SetLinearDamping(float damping); void SetLinearVelocity(const Vector3f& velocity); @@ -81,7 +81,7 @@ namespace Nz static void ForceAndTorqueCallback(const NewtonBody* body, float timeStep, int threadIndex); static void TransformCallback(const NewtonBody* body, const float* matrix, int threadIndex); - Collider3DRef m_geom; + std::shared_ptr m_geom; Matrix4f m_matrix; Vector3f m_forceAccumulator; Vector3f m_torqueAccumulator; diff --git a/include/Nazara/Platform/Cursor.hpp b/include/Nazara/Platform/Cursor.hpp index 52438123f..bf800dcd9 100644 --- a/include/Nazara/Platform/Cursor.hpp +++ b/include/Nazara/Platform/Cursor.hpp @@ -8,7 +8,6 @@ #define NAZARA_CURSOR_HPP #include -#include #include #include #include @@ -19,51 +18,42 @@ namespace Nz { class CursorImpl; - class Cursor; - - using CursorConstRef = ObjectRef; - using CursorRef = ObjectRef; - - class NAZARA_PLATFORM_API Cursor : public RefCounted + class NAZARA_PLATFORM_API Cursor { friend class Platform; friend class WindowImpl; public: - inline Cursor(); - inline Cursor(const Image& cursor, const Vector2i& hotSpot, SystemCursor placeholder); + Cursor(); + Cursor(const Image& cursor, const Vector2i& hotSpot, SystemCursor placeholder); Cursor(const Cursor&) = delete; - Cursor(Cursor&&) = delete; - inline ~Cursor(); + Cursor(Cursor&&) noexcept; + ~Cursor(); bool Create(const Image& cursor, const Vector2i& hotSpot, SystemCursor placeholder); - void Destroy(); - inline const Image& GetImage() const; inline SystemCursor GetSystemCursor() const; inline bool IsValid() const; Cursor& operator=(const Cursor&) = delete; - Cursor& operator=(Cursor&&) = delete; + Cursor& operator=(Cursor&&) noexcept; - static inline Cursor* Get(SystemCursor cursor); - template static CursorRef New(Args&&... args); + static inline std::shared_ptr& Get(SystemCursor cursor); private: - inline explicit Cursor(SystemCursor systemCursor); + explicit Cursor(SystemCursor systemCursor); bool Create(SystemCursor cursor); static bool Initialize(); static void Uninitialize(); - Image m_cursorImage; SystemCursor m_systemCursor; - CursorImpl* m_impl; + std::unique_ptr m_impl; - static std::array s_systemCursors; + static std::array, SystemCursorCount> s_systemCursors; }; } diff --git a/include/Nazara/Platform/Cursor.inl b/include/Nazara/Platform/Cursor.inl index 12aceb908..26bdf9070 100644 --- a/include/Nazara/Platform/Cursor.inl +++ b/include/Nazara/Platform/Cursor.inl @@ -2,47 +2,11 @@ // This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include namespace Nz { - inline Cursor::Cursor() : - m_impl(nullptr) - { - } - - inline Cursor::Cursor(const Image& cursor, const Vector2i& hotSpot, SystemCursor placeholder) - { - ErrorFlags flags(ErrorFlag_ThrowException, true); - Create(cursor, hotSpot, placeholder); - } - - inline Cursor* Cursor::Get(SystemCursor cursor) - { - return &s_systemCursors[cursor]; - } - - inline Cursor::Cursor(SystemCursor systemCursor) : - Cursor() - { - ErrorFlags flags(ErrorFlag_ThrowException, true); - Create(systemCursor); - } - - inline Cursor::~Cursor() - { - Destroy(); - } - - inline const Image& Cursor::GetImage() const - { - NazaraAssert(IsValid(), "Invalid cursor"); - NazaraAssert(m_cursorImage.IsValid(), "System cursors have no image"); - - return m_cursorImage; - } - inline SystemCursor Cursor::GetSystemCursor() const { NazaraAssert(IsValid(), "Invalid cursor"); @@ -55,13 +19,9 @@ namespace Nz return m_impl != nullptr; } - template - CursorRef Cursor::New(Args&&... args) + inline std::shared_ptr& Cursor::Get(SystemCursor cursor) { - std::unique_ptr object(new Cursor(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); + return s_systemCursors[UnderlyingCast(cursor)]; } } diff --git a/include/Nazara/Platform/CursorController.hpp b/include/Nazara/Platform/CursorController.hpp index 2fc68d623..efb519e2d 100644 --- a/include/Nazara/Platform/CursorController.hpp +++ b/include/Nazara/Platform/CursorController.hpp @@ -28,12 +28,12 @@ namespace Nz CursorController(CursorController&&) noexcept = default; ~CursorController() = default; - inline void UpdateCursor(const CursorRef& cursor); + inline void UpdateCursor(const std::shared_ptr& cursor); CursorController& operator=(const CursorController&) = delete; CursorController& operator=(CursorController&&) noexcept = default; - NazaraSignal(OnCursorUpdated, const CursorController* /*cursorController*/, const CursorRef& /*cursor*/); + NazaraSignal(OnCursorUpdated, const CursorController* /*cursorController*/, const std::shared_ptr& /*cursor*/); }; } diff --git a/include/Nazara/Platform/CursorController.inl b/include/Nazara/Platform/CursorController.inl index 45b9393e1..e9cde185b 100644 --- a/include/Nazara/Platform/CursorController.inl +++ b/include/Nazara/Platform/CursorController.inl @@ -7,7 +7,7 @@ namespace Nz { - inline void CursorController::UpdateCursor(const CursorRef& cursor) + inline void CursorController::UpdateCursor(const std::shared_ptr& cursor) { OnCursorUpdated(this, cursor); } diff --git a/include/Nazara/Platform/Enums.hpp b/include/Nazara/Platform/Enums.hpp index 1f8390ae6..f874a0947 100644 --- a/include/Nazara/Platform/Enums.hpp +++ b/include/Nazara/Platform/Enums.hpp @@ -11,75 +11,81 @@ namespace Nz { - enum SystemCursor + enum class SystemCursor { - SystemCursor_Crosshair, - SystemCursor_Default, - SystemCursor_Hand, - SystemCursor_Help, - SystemCursor_Move, - SystemCursor_None, - SystemCursor_Pointer, - SystemCursor_Progress, - SystemCursor_ResizeE, - SystemCursor_ResizeN, - SystemCursor_ResizeNE, - SystemCursor_ResizeNW, - SystemCursor_ResizeS, - SystemCursor_ResizeSE, - SystemCursor_ResizeSW, - SystemCursor_ResizeW, - SystemCursor_Text, - SystemCursor_Wait, + Crosshair, + Default, + Hand, + Help, + Move, + None, + Pointer, + Progress, + ResizeE, + ResizeN, + ResizeNE, + ResizeNW, + ResizeS, + ResizeSE, + ResizeSW, + ResizeW, + Text, + Wait, - SystemCursor_Max = SystemCursor_Wait + Max = Wait }; - enum WindowEventType - { - WindowEventType_GainedFocus, - WindowEventType_LostFocus, - WindowEventType_KeyPressed, - WindowEventType_KeyReleased, - WindowEventType_MouseButtonDoubleClicked, - WindowEventType_MouseButtonPressed, - WindowEventType_MouseButtonReleased, - WindowEventType_MouseEntered, - WindowEventType_MouseLeft, - WindowEventType_MouseMoved, - WindowEventType_MouseWheelMoved, - WindowEventType_Moved, - WindowEventType_Quit, - WindowEventType_Resized, - WindowEventType_TextEdited, - WindowEventType_TextEntered, + constexpr std::size_t SystemCursorCount = static_cast(SystemCursor::Max) + 1; - WindowEventType_Max = WindowEventType_TextEntered + enum class WindowEventType + { + GainedFocus, + LostFocus, + KeyPressed, + KeyReleased, + MouseButtonDoubleClicked, + MouseButtonPressed, + MouseButtonReleased, + MouseEntered, + MouseLeft, + MouseMoved, + MouseWheelMoved, + Moved, + Quit, + Resized, + TextEdited, + TextEntered, + + Max = TextEntered }; - enum WindowStyle + constexpr std::size_t WindowEventTypeCount = static_cast(WindowEventType::Max) + 1; + + enum class WindowStyle { - WindowStyle_None, ///< Window has no border nor titlebar. - WindowStyle_Fullscreen, ///< At the window creation, the OS tries to set it in fullscreen. + None, ///< Window has no border nor titlebar. + Fullscreen, ///< At the window creation, the OS tries to set it in fullscreen. - WindowStyle_Closable, ///< Allows the window to be closed by a button in the titlebar, generating a Quit event. - WindowStyle_Resizable, ///< Allows the window to be resized by dragging its corners or by a button of the titlebar. - WindowStyle_Titlebar, ///< Adds a titlebar to the window, this option is automatically enabled if buttons of the titlebar are enabled. + Closable, ///< Allows the window to be closed by a button in the titlebar, generating a Quit event. + Resizable, ///< Allows the window to be resized by dragging its corners or by a button of the titlebar. + Titlebar, ///< Adds a titlebar to the window, this option is automatically enabled if buttons of the titlebar are enabled. - WindowStyle_Threaded, ///< Runs the window into a thread, allowing the application to keep updating while resizing/dragging the window. + Threaded, ///< Runs the window into a thread, allowing the application to keep updating while resizing/dragging the window. - WindowStyle_Max = WindowStyle_Threaded + Max = Threaded }; + constexpr std::size_t WindowStyleCount = static_cast(WindowStyle::Max) + 1; + template<> struct EnumAsFlags { - static constexpr WindowStyle max = WindowStyle_Max; + static constexpr WindowStyle max = WindowStyle::Max; }; using WindowStyleFlags = Flags; - constexpr WindowStyleFlags WindowStyle_Default = WindowStyle_Closable | WindowStyle_Resizable | WindowStyle_Titlebar; + constexpr WindowStyleFlags WindowStyle_Default = WindowStyle::Closable | WindowStyle::Resizable | WindowStyle::Titlebar; } #endif // NAZARA_ENUMS_PLATFORM_HPP diff --git a/include/Nazara/Platform/Event.hpp b/include/Nazara/Platform/Event.hpp index cfa73efd9..625905a28 100644 --- a/include/Nazara/Platform/Event.hpp +++ b/include/Nazara/Platform/Event.hpp @@ -20,8 +20,8 @@ namespace Nz struct WindowEvent { // Used by: - // -WindowEventType_KeyPressed - // -WindowEventType_KeyReleased + // -WindowEventType::KeyPressed + // -WindowEventType::KeyReleased struct KeyEvent { Keyboard::Scancode scancode; @@ -34,8 +34,8 @@ namespace Nz }; // Used by: - // -WindowEventType_MouseButtonDoubleClicked - // -WindowEventType_MouseButtonPressed + // -WindowEventType::MouseButtonDoubleClicked + // -WindowEventType::MouseButtonPressed struct MouseButtonEvent { Mouse::Button button; @@ -44,7 +44,7 @@ namespace Nz }; // Used by: - // -WindowEventType_MouseMoved + // -WindowEventType::MouseMoved struct MouseMoveEvent { int deltaX; @@ -54,7 +54,7 @@ namespace Nz }; // Used by: - // -WindowEventType_MouseWheelMoved + // -WindowEventType::MouseWheelMoved struct MouseWheelEvent { float delta; @@ -63,7 +63,7 @@ namespace Nz }; // Used by: - // -WindowEventType_Moved + // -WindowEventType::Moved struct PositionEvent { int x; @@ -71,7 +71,7 @@ namespace Nz }; // Used by: - // -WindowEventType_Resized + // -WindowEventType::Resized struct SizeEvent { unsigned int height; @@ -79,7 +79,7 @@ namespace Nz }; // Used by: - // -WindowEventType_TextEntered + // -WindowEventType::TextEntered struct TextEvent { bool repeated; @@ -87,7 +87,7 @@ namespace Nz }; // Used by: - // -WindowEventType_TextEdited + // -WindowEventType::TextEdited struct EditEvent { int length; @@ -99,37 +99,37 @@ namespace Nz union { // Used by: - // -WindowEventType_KeyPressed - // -WindowEventType_KeyReleased + // -WindowEventType::KeyPressed + // -WindowEventType::KeyReleased KeyEvent key; // Used by: - // -WindowEventType_MouseButtonDoubleClicked - // -WindowEventType_MouseButtonPressed + // -WindowEventType::MouseButtonDoubleClicked + // -WindowEventType::MouseButtonPressed MouseButtonEvent mouseButton; // Used by: - // -WindowEventType_MouseMoved + // -WindowEventType::MouseMoved MouseMoveEvent mouseMove; // Used by: - // -WindowEventType_MouseWheelMoved + // -WindowEventType::MouseWheelMoved MouseWheelEvent mouseWheel; // Used by: - // -WindowEventType_Moved + // -WindowEventType::Moved PositionEvent position; // Used by: - // -WindowEventType_Resized + // -WindowEventType::Resized SizeEvent size; // Used by: - // -WindowEventType_TextEntered + // -WindowEventType::TextEntered TextEvent text; // Used by: - // -WindowEventType_TextEntered + // -WindowEventType::TextEntered EditEvent edit; }; }; diff --git a/include/Nazara/Platform/EventHandler.inl b/include/Nazara/Platform/EventHandler.inl index 7b083285f..f062891e0 100644 --- a/include/Nazara/Platform/EventHandler.inl +++ b/include/Nazara/Platform/EventHandler.inl @@ -19,67 +19,67 @@ namespace Nz switch (event.type) { - case WindowEventType_GainedFocus: + case WindowEventType::GainedFocus: OnGainedFocus(this); break; - case WindowEventType_KeyPressed: + case WindowEventType::KeyPressed: OnKeyPressed(this, event.key); break; - case WindowEventType_KeyReleased: + case WindowEventType::KeyReleased: OnKeyReleased(this, event.key); break; - case WindowEventType_LostFocus: + case WindowEventType::LostFocus: OnLostFocus(this); break; - case WindowEventType_MouseButtonDoubleClicked: + case WindowEventType::MouseButtonDoubleClicked: OnMouseButtonDoubleClicked(this, event.mouseButton); break; - case WindowEventType_MouseButtonPressed: + case WindowEventType::MouseButtonPressed: OnMouseButtonPressed(this, event.mouseButton); break; - case WindowEventType_MouseButtonReleased: + case WindowEventType::MouseButtonReleased: OnMouseButtonReleased(this, event.mouseButton); break; - case WindowEventType_MouseEntered: + case WindowEventType::MouseEntered: OnMouseEntered(this); break; - case WindowEventType_MouseLeft: + case WindowEventType::MouseLeft: OnMouseLeft(this); break; - case WindowEventType_MouseMoved: + case WindowEventType::MouseMoved: OnMouseMoved(this, event.mouseMove); break; - case WindowEventType_MouseWheelMoved: + case WindowEventType::MouseWheelMoved: OnMouseWheelMoved(this, event.mouseWheel); break; - case WindowEventType_Moved: + case WindowEventType::Moved: OnMoved(this, event.position); break; - case WindowEventType_Quit: + case WindowEventType::Quit: OnQuit(this); break; - case WindowEventType_Resized: + case WindowEventType::Resized: OnResized(this, event.size); break; - case WindowEventType_TextEntered: + case WindowEventType::TextEntered: OnTextEntered(this, event.text); break; - case WindowEventType_TextEdited: + case WindowEventType::TextEdited: OnTextEdited(this, event.edit); break; } diff --git a/include/Nazara/Platform/Icon.hpp b/include/Nazara/Platform/Icon.hpp index 080a42171..9e5258ed3 100644 --- a/include/Nazara/Platform/Icon.hpp +++ b/include/Nazara/Platform/Icon.hpp @@ -8,36 +8,35 @@ #define NAZARA_ICON_HPP #include -#include #include +#include namespace Nz { class Image; class IconImpl; - class Icon; - - using IconRef = ObjectRef; - - class NAZARA_PLATFORM_API Icon : public RefCounted + class NAZARA_PLATFORM_API Icon { friend class WindowImpl; public: - inline Icon(); - inline explicit Icon(const Image& icon); - inline ~Icon(); + Icon(); + explicit Icon(const Image& icon); + Icon(const Icon&) = delete; + Icon(Icon&&) noexcept; + ~Icon(); bool Create(const Image& icon); void Destroy(); inline bool IsValid() const; - template static IconRef New(Args&&... args); + Icon& operator=(const Icon&) = delete; + Icon& operator=(Icon&&) noexcept; private: - IconImpl* m_impl; + std::unique_ptr m_impl; }; } diff --git a/include/Nazara/Platform/Icon.inl b/include/Nazara/Platform/Icon.inl index 9dc84932c..53436de52 100644 --- a/include/Nazara/Platform/Icon.inl +++ b/include/Nazara/Platform/Icon.inl @@ -7,35 +7,10 @@ namespace Nz { - Icon::Icon() : - m_impl(nullptr) - { - } - - inline Icon::Icon(const Image& icon) - { - ErrorFlags flags(ErrorFlag_ThrowException, true); - Create(icon); - } - - Icon::~Icon() - { - Destroy(); - } - bool Icon::IsValid() const { return m_impl != nullptr; } - - template - IconRef Icon::New(Args&&... args) - { - std::unique_ptr object(new Icon(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); - } } #include diff --git a/include/Nazara/Platform/Window.hpp b/include/Nazara/Platform/Window.hpp index eebbabe0c..99c9c288d 100644 --- a/include/Nazara/Platform/Window.hpp +++ b/include/Nazara/Platform/Window.hpp @@ -58,7 +58,7 @@ namespace Nz void EnableKeyRepeat(bool enable); void EnableSmoothScrolling(bool enable); - inline const CursorRef& GetCursor() const; + inline const std::shared_ptr& GetCursor() const; inline CursorController& GetCursorController(); inline EventHandler& GetEventHandler(); Vector2i GetPosition() const; @@ -82,11 +82,11 @@ namespace Nz void ProcessEvents(bool block = false); - void SetCursor(CursorRef cursor); + void SetCursor(std::shared_ptr cursor); inline void SetCursor(SystemCursor systemCursor); void SetEventListener(bool listener); void SetFocus(); - void SetIcon(IconRef icon); + void SetIcon(std::shared_ptr icon); void SetMaximumSize(const Vector2i& maxSize); void SetMaximumSize(int width, int height); void SetMinimumSize(const Vector2i& minSize); @@ -133,9 +133,9 @@ namespace Nz std::vector m_pendingEvents; std::condition_variable m_eventCondition; CursorController m_cursorController; - CursorRef m_cursor; + std::shared_ptr m_cursor; EventHandler m_eventHandler; - IconRef m_icon; + std::shared_ptr m_icon; std::mutex m_eventMutex; std::mutex m_eventConditionMutex; bool m_asyncWindow; diff --git a/include/Nazara/Platform/Window.inl b/include/Nazara/Platform/Window.inl index d6ab61579..d81a2ff5d 100644 --- a/include/Nazara/Platform/Window.inl +++ b/include/Nazara/Platform/Window.inl @@ -15,14 +15,14 @@ namespace Nz inline Window::Window(VideoMode mode, const std::string& title, WindowStyleFlags style) : Window() { - ErrorFlags flags(ErrorFlag_ThrowException, true); + ErrorFlags flags(ErrorMode::ThrowException, true); Create(mode, title, style); } inline Window::Window(void* handle) : Window() { - ErrorFlags flags(ErrorFlag_ThrowException, true); + ErrorFlags flags(ErrorMode::ThrowException, true); Create(handle); } @@ -46,7 +46,7 @@ namespace Nz } } - inline const CursorRef& Window::GetCursor() const + inline const std::shared_ptr& Window::GetCursor() const { return m_cursor; } diff --git a/include/Nazara/Renderer.hpp b/include/Nazara/Renderer.hpp index 3b792a6b1..2714ea822 100644 --- a/include/Nazara/Renderer.hpp +++ b/include/Nazara/Renderer.hpp @@ -53,7 +53,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/Nazara/Renderer/CommandBufferBuilder.hpp b/include/Nazara/Renderer/CommandBufferBuilder.hpp index 4cc05a66a..0363703a4 100644 --- a/include/Nazara/Renderer/CommandBufferBuilder.hpp +++ b/include/Nazara/Renderer/CommandBufferBuilder.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,7 @@ namespace Nz class RenderPass; class RenderPipeline; class ShaderBinding; + class Texture; class NAZARA_RENDERER_API CommandBufferBuilder { @@ -33,7 +35,9 @@ namespace Nz virtual ~CommandBufferBuilder(); virtual void BeginDebugRegion(const std::string_view& regionName, const Nz::Color& color) = 0; - virtual void BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect, std::initializer_list clearValues) = 0; + virtual void BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect, const ClearValues* clearValues, std::size_t clearValueCount) = 0; + inline void BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect); + inline void BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect, std::initializer_list clearValues); virtual void BindIndexBuffer(Nz::AbstractBuffer* indexBuffer, UInt64 offset = 0) = 0; virtual void BindPipeline(const RenderPipeline& pipeline) = 0; @@ -51,20 +55,24 @@ namespace Nz virtual void EndDebugRegion() = 0; virtual void EndRenderPass() = 0; + virtual void NextSubpass() = 0; + virtual void PreTransferBarrier() = 0; virtual void PostTransferBarrier() = 0; virtual void SetScissor(Nz::Recti scissorRegion) = 0; virtual void SetViewport(Nz::Recti viewportRegion) = 0; + virtual void TextureBarrier(PipelineStageFlags srcStageMask, PipelineStageFlags dstStageMask, MemoryAccessFlags srcAccessMask, MemoryAccessFlags dstAccessMask, TextureLayout oldLayout, TextureLayout newLayout, const Texture& texture) = 0; + CommandBufferBuilder& operator=(const CommandBufferBuilder&) = delete; CommandBufferBuilder& operator=(CommandBufferBuilder&&) = default; struct ClearValues { - Nz::Color color; - float depth; - UInt32 stencil; + Nz::Color color = Nz::Color::Black; + float depth = 1.f; + UInt32 stencil = 0; }; }; } diff --git a/include/Nazara/Renderer/CommandBufferBuilder.inl b/include/Nazara/Renderer/CommandBufferBuilder.inl index c0a726580..ad156b4ce 100644 --- a/include/Nazara/Renderer/CommandBufferBuilder.inl +++ b/include/Nazara/Renderer/CommandBufferBuilder.inl @@ -7,6 +7,16 @@ namespace Nz { + inline void CommandBufferBuilder::BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect) + { + return BeginRenderPass(framebuffer, renderPass, renderRect, nullptr, 0); + } + + inline void CommandBufferBuilder::BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect, std::initializer_list clearValues) + { + return BeginRenderPass(framebuffer, renderPass, renderRect, clearValues.begin(), clearValues.size()); + } + inline void CommandBufferBuilder::CopyBuffer(const RenderBufferView& from, const RenderBufferView& to) { return CopyBuffer(from, to, from.GetSize()); diff --git a/include/Nazara/Renderer/Enums.hpp b/include/Nazara/Renderer/Enums.hpp index 0b44ae629..84b04504e 100644 --- a/include/Nazara/Renderer/Enums.hpp +++ b/include/Nazara/Renderer/Enums.hpp @@ -11,6 +11,96 @@ namespace Nz { + enum class AttachmentLoadOp + { + Clear, + Discard, + Load + }; + + enum class AttachmentStoreOp + { + Discard, + Store + }; + + enum class MemoryAccess + { + ColorRead, + ColorWrite, + DepthStencilRead, + DepthStencilWrite, + IndexBufferRead, + IndirectCommandRead, + HostRead, + HostWrite, + MemoryRead, + MemoryWrite, + ShaderRead, + ShaderWrite, + TransferRead, + TransferWrite, + UniformBufferRead, + VertexBufferRead, + + Max = VertexBufferRead + }; + + template<> + struct EnumAsFlags + { + static constexpr MemoryAccess max = MemoryAccess::Max; + }; + + using MemoryAccessFlags = Flags; + + enum class PipelineStage + { + TopOfPipe, + + ColorOutput, + DrawIndirect, + FragmentShader, + FragmentTestsEarly, + FragmentTestsLate, + GeometryShader, + TessellationControlShader, + TessellationEvaluationShader, + Transfer, + TransformFeedback, + VertexInput, + VertexShader, + + BottomOfPipe, + + Max = BottomOfPipe + }; + + template<> + struct EnumAsFlags + { + static constexpr PipelineStage max = PipelineStage::Max; + }; + + using PipelineStageFlags = Flags; + + enum class QueueType + { + Compute, + Graphics, + Transfer, + + Max = Transfer + }; + + template<> + struct EnumAsFlags + { + static constexpr QueueType max = QueueType::Max; + }; + + using QueueTypeFlags = Flags; + enum class RenderAPI { Direct3D, ///< Microsoft Render API, only works on MS platforms @@ -24,6 +114,8 @@ namespace Nz Max = Unknown }; + constexpr std::size_t RenderAPICount = static_cast(RenderAPI::Max) + 1; + enum class RenderDeviceType { Integrated, ///< Hardware-accelerated chipset integrated to a CPU (ex: Intel Graphics HD 4000) @@ -50,25 +142,41 @@ namespace Nz HLSL, MSL, NazaraBinary, + NazaraShader, SpirV }; - enum class QueueType + enum class TextureLayout { - Compute, - Graphics, - Transfer, + ColorInput, + ColorOutput, + DepthStencilReadOnly, + DepthStencilReadWrite, + Present, + TransferSource, + TransferDestination, + Undefined + }; - Max = Transfer + enum class TextureUsage + { + ColorAttachment, + DepthStencilAttachment, + InputAttachment, + ShaderSampling, + TransferSource, + TransferDestination, + + Max = TransferDestination }; template<> - struct EnumAsFlags + struct EnumAsFlags { - static constexpr QueueType max = QueueType::Max; + static constexpr TextureUsage max = TextureUsage::Max; }; - using QueueTypeFlags = Flags; + using TextureUsageFlags = Flags; } #endif // NAZARA_ENUMS_RENDERER_HPP diff --git a/include/Nazara/Renderer/RenderDevice.hpp b/include/Nazara/Renderer/RenderDevice.hpp index 000aca2e2..de8f5e058 100644 --- a/include/Nazara/Renderer/RenderDevice.hpp +++ b/include/Nazara/Renderer/RenderDevice.hpp @@ -10,18 +10,24 @@ #include #include #include +#include +#include +#include #include #include #include #include +#include +#include #include +#include #include #include namespace Nz { class CommandPool; - class ShaderStageImpl; + class ShaderModule; class NAZARA_RENDERER_API RenderDevice { @@ -29,14 +35,21 @@ namespace Nz RenderDevice() = default; virtual ~RenderDevice(); + virtual const RenderDeviceInfo& GetDeviceInfo() const = 0; + virtual std::shared_ptr InstantiateBuffer(BufferType type) = 0; virtual std::shared_ptr InstantiateCommandPool(QueueType queueType) = 0; + virtual std::shared_ptr InstantiateFramebuffer(unsigned int width, unsigned int height, const std::shared_ptr& renderPass, const std::vector>& attachments) = 0; + virtual std::shared_ptr InstantiateRenderPass(std::vector attachments, std::vector subpassDescriptions, std::vector subpassDependencies) = 0; virtual std::shared_ptr InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) = 0; virtual std::shared_ptr InstantiateRenderPipelineLayout(RenderPipelineLayoutInfo pipelineLayoutInfo) = 0; - virtual std::shared_ptr InstantiateShaderStage(ShaderStageType type, ShaderLanguage lang, const void* source, std::size_t sourceSize) = 0; - std::shared_ptr InstantiateShaderStage(ShaderStageType type, ShaderLanguage lang, const std::filesystem::path& sourcePath); + virtual std::shared_ptr InstantiateShaderModule(ShaderStageTypeFlags shaderStages, ShaderAst::StatementPtr& shaderAst, const ShaderWriter::States& states) = 0; + virtual std::shared_ptr InstantiateShaderModule(ShaderStageTypeFlags shaderStages, ShaderLanguage lang, const void* source, std::size_t sourceSize, const ShaderWriter::States& states) = 0; + std::shared_ptr InstantiateShaderModule(ShaderStageTypeFlags shaderStages, ShaderLanguage lang, const std::filesystem::path& sourcePath, const ShaderWriter::States& states); virtual std::shared_ptr InstantiateTexture(const TextureInfo& params) = 0; virtual std::shared_ptr InstantiateTextureSampler(const TextureSamplerInfo& params) = 0; + + virtual bool IsTextureFormatSupported(PixelFormat format, TextureUsage usage) const = 0; }; } diff --git a/include/Nazara/Renderer/RenderDeviceInfo.hpp b/include/Nazara/Renderer/RenderDeviceInfo.hpp index 5e6853ca0..d11f9e7c6 100644 --- a/include/Nazara/Renderer/RenderDeviceInfo.hpp +++ b/include/Nazara/Renderer/RenderDeviceInfo.hpp @@ -9,11 +9,18 @@ #include #include +#include namespace Nz { + struct RenderDeviceLimits + { + UInt64 minUniformBufferOffsetAlignment; + }; + struct RenderDeviceInfo { + RenderDeviceLimits limits; RenderDeviceType type; std::string name; }; diff --git a/include/Nazara/Renderer/RenderFrame.hpp b/include/Nazara/Renderer/RenderFrame.hpp index 1e16bd10c..effc367ec 100644 --- a/include/Nazara/Renderer/RenderFrame.hpp +++ b/include/Nazara/Renderer/RenderFrame.hpp @@ -10,13 +10,13 @@ #include #include #include +#include #include namespace Nz { class CommandBuffer; class CommandBufferBuilder; - class RenderImage; class UploadPool; class NAZARA_RENDERER_API RenderFrame @@ -34,10 +34,13 @@ namespace Nz inline bool IsFramebufferInvalidated() const; - void SubmitCommandBuffer(CommandBuffer* commandBuffer, QueueTypeFlags queueTypeFlags) ; + template void PushForRelease(T&& value); + template void PushReleaseCallback(F&& releaseCallback); void Present(); + void SubmitCommandBuffer(CommandBuffer* commandBuffer, QueueTypeFlags queueTypeFlags) ; + inline explicit operator bool(); RenderFrame& operator=(const RenderFrame&) = delete; diff --git a/include/Nazara/Renderer/RenderFrame.inl b/include/Nazara/Renderer/RenderFrame.inl index 6a3cd4e19..9a04e1981 100644 --- a/include/Nazara/Renderer/RenderFrame.inl +++ b/include/Nazara/Renderer/RenderFrame.inl @@ -23,6 +23,21 @@ namespace Nz return m_framebufferInvalidation; } + template + void RenderFrame::PushForRelease(T&& value) + { + return PushReleaseCallback([v = std::forward(value)] {}); + } + + template + void RenderFrame::PushReleaseCallback(F&& releaseCallback) + { + if (!m_image) + throw std::runtime_error("frame is either invalid or has already been presented"); + + m_image->PushReleaseCallback(std::forward(releaseCallback)); + } + inline RenderFrame::operator bool() { return m_image != nullptr; diff --git a/include/Nazara/Renderer/RenderImage.hpp b/include/Nazara/Renderer/RenderImage.hpp index 3081ac231..b345f0583 100644 --- a/include/Nazara/Renderer/RenderImage.hpp +++ b/include/Nazara/Renderer/RenderImage.hpp @@ -21,20 +21,61 @@ namespace Nz class NAZARA_RENDERER_API RenderImage { public: + class Releasable; + template class ReleasableLambda; + virtual ~RenderImage(); virtual void Execute(const std::function& callback, QueueTypeFlags queueTypeFlags) = 0; + inline void FlushReleaseQueue(); + virtual UploadPool& GetUploadPool() = 0; - virtual void SubmitCommandBuffer(CommandBuffer* commandBuffer, QueueTypeFlags queueTypeFlags) = 0; - virtual void Present() = 0; + template void PushReleaseCallback(F&& callback); + + virtual void SubmitCommandBuffer(CommandBuffer* commandBuffer, QueueTypeFlags queueTypeFlags) = 0; + protected: RenderImage() = default; RenderImage(const RenderImage&) = delete; - RenderImage(RenderImage&&) = default; + RenderImage(RenderImage&&) = delete; + + private: + static constexpr std::size_t BlockSize = 4 * 1024; + + using Block = std::vector; + + std::vector m_releaseQueue; + std::vector m_releaseMemoryPool; + }; + + class NAZARA_RENDERER_API RenderImage::Releasable + { + public: + virtual ~Releasable(); + + virtual void Release() = 0; + }; + + template + class RenderImage::ReleasableLambda : public Releasable + { + public: + template ReleasableLambda(U&& lambda); + ReleasableLambda(const ReleasableLambda&) = delete; + ReleasableLambda(ReleasableLambda&&) = delete; + ~ReleasableLambda() = default; + + void Release() override; + + ReleasableLambda& operator=(const ReleasableLambda&) = delete; + ReleasableLambda& operator=(ReleasableLambda&&) = delete; + + private: + T m_lambda; }; } diff --git a/include/Nazara/Renderer/RenderImage.inl b/include/Nazara/Renderer/RenderImage.inl index 20f3103f8..fd4d3a638 100644 --- a/include/Nazara/Renderer/RenderImage.inl +++ b/include/Nazara/Renderer/RenderImage.inl @@ -3,10 +3,91 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include +#include #include namespace Nz { + inline void RenderImage::FlushReleaseQueue() + { + for (Releasable* releasable : m_releaseQueue) + { + releasable->Release(); + PlacementDestroy(releasable); + } + m_releaseQueue.clear(); + + for (auto& memoryblock : m_releaseMemoryPool) + memoryblock.clear(); + } + + template + void RenderImage::PushReleaseCallback(F&& callback) + { + using Functor = ReleasableLambda>>; + + constexpr std::size_t functorSize = sizeof(Functor); + constexpr std::size_t functorAlignment = alignof(Functor); + + // Try to minimize lost space + struct + { + Block* block = nullptr; + UInt64 alignedOffset = 0; + UInt64 lostSpace = 0; + } bestBlock; + + for (Block& block : m_releaseMemoryPool) + { + std::size_t freeOffset = block.size(); + + UInt64 alignedOffset = Align(freeOffset, functorAlignment); + if (alignedOffset + functorSize > block.capacity()) + continue; //< Not enough space + + UInt64 lostSpace = alignedOffset - freeOffset; + + if (!bestBlock.block || lostSpace < bestBlock.lostSpace) + { + bestBlock.block = █ + bestBlock.alignedOffset = alignedOffset; + bestBlock.lostSpace = lostSpace; + } + } + + // No block found, allocate a new one + if (!bestBlock.block) + { + Block newBlock; + newBlock.reserve(BlockSize); + + bestBlock.block = &m_releaseMemoryPool.emplace_back(std::move(newBlock)); + bestBlock.alignedOffset = 0; + bestBlock.lostSpace = 0; + } + + Block& targetBlock = *bestBlock.block; + targetBlock.resize(bestBlock.alignedOffset + functorSize); + + Functor* releasable = reinterpret_cast(&targetBlock[bestBlock.alignedOffset]); + PlacementNew(releasable, std::forward(callback)); + + m_releaseQueue.push_back(releasable); + } + + template + template + RenderImage::ReleasableLambda::ReleasableLambda(U&& lambda) : + m_lambda(std::forward(lambda)) + { + } + + template + void RenderImage::ReleasableLambda::Release() + { + m_lambda(); + } } #include diff --git a/include/Nazara/Renderer/RenderPass.hpp b/include/Nazara/Renderer/RenderPass.hpp index 10f57ddbe..38868d541 100644 --- a/include/Nazara/Renderer/RenderPass.hpp +++ b/include/Nazara/Renderer/RenderPass.hpp @@ -11,6 +11,9 @@ #include #include #include +#include +#include +#include namespace Nz { @@ -18,20 +21,66 @@ namespace Nz { public: struct Attachment; + struct SubpassDependency; + struct SubpassDescription; - RenderPass() = default; + inline RenderPass(std::vector attachments, std::vector subpassDescriptions, std::vector subpassDependencies); RenderPass(const RenderPass&) = delete; RenderPass(RenderPass&&) noexcept = default; virtual ~RenderPass(); + inline const Attachment& GetAttachment(std::size_t attachmentIndex) const; + inline std::size_t GetAttachmentCount() const; + inline const std::vector& GetAttachments() const; + inline const std::vector& GetSubpassDescriptions() const; + inline const std::vector& GetSubpassDependencies() const; + RenderPass& operator=(const RenderPass&) = delete; RenderPass& operator=(RenderPass&&) noexcept = default; struct Attachment { PixelFormat format; - // TODO + AttachmentLoadOp loadOp = AttachmentLoadOp::Load; + AttachmentLoadOp stencilLoadOp = AttachmentLoadOp::Load; + AttachmentStoreOp storeOp = AttachmentStoreOp::Store; + AttachmentStoreOp stencilStoreOp = AttachmentStoreOp::Store; + TextureLayout initialLayout = TextureLayout::Undefined; + TextureLayout finalLayout = TextureLayout::Present; }; + + struct AttachmentReference + { + std::size_t attachmentIndex; + TextureLayout attachmentLayout = TextureLayout::ColorInput; + }; + + struct SubpassDependency + { + std::size_t fromSubpassIndex; + PipelineStageFlags fromStages; + MemoryAccessFlags fromAccessFlags; + + std::size_t toSubpassIndex; + PipelineStageFlags toStages; + MemoryAccessFlags toAccessFlags; + bool tilable = false; + }; + + struct SubpassDescription + { + std::vector colorAttachment; + std::vector inputAttachments; + std::vector preserveAttachments; + std::optional depthStencilAttachment; + }; + + static constexpr std::size_t ExternalSubpassIndex = std::numeric_limits::max(); + + protected: + std::vector m_attachments; + std::vector m_subpassDependencies; + std::vector m_subpassDescriptions; }; } diff --git a/include/Nazara/Renderer/RenderPass.inl b/include/Nazara/Renderer/RenderPass.inl index c2c3865a3..cc491890c 100644 --- a/include/Nazara/Renderer/RenderPass.inl +++ b/include/Nazara/Renderer/RenderPass.inl @@ -3,10 +3,43 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include namespace Nz { + inline RenderPass::RenderPass(std::vector attachments, std::vector subpassDescriptions, std::vector subpassDependencies) : + m_attachments(std::move(attachments)), + m_subpassDependencies(std::move(subpassDependencies)), + m_subpassDescriptions(std::move(subpassDescriptions)) + { + } + + inline auto RenderPass::GetAttachment(std::size_t attachmentIndex) const -> const Attachment& + { + assert(attachmentIndex < m_attachments.size()); + return m_attachments[attachmentIndex]; + } + + inline std::size_t RenderPass::GetAttachmentCount() const + { + return m_attachments.size(); + } + + inline auto RenderPass::GetAttachments() const -> const std::vector& + { + return m_attachments; + } + + inline auto RenderPass::GetSubpassDescriptions() const -> const std::vector& + { + return m_subpassDescriptions; + } + + inline auto RenderPass::GetSubpassDependencies() const -> const std::vector& + { + return m_subpassDependencies; + } } #include diff --git a/include/Nazara/Renderer/RenderPipeline.hpp b/include/Nazara/Renderer/RenderPipeline.hpp index 6e938eba7..a6485cd85 100644 --- a/include/Nazara/Renderer/RenderPipeline.hpp +++ b/include/Nazara/Renderer/RenderPipeline.hpp @@ -10,7 +10,6 @@ #include #include #include -//#include namespace Nz { @@ -19,11 +18,11 @@ namespace Nz struct VertexBufferData { std::size_t binding; - VertexDeclarationConstRef declaration; + std::shared_ptr declaration; }; std::shared_ptr pipelineLayout; - std::vector> shaderStages; + std::vector> shaderModules; std::vector vertexBuffers; }; @@ -32,6 +31,8 @@ namespace Nz public: RenderPipeline() = default; virtual ~RenderPipeline(); + + virtual const RenderPipelineInfo& GetPipelineInfo() const = 0; }; } diff --git a/include/Nazara/Renderer/RenderPipelineLayout.hpp b/include/Nazara/Renderer/RenderPipelineLayout.hpp index 38c1b6ef3..c0d64b26a 100644 --- a/include/Nazara/Renderer/RenderPipelineLayout.hpp +++ b/include/Nazara/Renderer/RenderPipelineLayout.hpp @@ -21,7 +21,6 @@ namespace Nz { struct Binding { - std::string name; //< FIXME: wtf is this? ShaderBindingType type; ShaderStageTypeFlags shaderStageFlags; unsigned int index; diff --git a/include/Nazara/Renderer/RenderStates.hpp b/include/Nazara/Renderer/RenderStates.hpp index dca3d4c7c..0119f7c99 100644 --- a/include/Nazara/Renderer/RenderStates.hpp +++ b/include/Nazara/Renderer/RenderStates.hpp @@ -15,23 +15,32 @@ namespace Nz { - class ShaderStageImpl; + class ShaderModule; struct RenderStates { - BlendFunc dstBlend = BlendFunc_Zero; - BlendFunc srcBlend = BlendFunc_One; - FaceFilling faceFilling = FaceFilling_Fill; - FaceSide cullingSide = FaceSide_Back; - RendererComparison depthCompare = RendererComparison_Less; - PrimitiveMode primitiveMode = PrimitiveMode_TriangleList; + FaceFilling faceFilling = FaceFilling::Fill; + FaceSide cullingSide = FaceSide::Back; + FrontFace frontFace = FrontFace::Clockwise; + RendererComparison depthCompare = RendererComparison::Less; + PrimitiveMode primitiveMode = PrimitiveMode::TriangleList; + + struct + { + BlendEquation modeAlpha = BlendEquation::Add; + BlendEquation modeColor = BlendEquation::Add; + BlendFunc dstAlpha = BlendFunc::Zero; + BlendFunc dstColor = BlendFunc::Zero; + BlendFunc srcAlpha = BlendFunc::One; + BlendFunc srcColor = BlendFunc::One; + } blend; struct { - RendererComparison compare = RendererComparison_Always; - StencilOperation depthFail = StencilOperation_Keep; - StencilOperation fail = StencilOperation_Keep; - StencilOperation pass = StencilOperation_Keep; + RendererComparison compare = RendererComparison::Always; + StencilOperation depthFail = StencilOperation::Keep; + StencilOperation fail = StencilOperation::Keep; + StencilOperation pass = StencilOperation::Keep; UInt32 compareMask = 0xFFFFFFFF; UInt32 reference = 0; UInt32 writeMask = 0xFFFFFFFF; diff --git a/include/Nazara/Renderer/RenderStates.inl b/include/Nazara/Renderer/RenderStates.inl index 2a1fc08fc..f688532fe 100644 --- a/include/Nazara/Renderer/RenderStates.inl +++ b/include/Nazara/Renderer/RenderStates.inl @@ -30,8 +30,12 @@ namespace Nz if (lhs.blending) //< Remember, at this time we know lhs.blending == rhs.blending { - NazaraRenderStateMember(dstBlend); - NazaraRenderStateMember(srcBlend); + NazaraRenderStateMember(blend.dstAlpha); + NazaraRenderStateMember(blend.dstColor); + NazaraRenderStateMember(blend.modeAlpha); + NazaraRenderStateMember(blend.modeColor); + NazaraRenderStateMember(blend.srcAlpha); + NazaraRenderStateMember(blend.srcColor); } if (lhs.depthBuffer) @@ -101,8 +105,12 @@ namespace std if (pipelineInfo.blending) //< Remember, at this time we know lhs.blending == rhs.blending { - NazaraRenderStateEnum(dstBlend); - NazaraRenderStateEnum(srcBlend); + NazaraRenderStateEnum(blend.dstAlpha); + NazaraRenderStateEnum(blend.dstColor); + NazaraRenderStateEnum(blend.modeAlpha); + NazaraRenderStateEnum(blend.modeColor); + NazaraRenderStateEnum(blend.srcAlpha); + NazaraRenderStateEnum(blend.srcColor); } if (pipelineInfo.depthBuffer) diff --git a/include/Nazara/Renderer/RenderWindow.hpp b/include/Nazara/Renderer/RenderWindow.hpp index d02e37323..c4534c2ea 100644 --- a/include/Nazara/Renderer/RenderWindow.hpp +++ b/include/Nazara/Renderer/RenderWindow.hpp @@ -25,19 +25,19 @@ namespace Nz { public: inline RenderWindow(); - inline RenderWindow(VideoMode mode, const std::string& title, WindowStyleFlags style = WindowStyle_Default, const RenderWindowParameters& parameters = RenderWindowParameters()); - inline explicit RenderWindow(void* handle, const RenderWindowParameters ¶meters = RenderWindowParameters()); + inline RenderWindow(std::shared_ptr renderDevice, VideoMode mode, const std::string& title, WindowStyleFlags style = WindowStyle_Default, const RenderWindowParameters& parameters = RenderWindowParameters()); + inline RenderWindow(std::shared_ptr renderDevice, void* handle, const RenderWindowParameters& parameters = RenderWindowParameters()); inline ~RenderWindow(); - inline bool Create(VideoMode mode, const std::string& title, WindowStyleFlags style = WindowStyle_Default, const RenderWindowParameters& parameters = RenderWindowParameters()); - inline bool Create(void* handle, const RenderWindowParameters ¶meters = RenderWindowParameters()); + bool Create(std::shared_ptr renderDevice, VideoMode mode, const std::string& title, WindowStyleFlags style = WindowStyle_Default, const RenderWindowParameters& parameters = RenderWindowParameters()); + bool Create(std::shared_ptr renderDevice, void* handle, const RenderWindowParameters ¶meters = RenderWindowParameters()); void Display(); void EnableVerticalSync(bool enabled); inline RenderWindowImpl* GetImpl(); - std::shared_ptr GetRenderDevice(); + inline const std::shared_ptr& GetRenderDevice() const; inline RenderSurface* GetSurface(); inline bool IsValid() const; @@ -53,9 +53,10 @@ namespace Nz void OnWindowResized() override; private: + std::shared_ptr m_renderDevice; + std::unique_ptr m_surface; std::unique_ptr m_impl; Clock m_clock; - std::unique_ptr m_surface; RenderWindowParameters m_parameters; unsigned int m_framerateLimit; }; diff --git a/include/Nazara/Renderer/RenderWindow.inl b/include/Nazara/Renderer/RenderWindow.inl index 9179ef577..c93291e46 100644 --- a/include/Nazara/Renderer/RenderWindow.inl +++ b/include/Nazara/Renderer/RenderWindow.inl @@ -12,19 +12,19 @@ namespace Nz { } - inline RenderWindow::RenderWindow(VideoMode mode, const std::string& title, WindowStyleFlags style, const RenderWindowParameters& parameters) : + inline RenderWindow::RenderWindow(std::shared_ptr renderDevice, VideoMode mode, const std::string& title, WindowStyleFlags style, const RenderWindowParameters& parameters) : RenderWindow() { - ErrorFlags errFlags(ErrorFlag_ThrowException, true); + ErrorFlags errFlags(ErrorMode::ThrowException, true); - Create(mode, title, style, parameters); + Create(std::move(renderDevice), mode, title, style, parameters); } - inline RenderWindow::RenderWindow(void* handle, const RenderWindowParameters& parameters) + inline RenderWindow::RenderWindow(std::shared_ptr renderDevice, void* handle, const RenderWindowParameters& parameters) { - ErrorFlags errFlags(ErrorFlag_ThrowException, true); + ErrorFlags errFlags(ErrorMode::ThrowException, true); - Create(handle, parameters); + Create(std::move(renderDevice), handle, parameters); } inline RenderWindow::~RenderWindow() @@ -32,25 +32,16 @@ namespace Nz Destroy(); } - inline bool RenderWindow::Create(VideoMode mode, const std::string& title, WindowStyleFlags style, const RenderWindowParameters& parameters) - { - m_parameters = parameters; - - return Window::Create(mode, title, style); - } - - inline bool RenderWindow::Create(void* handle, const RenderWindowParameters& parameters) - { - m_parameters = parameters; - - return Window::Create(handle); - } - inline RenderWindowImpl* RenderWindow::GetImpl() { return m_impl.get(); } + inline const std::shared_ptr& RenderWindow::GetRenderDevice() const + { + return m_renderDevice; + } + inline RenderSurface* RenderWindow::GetSurface() { return m_surface.get(); diff --git a/include/Nazara/Renderer/RenderWindowImpl.hpp b/include/Nazara/Renderer/RenderWindowImpl.hpp index dec071274..2ef81f2f5 100644 --- a/include/Nazara/Renderer/RenderWindowImpl.hpp +++ b/include/Nazara/Renderer/RenderWindowImpl.hpp @@ -13,14 +13,16 @@ #include #include #include +#include #include +#include namespace Nz { class CommandPool; class Framebuffer; class RendererImpl; - class RenderPass; + class RenderDevice; class RenderSurface; class NAZARA_RENDERER_API RenderWindowImpl @@ -35,8 +37,10 @@ namespace Nz virtual std::shared_ptr CreateCommandPool(QueueType queueType) = 0; virtual const Framebuffer& GetFramebuffer() const = 0; - virtual std::shared_ptr GetRenderDevice() = 0; virtual const RenderPass& GetRenderPass() const = 0; + + protected: + static void BuildRenderPass(PixelFormat colorFormat, PixelFormat depthFormat, std::vector& attachments, std::vector& subpassDescriptions, std::vector& subpassDependencies); }; } diff --git a/include/Nazara/Renderer/RenderWindowParameters.hpp b/include/Nazara/Renderer/RenderWindowParameters.hpp index 9c7fcb576..927552482 100644 --- a/include/Nazara/Renderer/RenderWindowParameters.hpp +++ b/include/Nazara/Renderer/RenderWindowParameters.hpp @@ -15,7 +15,7 @@ namespace Nz { struct RenderWindowParameters { - std::vector depthFormats = {Nz::PixelFormat_Depth32, Nz::PixelFormat_Depth24}; //< By order of preference + std::vector depthFormats = {Nz::PixelFormat::Depth24Stencil8, Nz::PixelFormat::Depth32FStencil8, Nz::PixelFormat::Depth16Stencil8, Nz::PixelFormat::Depth32F, Nz::PixelFormat::Depth24}; //< By order of preference bool verticalSync = false; }; } diff --git a/include/Nazara/Renderer/Renderer.hpp b/include/Nazara/Renderer/Renderer.hpp index 72d51b3a7..2a97441a3 100644 --- a/include/Nazara/Renderer/Renderer.hpp +++ b/include/Nazara/Renderer/Renderer.hpp @@ -34,12 +34,22 @@ namespace Nz inline RendererImpl* GetRendererImpl(); + std::shared_ptr InstanciateRenderDevice(std::size_t deviceIndex); + + RenderAPI QueryAPI() const; + std::string QueryAPIString() const; + UInt32 QueryAPIVersion() const; + + const std::vector& QueryRenderDevices() const; + struct Config { - Nz::RenderAPI preferredAPI = Nz::RenderAPI::Unknown; + Nz::RenderAPI preferredAPI = RenderAPI::Unknown; }; private: + void LoadBackend(const Config& config); + std::unique_ptr m_rendererImpl; DynLib m_rendererLib; diff --git a/include/Nazara/Renderer/RendererImpl.hpp b/include/Nazara/Renderer/RendererImpl.hpp index 8bff2d8a2..54518ece8 100644 --- a/include/Nazara/Renderer/RendererImpl.hpp +++ b/include/Nazara/Renderer/RendererImpl.hpp @@ -43,7 +43,7 @@ namespace Nz virtual std::string QueryAPIString() const = 0; virtual UInt32 QueryAPIVersion() const = 0; - virtual std::vector QueryRenderDevices() const = 0; + virtual const std::vector& QueryRenderDevices() const = 0; virtual bool Prepare(const ParameterList& parameters) = 0; }; diff --git a/include/Nazara/Renderer/ShaderBinding.hpp b/include/Nazara/Renderer/ShaderBinding.hpp index 4105974bc..53f38b128 100644 --- a/include/Nazara/Renderer/ShaderBinding.hpp +++ b/include/Nazara/Renderer/ShaderBinding.hpp @@ -34,7 +34,8 @@ namespace Nz ShaderBinding(ShaderBinding&&) = delete; virtual ~ShaderBinding(); - virtual void Update(std::initializer_list bindings) = 0; + virtual void Update(const Binding* bindings, std::size_t bindingCount) = 0; + inline void Update(std::initializer_list bindings); ShaderBinding& operator=(const ShaderBinding&) = delete; ShaderBinding& operator=(ShaderBinding&&) = delete; diff --git a/include/Nazara/Renderer/ShaderBinding.inl b/include/Nazara/Renderer/ShaderBinding.inl index 6d1f7f3d0..971be9ffd 100644 --- a/include/Nazara/Renderer/ShaderBinding.inl +++ b/include/Nazara/Renderer/ShaderBinding.inl @@ -7,6 +7,11 @@ namespace Nz { + inline void ShaderBinding::Update(std::initializer_list bindings) + { + Update(bindings.begin(), bindings.size()); + } + inline void ShaderBindingDeleter::operator()(ShaderBinding* binding) { binding->Release(); diff --git a/include/Nazara/Renderer/ShaderStageImpl.hpp b/include/Nazara/Renderer/ShaderModule.hpp similarity index 58% rename from include/Nazara/Renderer/ShaderStageImpl.hpp rename to include/Nazara/Renderer/ShaderModule.hpp index 4bee731e2..30608212a 100644 --- a/include/Nazara/Renderer/ShaderStageImpl.hpp +++ b/include/Nazara/Renderer/ShaderModule.hpp @@ -4,8 +4,8 @@ #pragma once -#ifndef NAZARA_RENDERER_SHADERSTAGEIMPL_HPP -#define NAZARA_RENDERER_SHADERSTAGEIMPL_HPP +#ifndef NAZARA_RENDERER_SHADERMODULE_HPP +#define NAZARA_RENDERER_SHADERMODULE_HPP #include #include @@ -13,12 +13,12 @@ namespace Nz { - class NAZARA_RENDERER_API ShaderStageImpl + class NAZARA_RENDERER_API ShaderModule { public: - ShaderStageImpl() = default; - virtual ~ShaderStageImpl(); + ShaderModule() = default; + virtual ~ShaderModule(); }; } -#endif // NAZARA_RENDERER_SHADERSTAGEIMPL_HPP +#endif // NAZARA_RENDERER_SHADERSTAGE_HPP diff --git a/include/Nazara/Renderer/Texture.hpp b/include/Nazara/Renderer/Texture.hpp index 4fa0ebc75..f20fe9069 100644 --- a/include/Nazara/Renderer/Texture.hpp +++ b/include/Nazara/Renderer/Texture.hpp @@ -8,23 +8,44 @@ #define NAZARA_TEXTURE_HPP #include +#include +#include +#include #include #include #include -#include +#include +#include namespace Nz { + class RenderDevice; + struct TextureInfo { PixelFormat pixelFormat; ImageType type; + TextureUsageFlags usageFlags = TextureUsage::ShaderSampling | TextureUsage::TransferDestination; + UInt8 mipmapLevel = 1; unsigned int depth = 1; unsigned int height; - unsigned int mipmapLevel = 1; unsigned int width; }; + struct NAZARA_RENDERER_API TextureParams : ImageParams + { + std::shared_ptr renderDevice; + TextureUsageFlags usageFlags = TextureUsage::ShaderSampling | TextureUsage::TransferDestination; + + bool IsValid() const; + }; + + class Texture; + + using TextureLibrary = ObjectLibrary; + using TextureLoader = ResourceLoader; + using TextureManager = ResourceManager; + class NAZARA_RENDERER_API Texture : public Resource { public: @@ -42,6 +63,23 @@ namespace Nz static inline unsigned int GetLevelSize(unsigned int size, unsigned int level); + static std::shared_ptr CreateFromImage(const Image& image, const TextureParams& params); + + // Load + static std::shared_ptr LoadFromFile(const std::filesystem::path& filePath, const TextureParams& params); + static std::shared_ptr LoadFromMemory(const void* data, std::size_t size, const TextureParams& params); + static std::shared_ptr LoadFromStream(Stream& stream, const TextureParams& params); + + // LoadArray + static std::shared_ptr LoadArrayFromFile(const std::filesystem::path& filePath, const TextureParams& textureParams, const Vector2ui& atlasSize = Vector2ui(2, 2)); + static std::shared_ptr LoadArrayFromMemory(const void* data, std::size_t size, const TextureParams& textureParams, const Vector2ui& atlasSize = Vector2ui(2, 2)); + static std::shared_ptr LoadArrayFromStream(Stream& stream, const TextureParams& textureParams, const Vector2ui& atlasSize = Vector2ui(2, 2)); + + // LoadCubemap + static std::shared_ptr LoadCubemapFromFile(const std::filesystem::path& filePath, const TextureParams& textureParams, const CubemapParams& cubemapParams = CubemapParams()); + static std::shared_ptr LoadCubemapFromMemory(const void* data, std::size_t size, const TextureParams& textureParams, const CubemapParams& cubemapParams = CubemapParams()); + static std::shared_ptr LoadCubemapFromStream(Stream& stream, const TextureParams& textureParams, const CubemapParams& cubemapParams = CubemapParams()); + Texture& operator=(const Texture&) = delete; Texture& operator=(Texture&&) = delete; }; diff --git a/include/Nazara/Renderer/TextureSampler.hpp b/include/Nazara/Renderer/TextureSampler.hpp index e050298c3..62195d6c3 100644 --- a/include/Nazara/Renderer/TextureSampler.hpp +++ b/include/Nazara/Renderer/TextureSampler.hpp @@ -10,18 +10,22 @@ #include #include #include +#include namespace Nz { struct TextureSamplerInfo { float anisotropyLevel = 0.f; - SamplerFilter magFilter = SamplerFilter_Linear; - SamplerFilter minFilter = SamplerFilter_Linear; - SamplerMipmapMode mipmapMode = SamplerMipmapMode_Linear; - SamplerWrap wrapModeU = SamplerWrap_Clamp; - SamplerWrap wrapModeV = SamplerWrap_Clamp; - SamplerWrap wrapModeW = SamplerWrap_Clamp; + SamplerFilter magFilter = SamplerFilter::Linear; + SamplerFilter minFilter = SamplerFilter::Linear; + SamplerMipmapMode mipmapMode = SamplerMipmapMode::Linear; + SamplerWrap wrapModeU = SamplerWrap::Clamp; + SamplerWrap wrapModeV = SamplerWrap::Clamp; + SamplerWrap wrapModeW = SamplerWrap::Clamp; + + inline bool operator==(const TextureSamplerInfo& samplerInfo) const; + inline bool operator!=(const TextureSamplerInfo& samplerInfo) const; }; class NAZARA_RENDERER_API TextureSampler @@ -37,6 +41,9 @@ namespace Nz }; } +template<> +struct std::hash; + #include #endif // NAZARA_TEXTURE_HPP diff --git a/include/Nazara/Renderer/TextureSampler.inl b/include/Nazara/Renderer/TextureSampler.inl index a741958f0..a7f802bcb 100644 --- a/include/Nazara/Renderer/TextureSampler.inl +++ b/include/Nazara/Renderer/TextureSampler.inl @@ -3,10 +3,60 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include +#include #include namespace Nz { + inline bool TextureSamplerInfo::operator==(const TextureSamplerInfo& samplerInfo) const + { + if (!NumberEquals(anisotropyLevel, samplerInfo.anisotropyLevel, 0.99f)) + return false; + + if (magFilter != samplerInfo.magFilter) + return false; + + if (minFilter != samplerInfo.minFilter) + return false; + + if (mipmapMode != samplerInfo.mipmapMode) + return false; + + if (wrapModeU != samplerInfo.wrapModeU) + return false; + + if (wrapModeV != samplerInfo.wrapModeV) + return false; + + if (wrapModeW != samplerInfo.wrapModeW) + return false; + + return true; + } + + inline bool TextureSamplerInfo::operator!=(const TextureSamplerInfo& samplerInfo) const + { + return !operator==(samplerInfo); + } } +template<> +struct std::hash +{ + std::size_t operator()(const Nz::TextureSamplerInfo& sampler) const + { + std::size_t seed = 0; + Nz::HashCombine(seed, sampler.anisotropyLevel); + Nz::HashCombine(seed, sampler.magFilter); + Nz::HashCombine(seed, sampler.minFilter); + Nz::HashCombine(seed, sampler.mipmapMode); + Nz::HashCombine(seed, sampler.wrapModeU); + Nz::HashCombine(seed, sampler.wrapModeV); + Nz::HashCombine(seed, sampler.wrapModeW); + + return seed; + } +}; + #include diff --git a/include/Nazara/Shader.hpp b/include/Nazara/Shader.hpp index d72fa4367..1bac8589f 100644 --- a/include/Nazara/Shader.hpp +++ b/include/Nazara/Shader.hpp @@ -31,30 +31,22 @@ #include #include +#include #include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include #include #include +#include #include #include +#include #include #include #include #include +#include #include #endif // NAZARA_GLOBAL_SHADER_HPP diff --git a/include/Nazara/Shader/Ast/AstCloner.hpp b/include/Nazara/Shader/Ast/AstCloner.hpp new file mode 100644 index 000000000..ef4b50670 --- /dev/null +++ b/include/Nazara/Shader/Ast/AstCloner.hpp @@ -0,0 +1,88 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADERASTCLONER_HPP +#define NAZARA_SHADERASTCLONER_HPP + +#include +#include +#include +#include +#include + +namespace Nz::ShaderAst +{ + class NAZARA_SHADER_API AstCloner : public AstExpressionVisitor, public AstStatementVisitor + { + public: + AstCloner() = default; + AstCloner(const AstCloner&) = delete; + AstCloner(AstCloner&&) = delete; + ~AstCloner() = default; + + ExpressionPtr Clone(const ExpressionPtr& statement); + StatementPtr Clone(const StatementPtr& statement); + + AstCloner& operator=(const AstCloner&) = delete; + AstCloner& operator=(AstCloner&&) = delete; + + protected: + inline ExpressionPtr CloneExpression(const ExpressionPtr& expr); + inline StatementPtr CloneStatement(const StatementPtr& statement); + + virtual ExpressionPtr CloneExpression(Expression& expr); + virtual StatementPtr CloneStatement(Statement& statement); + + virtual ExpressionPtr Clone(AccessIdentifierExpression& node); + virtual ExpressionPtr Clone(AccessIndexExpression& node); + virtual ExpressionPtr Clone(AssignExpression& node); + virtual ExpressionPtr Clone(BinaryExpression& node); + virtual ExpressionPtr Clone(CallFunctionExpression& node); + virtual ExpressionPtr Clone(CallMethodExpression& node); + virtual ExpressionPtr Clone(CastExpression& node); + virtual ExpressionPtr Clone(ConditionalExpression& node); + virtual ExpressionPtr Clone(ConstantExpression& node); + virtual ExpressionPtr Clone(IdentifierExpression& node); + virtual ExpressionPtr Clone(IntrinsicExpression& node); + virtual ExpressionPtr Clone(SelectOptionExpression& node); + virtual ExpressionPtr Clone(SwizzleExpression& node); + virtual ExpressionPtr Clone(VariableExpression& node); + virtual ExpressionPtr Clone(UnaryExpression& node); + + virtual StatementPtr Clone(BranchStatement& node); + virtual StatementPtr Clone(ConditionalStatement& node); + virtual StatementPtr Clone(DeclareExternalStatement& node); + virtual StatementPtr Clone(DeclareFunctionStatement& node); + virtual StatementPtr Clone(DeclareOptionStatement& node); + virtual StatementPtr Clone(DeclareStructStatement& node); + virtual StatementPtr Clone(DeclareVariableStatement& node); + virtual StatementPtr Clone(DiscardStatement& node); + virtual StatementPtr Clone(ExpressionStatement& node); + virtual StatementPtr Clone(MultiStatement& node); + virtual StatementPtr Clone(NoOpStatement& node); + virtual StatementPtr Clone(ReturnStatement& node); + +#define NAZARA_SHADERAST_NODE(NodeType) void Visit(NodeType& node) override; +#include + + void PushExpression(ExpressionPtr expression); + void PushStatement(StatementPtr statement); + + ExpressionPtr PopExpression(); + StatementPtr PopStatement(); + + private: + std::vector m_expressionStack; + std::vector m_statementStack; + }; + + inline ExpressionPtr Clone(ExpressionPtr& node); + inline StatementPtr Clone(StatementPtr& node); +} + +#include + +#endif diff --git a/include/Nazara/Shader/Ast/AstCloner.inl b/include/Nazara/Shader/Ast/AstCloner.inl new file mode 100644 index 000000000..a4ee519f9 --- /dev/null +++ b/include/Nazara/Shader/Ast/AstCloner.inl @@ -0,0 +1,39 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz::ShaderAst +{ + ExpressionPtr AstCloner::CloneExpression(const ExpressionPtr& expr) + { + if (!expr) + return nullptr; + + return CloneExpression(*expr); + } + + StatementPtr AstCloner::CloneStatement(const StatementPtr& statement) + { + if (!statement) + return nullptr; + + return CloneStatement(*statement); + } + + inline ExpressionPtr Clone(ExpressionPtr& node) + { + AstCloner cloner; + return cloner.Clone(node); + } + + inline StatementPtr Clone(StatementPtr& node) + { + AstCloner cloner; + return cloner.Clone(node); + } +} + +#include diff --git a/include/Nazara/Shader/Ast/AstExpressionVisitor.hpp b/include/Nazara/Shader/Ast/AstExpressionVisitor.hpp new file mode 100644 index 000000000..1c72f88b0 --- /dev/null +++ b/include/Nazara/Shader/Ast/AstExpressionVisitor.hpp @@ -0,0 +1,32 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADER_AST_EXPRESSIONVISITOR_HPP +#define NAZARA_SHADER_AST_EXPRESSIONVISITOR_HPP + +#include +#include +#include + +namespace Nz::ShaderAst +{ + class NAZARA_SHADER_API AstExpressionVisitor + { + public: + AstExpressionVisitor() = default; + AstExpressionVisitor(const AstExpressionVisitor&) = delete; + AstExpressionVisitor(AstExpressionVisitor&&) = delete; + virtual ~AstExpressionVisitor(); + +#define NAZARA_SHADERAST_EXPRESSION(Node) virtual void Visit(Node& node) = 0; +#include + + AstExpressionVisitor& operator=(const AstExpressionVisitor&) = delete; + AstExpressionVisitor& operator=(AstExpressionVisitor&&) = delete; + }; +} + +#endif diff --git a/include/Nazara/Shader/Ast/AstExpressionVisitorExcept.hpp b/include/Nazara/Shader/Ast/AstExpressionVisitorExcept.hpp new file mode 100644 index 000000000..40af7e695 --- /dev/null +++ b/include/Nazara/Shader/Ast/AstExpressionVisitorExcept.hpp @@ -0,0 +1,26 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADERASTEXPRESSIONVISITOREXCEPT_HPP +#define NAZARA_SHADERASTEXPRESSIONVISITOREXCEPT_HPP + +#include +#include +#include + +namespace Nz::ShaderAst +{ + class NAZARA_SHADER_API ExpressionVisitorExcept : public AstExpressionVisitor + { + public: + using AstExpressionVisitor::Visit; + +#define NAZARA_SHADERAST_EXPRESSION(Node) void Visit(ShaderAst::Node& node) override; +#include + }; +} + +#endif diff --git a/include/Nazara/Shader/Ast/AstNodeList.hpp b/include/Nazara/Shader/Ast/AstNodeList.hpp new file mode 100644 index 000000000..37f694d5d --- /dev/null +++ b/include/Nazara/Shader/Ast/AstNodeList.hpp @@ -0,0 +1,61 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#if !defined(NAZARA_SHADERAST_NODE) && !defined(NAZARA_SHADERAST_EXPRESSION) && !defined(NAZARA_SHADERAST_STATEMENT) +#error You must define NAZARA_SHADERAST_NODE or NAZARA_SHADERAST_EXPRESSION or NAZARA_SHADERAST_STATEMENT before including this file +#endif + +#ifndef NAZARA_SHADERAST_NODE +#define NAZARA_SHADERAST_NODE(X) +#endif + +#ifndef NAZARA_SHADERAST_NODE_LAST +#define NAZARA_SHADERAST_NODE_LAST(X) +#endif + +#ifndef NAZARA_SHADERAST_EXPRESSION +#define NAZARA_SHADERAST_EXPRESSION(X) NAZARA_SHADERAST_NODE(X) +#endif + +#ifndef NAZARA_SHADERAST_STATEMENT +#define NAZARA_SHADERAST_STATEMENT(X) NAZARA_SHADERAST_NODE(X) +#endif + +#ifndef NAZARA_SHADERAST_STATEMENT_LAST +#define NAZARA_SHADERAST_STATEMENT_LAST(X) NAZARA_SHADERAST_STATEMENT(X) +#endif + +NAZARA_SHADERAST_EXPRESSION(AccessIdentifierExpression) +NAZARA_SHADERAST_EXPRESSION(AccessIndexExpression) +NAZARA_SHADERAST_EXPRESSION(AssignExpression) +NAZARA_SHADERAST_EXPRESSION(BinaryExpression) +NAZARA_SHADERAST_EXPRESSION(CallFunctionExpression) +NAZARA_SHADERAST_EXPRESSION(CallMethodExpression) +NAZARA_SHADERAST_EXPRESSION(CastExpression) +NAZARA_SHADERAST_EXPRESSION(ConditionalExpression) +NAZARA_SHADERAST_EXPRESSION(ConstantExpression) +NAZARA_SHADERAST_EXPRESSION(IdentifierExpression) +NAZARA_SHADERAST_EXPRESSION(IntrinsicExpression) +NAZARA_SHADERAST_EXPRESSION(SelectOptionExpression) +NAZARA_SHADERAST_EXPRESSION(SwizzleExpression) +NAZARA_SHADERAST_EXPRESSION(VariableExpression) +NAZARA_SHADERAST_EXPRESSION(UnaryExpression) +NAZARA_SHADERAST_STATEMENT(BranchStatement) +NAZARA_SHADERAST_STATEMENT(ConditionalStatement) +NAZARA_SHADERAST_STATEMENT(DeclareExternalStatement) +NAZARA_SHADERAST_STATEMENT(DeclareFunctionStatement) +NAZARA_SHADERAST_STATEMENT(DeclareOptionStatement) +NAZARA_SHADERAST_STATEMENT(DeclareStructStatement) +NAZARA_SHADERAST_STATEMENT(DeclareVariableStatement) +NAZARA_SHADERAST_STATEMENT(DiscardStatement) +NAZARA_SHADERAST_STATEMENT(ExpressionStatement) +NAZARA_SHADERAST_STATEMENT(MultiStatement) +NAZARA_SHADERAST_STATEMENT(NoOpStatement) +NAZARA_SHADERAST_STATEMENT_LAST(ReturnStatement) + +#undef NAZARA_SHADERAST_EXPRESSION +#undef NAZARA_SHADERAST_NODE +#undef NAZARA_SHADERAST_NODE_LAST +#undef NAZARA_SHADERAST_STATEMENT +#undef NAZARA_SHADERAST_STATEMENT_LAST diff --git a/include/Nazara/Shader/Ast/AstOptimizer.hpp b/include/Nazara/Shader/Ast/AstOptimizer.hpp new file mode 100644 index 000000000..d81eced76 --- /dev/null +++ b/include/Nazara/Shader/Ast/AstOptimizer.hpp @@ -0,0 +1,57 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADERASTOPTIMISER_HPP +#define NAZARA_SHADERASTOPTIMISER_HPP + +#include +#include +#include +#include +#include + +namespace Nz::ShaderAst +{ + class NAZARA_SHADER_API AstOptimizer : public AstCloner + { + public: + AstOptimizer() = default; + AstOptimizer(const AstOptimizer&) = delete; + AstOptimizer(AstOptimizer&&) = delete; + ~AstOptimizer() = default; + + StatementPtr Optimise(const StatementPtr& statement); + StatementPtr Optimise(const StatementPtr& statement, UInt64 enabledConditions); + + AstOptimizer& operator=(const AstOptimizer&) = delete; + AstOptimizer& operator=(AstOptimizer&&) = delete; + + protected: + ExpressionPtr Clone(BinaryExpression& node) override; + ExpressionPtr Clone(CastExpression& node) override; + ExpressionPtr Clone(ConditionalExpression& node) override; + ExpressionPtr Clone(UnaryExpression& node) override; + StatementPtr Clone(BranchStatement& node) override; + StatementPtr Clone(ConditionalStatement& node) override; + + template ExpressionPtr PropagateBinaryConstant(std::unique_ptr&& lhs, std::unique_ptr&& rhs); + template ExpressionPtr PropagateSingleValueCast(std::unique_ptr&& operand); + template ExpressionPtr PropagateUnaryConstant(std::unique_ptr&& operand); + template ExpressionPtr PropagateVec2Cast(TargetType v1, TargetType v2); + template ExpressionPtr PropagateVec3Cast(TargetType v1, TargetType v2, TargetType v3); + template ExpressionPtr PropagateVec4Cast(TargetType v1, TargetType v2, TargetType v3, TargetType v4); + + private: + std::optional m_enabledOptions; + }; + + inline StatementPtr Optimize(const StatementPtr& ast); + inline StatementPtr Optimize(const StatementPtr& ast, UInt64 enabledConditions); +} + +#include + +#endif diff --git a/include/Nazara/Shader/Ast/AstOptimizer.inl b/include/Nazara/Shader/Ast/AstOptimizer.inl new file mode 100644 index 000000000..78b79324d --- /dev/null +++ b/include/Nazara/Shader/Ast/AstOptimizer.inl @@ -0,0 +1,23 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz::ShaderAst +{ + inline StatementPtr Optimize(const StatementPtr& ast) + { + AstOptimizer optimize; + return optimize.Optimise(ast); + } + + inline StatementPtr Optimize(const StatementPtr& ast, UInt64 enabledConditions) + { + AstOptimizer optimize; + return optimize.Optimise(ast, enabledConditions); + } +} + +#include diff --git a/include/Nazara/Shader/Ast/AstRecursiveVisitor.hpp b/include/Nazara/Shader/Ast/AstRecursiveVisitor.hpp new file mode 100644 index 000000000..5b1428633 --- /dev/null +++ b/include/Nazara/Shader/Ast/AstRecursiveVisitor.hpp @@ -0,0 +1,56 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADER_RECURSIVE_VISITOR_HPP +#define NAZARA_SHADER_RECURSIVE_VISITOR_HPP + +#include +#include +#include +#include + +namespace Nz::ShaderAst +{ + class NAZARA_SHADER_API AstRecursiveVisitor : public AstExpressionVisitor, public AstStatementVisitor + { + public: + AstRecursiveVisitor() = default; + ~AstRecursiveVisitor() = default; + + void Visit(AccessIdentifierExpression& node) override; + void Visit(AccessIndexExpression& node) override; + void Visit(AssignExpression& node) override; + void Visit(BinaryExpression& node) override; + void Visit(CallFunctionExpression& node) override; + void Visit(CallMethodExpression& node) override; + void Visit(CastExpression& node) override; + void Visit(ConditionalExpression& node) override; + void Visit(ConstantExpression& node) override; + void Visit(IdentifierExpression& node) override; + void Visit(IntrinsicExpression& node) override; + void Visit(SelectOptionExpression& node) override; + void Visit(SwizzleExpression& node) override; + void Visit(VariableExpression& node) override; + void Visit(UnaryExpression& node) override; + + void Visit(BranchStatement& node) override; + void Visit(ConditionalStatement& node) override; + void Visit(DeclareExternalStatement& node) override; + void Visit(DeclareFunctionStatement& node) override; + void Visit(DeclareOptionStatement& node) override; + void Visit(DeclareStructStatement& node) override; + void Visit(DeclareVariableStatement& node) override; + void Visit(DiscardStatement& node) override; + void Visit(ExpressionStatement& node) override; + void Visit(MultiStatement& node) override; + void Visit(NoOpStatement& node) override; + void Visit(ReturnStatement& node) override; + }; +} + +#include + +#endif diff --git a/include/Nazara/Shader/ShaderAstRecursiveVisitor.inl b/include/Nazara/Shader/Ast/AstRecursiveVisitor.inl similarity index 83% rename from include/Nazara/Shader/ShaderAstRecursiveVisitor.inl rename to include/Nazara/Shader/Ast/AstRecursiveVisitor.inl index 8de7f453c..1467b2ca2 100644 --- a/include/Nazara/Shader/ShaderAstRecursiveVisitor.inl +++ b/include/Nazara/Shader/Ast/AstRecursiveVisitor.inl @@ -2,7 +2,7 @@ // This file is part of the "Nazara Engine - Shader generator" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include namespace Nz diff --git a/include/Nazara/Shader/Ast/AstReflect.hpp b/include/Nazara/Shader/Ast/AstReflect.hpp new file mode 100644 index 000000000..3ee91f524 --- /dev/null +++ b/include/Nazara/Shader/Ast/AstReflect.hpp @@ -0,0 +1,46 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADER_AST_REFLECT_HPP +#define NAZARA_SHADER_AST_REFLECT_HPP + +#include +#include +#include +#include + +namespace Nz::ShaderAst +{ + class NAZARA_SHADER_API AstReflect : public AstRecursiveVisitor + { + public: + struct Callbacks; + + AstReflect() = default; + AstReflect(const AstReflect&) = delete; + AstReflect(AstReflect&&) = delete; + ~AstReflect() = default; + + void Reflect(const StatementPtr& statement, const Callbacks& callbacks); + + AstReflect& operator=(const AstReflect&) = delete; + AstReflect& operator=(AstReflect&&) = delete; + + struct Callbacks + { + std::function onOptionDeclaration; + }; + + private: + void Visit(DeclareOptionStatement& node) override; + + const Callbacks* m_callbacks; + }; +} + +#include + +#endif diff --git a/include/Nazara/Shader/Ast/AstReflect.inl b/include/Nazara/Shader/Ast/AstReflect.inl new file mode 100644 index 000000000..c9fe65d86 --- /dev/null +++ b/include/Nazara/Shader/Ast/AstReflect.inl @@ -0,0 +1,12 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz::ShaderAst +{ +} + +#include diff --git a/include/Nazara/Shader/ShaderAstSerializer.hpp b/include/Nazara/Shader/Ast/AstSerializer.hpp similarity index 53% rename from include/Nazara/Shader/ShaderAstSerializer.hpp rename to include/Nazara/Shader/Ast/AstSerializer.hpp index ac03cc66d..932f7991a 100644 --- a/include/Nazara/Shader/ShaderAstSerializer.hpp +++ b/include/Nazara/Shader/Ast/AstSerializer.hpp @@ -11,35 +11,46 @@ #include #include #include -#include -#include -#include +#include -namespace Nz +namespace Nz::ShaderAst { - class NAZARA_SHADER_API ShaderAstSerializerBase + class NAZARA_SHADER_API AstSerializerBase { public: - ShaderAstSerializerBase() = default; - ShaderAstSerializerBase(const ShaderAstSerializerBase&) = delete; - ShaderAstSerializerBase(ShaderAstSerializerBase&&) = delete; - ~ShaderAstSerializerBase() = default; + AstSerializerBase() = default; + AstSerializerBase(const AstSerializerBase&) = delete; + AstSerializerBase(AstSerializerBase&&) = delete; + ~AstSerializerBase() = default; - void Serialize(ShaderNodes::AccessMember& node); - void Serialize(ShaderNodes::AssignOp& node); - void Serialize(ShaderNodes::BinaryOp& node); - void Serialize(ShaderNodes::BuiltinVariable& var); - void Serialize(ShaderNodes::Branch& node); - void Serialize(ShaderNodes::Cast& node); - void Serialize(ShaderNodes::Constant& node); - void Serialize(ShaderNodes::DeclareVariable& node); - void Serialize(ShaderNodes::ExpressionStatement& node); - void Serialize(ShaderNodes::Identifier& node); - void Serialize(ShaderNodes::IntrinsicCall& node); - void Serialize(ShaderNodes::NamedVariable& var); - void Serialize(ShaderNodes::Sample2D& node); - void Serialize(ShaderNodes::StatementBlock& node); - void Serialize(ShaderNodes::SwizzleOp& node); + void Serialize(AccessIdentifierExpression& node); + void Serialize(AccessIndexExpression& node); + void Serialize(AssignExpression& node); + void Serialize(BinaryExpression& node); + void Serialize(CallFunctionExpression& node); + void Serialize(CallMethodExpression& node); + void Serialize(CastExpression& node); + void Serialize(ConditionalExpression& node); + void Serialize(ConstantExpression& node); + void Serialize(IdentifierExpression& node); + void Serialize(IntrinsicExpression& node); + void Serialize(SelectOptionExpression& node); + void Serialize(SwizzleExpression& node); + void Serialize(VariableExpression& node); + void Serialize(UnaryExpression& node); + + void Serialize(BranchStatement& node); + void Serialize(ConditionalStatement& node); + void Serialize(DeclareExternalStatement& node); + void Serialize(DeclareFunctionStatement& node); + void Serialize(DeclareOptionStatement& node); + void Serialize(DeclareStructStatement& node); + void Serialize(DeclareVariableStatement& node); + void Serialize(DiscardStatement& node); + void Serialize(ExpressionStatement& node); + void Serialize(MultiStatement& node); + void Serialize(NoOpStatement& node); + void Serialize(ReturnStatement& node); protected: template void Container(T& container); @@ -49,10 +60,10 @@ namespace Nz virtual bool IsWriting() const = 0; - virtual void Node(ShaderNodes::NodePtr& node) = 0; - template void Node(std::shared_ptr& node); + virtual void Node(ExpressionPtr& node) = 0; + virtual void Node(StatementPtr& node) = 0; - virtual void Type(ShaderExpressionType& type) = 0; + virtual void Type(ExpressionType& type) = 0; virtual void Value(bool& val) = 0; virtual void Value(float& val) = 0; @@ -69,24 +80,21 @@ namespace Nz virtual void Value(UInt32& val) = 0; virtual void Value(UInt64& val) = 0; inline void SizeT(std::size_t& val); - - virtual void Variable(ShaderNodes::VariablePtr& var) = 0; - template void Variable(std::shared_ptr& var); }; - class NAZARA_SHADER_API ShaderAstSerializer final : public ShaderAstSerializerBase + class NAZARA_SHADER_API ShaderAstSerializer final : public AstSerializerBase { public: inline ShaderAstSerializer(ByteStream& stream); ~ShaderAstSerializer() = default; - void Serialize(const ShaderAst& shader); + void Serialize(StatementPtr& shader); private: bool IsWriting() const override; - void Node(const ShaderNodes::NodePtr& node); - void Node(ShaderNodes::NodePtr& node) override; - void Type(ShaderExpressionType& type) override; + void Node(ExpressionPtr& node) override; + void Node(StatementPtr& node) override; + void Type(ExpressionType& type) override; void Value(bool& val) override; void Value(float& val) override; void Value(std::string& val) override; @@ -101,23 +109,23 @@ namespace Nz void Value(UInt16& val) override; void Value(UInt32& val) override; void Value(UInt64& val) override; - void Variable(ShaderNodes::VariablePtr& var) override; ByteStream& m_stream; }; - class NAZARA_SHADER_API ShaderAstUnserializer final : public ShaderAstSerializerBase + class NAZARA_SHADER_API ShaderAstUnserializer final : public AstSerializerBase { public: ShaderAstUnserializer(ByteStream& stream); ~ShaderAstUnserializer() = default; - ShaderAst Unserialize(); + StatementPtr Unserialize(); private: bool IsWriting() const override; - void Node(ShaderNodes::NodePtr& node) override; - void Type(ShaderExpressionType& type) override; + void Node(ExpressionPtr& node) override; + void Node(StatementPtr& node) override; + void Type(ExpressionType& type) override; void Value(bool& val) override; void Value(float& val) override; void Value(std::string& val) override; @@ -132,15 +140,15 @@ namespace Nz void Value(UInt16& val) override; void Value(UInt32& val) override; void Value(UInt64& val) override; - void Variable(ShaderNodes::VariablePtr& var) override; ByteStream& m_stream; }; - NAZARA_SHADER_API ByteArray SerializeShader(const ShaderAst& shader); - NAZARA_SHADER_API ShaderAst UnserializeShader(ByteStream& stream); + NAZARA_SHADER_API ByteArray SerializeShader(StatementPtr& shader); + inline StatementPtr UnserializeShader(const void* data, std::size_t size); + NAZARA_SHADER_API StatementPtr UnserializeShader(ByteStream& stream); } -#include +#include #endif diff --git a/include/Nazara/Shader/ShaderAstSerializer.inl b/include/Nazara/Shader/Ast/AstSerializer.inl similarity index 65% rename from include/Nazara/Shader/ShaderAstSerializer.inl rename to include/Nazara/Shader/Ast/AstSerializer.inl index 31882eeb7..025e869b9 100644 --- a/include/Nazara/Shader/ShaderAstSerializer.inl +++ b/include/Nazara/Shader/Ast/AstSerializer.inl @@ -2,13 +2,13 @@ // This file is part of the "Nazara Engine - Shader generator" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include -namespace Nz +namespace Nz::ShaderAst { template - void ShaderAstSerializerBase::Container(T& container) + void AstSerializerBase::Container(T& container) { bool isWriting = IsWriting(); @@ -23,7 +23,7 @@ namespace Nz template - void ShaderAstSerializerBase::Enum(T& enumVal) + void AstSerializerBase::Enum(T& enumVal) { bool isWriting = IsWriting(); @@ -37,7 +37,7 @@ namespace Nz } template - void ShaderAstSerializerBase::OptEnum(std::optional& optVal) + void AstSerializerBase::OptEnum(std::optional& optVal) { bool isWriting = IsWriting(); @@ -55,7 +55,7 @@ namespace Nz } template - void ShaderAstSerializerBase::OptVal(std::optional& optVal) + void AstSerializerBase::OptVal(std::optional& optVal) { bool isWriting = IsWriting(); @@ -77,21 +77,7 @@ namespace Nz } } - template - void ShaderAstSerializerBase::Node(std::shared_ptr& node) - { - bool isWriting = IsWriting(); - - ShaderNodes::NodePtr value; - if (isWriting) - value = node; - - Node(value); - if (!isWriting) - node = std::static_pointer_cast(value); - } - - inline void ShaderAstSerializerBase::SizeT(std::size_t& val) + inline void AstSerializerBase::SizeT(std::size_t& val) { bool isWriting = IsWriting(); @@ -105,20 +91,6 @@ namespace Nz val = static_cast(fixedVal); } - template - void ShaderAstSerializerBase::Variable(std::shared_ptr& var) - { - bool isWriting = IsWriting(); - - ShaderNodes::VariablePtr value; - if (isWriting) - value = var; - - Variable(value); - if (!isWriting) - var = std::static_pointer_cast(value); - } - inline ShaderAstSerializer::ShaderAstSerializer(ByteStream& stream) : m_stream(stream) { @@ -128,6 +100,12 @@ namespace Nz m_stream(stream) { } + + inline StatementPtr UnserializeShader(const void* data, std::size_t size) + { + ByteStream byteStream(data, size); + return UnserializeShader(byteStream); + } } #include diff --git a/include/Nazara/Shader/Ast/AstStatementVisitor.hpp b/include/Nazara/Shader/Ast/AstStatementVisitor.hpp new file mode 100644 index 000000000..d204e4e9f --- /dev/null +++ b/include/Nazara/Shader/Ast/AstStatementVisitor.hpp @@ -0,0 +1,32 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADERASTSTATEMENTVISITOR_HPP +#define NAZARA_SHADERASTSTATEMENTVISITOR_HPP + +#include +#include +#include + +namespace Nz::ShaderAst +{ + class NAZARA_SHADER_API AstStatementVisitor + { + public: + AstStatementVisitor() = default; + AstStatementVisitor(const AstStatementVisitor&) = delete; + AstStatementVisitor(AstStatementVisitor&&) = delete; + virtual ~AstStatementVisitor(); + +#define NAZARA_SHADERAST_STATEMENT(NodeType) virtual void Visit(ShaderAst::NodeType& node) = 0; +#include + + AstStatementVisitor& operator=(const AstStatementVisitor&) = delete; + AstStatementVisitor& operator=(AstStatementVisitor&&) = delete; + }; +} + +#endif diff --git a/include/Nazara/Shader/Ast/AstStatementVisitorExcept.hpp b/include/Nazara/Shader/Ast/AstStatementVisitorExcept.hpp new file mode 100644 index 000000000..88199ddb2 --- /dev/null +++ b/include/Nazara/Shader/Ast/AstStatementVisitorExcept.hpp @@ -0,0 +1,26 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADERASTSTATEMENTVISITOREXCEPT_HPP +#define NAZARA_SHADERASTSTATEMENTVISITOREXCEPT_HPP + +#include +#include +#include + +namespace Nz::ShaderAst +{ + class NAZARA_SHADER_API StatementVisitorExcept : public AstStatementVisitor + { + public: + using AstStatementVisitor::Visit; + +#define NAZARA_SHADERAST_STATEMENT(Node) void Visit(ShaderAst::Node& node) override; +#include + }; +} + +#endif diff --git a/include/Nazara/Shader/Ast/AstUtils.hpp b/include/Nazara/Shader/Ast/AstUtils.hpp new file mode 100644 index 000000000..e020c10ed --- /dev/null +++ b/include/Nazara/Shader/Ast/AstUtils.hpp @@ -0,0 +1,58 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADER_AST_UTILS_HPP +#define NAZARA_SHADER_AST_UTILS_HPP + +#include +#include +#include +#include +#include + +namespace Nz::ShaderAst +{ + class NAZARA_SHADER_API ShaderAstValueCategory final : public AstExpressionVisitor + { + public: + ShaderAstValueCategory() = default; + ShaderAstValueCategory(const ShaderAstValueCategory&) = delete; + ShaderAstValueCategory(ShaderAstValueCategory&&) = delete; + ~ShaderAstValueCategory() = default; + + ExpressionCategory GetExpressionCategory(Expression& expression); + + ShaderAstValueCategory& operator=(const ShaderAstValueCategory&) = delete; + ShaderAstValueCategory& operator=(ShaderAstValueCategory&&) = delete; + + private: + using AstExpressionVisitor::Visit; + + void Visit(AccessIdentifierExpression& node) override; + void Visit(AccessIndexExpression& node) override; + void Visit(AssignExpression& node) override; + void Visit(BinaryExpression& node) override; + void Visit(CallFunctionExpression& node) override; + void Visit(CallMethodExpression& node) override; + void Visit(CastExpression& node) override; + void Visit(ConditionalExpression& node) override; + void Visit(ConstantExpression& node) override; + void Visit(IdentifierExpression& node) override; + void Visit(IntrinsicExpression& node) override; + void Visit(SelectOptionExpression& node) override; + void Visit(SwizzleExpression& node) override; + void Visit(VariableExpression& node) override; + void Visit(UnaryExpression& node) override; + + ExpressionCategory m_expressionCategory; + }; + + inline ExpressionCategory GetExpressionCategory(Expression& expression); +} + +#include + +#endif diff --git a/include/Nazara/Shader/Ast/AstUtils.inl b/include/Nazara/Shader/Ast/AstUtils.inl new file mode 100644 index 000000000..b988f6fef --- /dev/null +++ b/include/Nazara/Shader/Ast/AstUtils.inl @@ -0,0 +1,17 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz::ShaderAst +{ + ExpressionCategory GetExpressionCategory(Expression& expression) + { + ShaderAstValueCategory visitor; + return visitor.GetExpressionCategory(expression); + } +} + +#include diff --git a/include/Nazara/Shader/Ast/Attribute.hpp b/include/Nazara/Shader/Ast/Attribute.hpp new file mode 100644 index 000000000..5bd1cf589 --- /dev/null +++ b/include/Nazara/Shader/Ast/Attribute.hpp @@ -0,0 +1,25 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADERAST_ATTRIBUTES_HPP +#define NAZARA_SHADERAST_ATTRIBUTES_HPP + +#include +#include +#include + +namespace Nz::ShaderAst +{ + struct Attribute + { + using Param = std::variant; + + AttributeType type; + Param args; + }; +} + +#endif diff --git a/include/Nazara/Shader/ShaderConstantValue.hpp b/include/Nazara/Shader/Ast/ConstantValue.hpp similarity index 71% rename from include/Nazara/Shader/ShaderConstantValue.hpp rename to include/Nazara/Shader/Ast/ConstantValue.hpp index 27c9e1d7e..3064603cf 100644 --- a/include/Nazara/Shader/ShaderConstantValue.hpp +++ b/include/Nazara/Shader/Ast/ConstantValue.hpp @@ -11,11 +11,13 @@ #include #include #include +#include +#include #include -namespace Nz +namespace Nz::ShaderAst { - using ShaderConstantValue = std::variant< + using ConstantValue = std::variant< bool, float, Int32, @@ -27,6 +29,8 @@ namespace Nz Vector3i32, Vector4i32 >; + + NAZARA_SHADER_API ExpressionType GetExpressionType(const ConstantValue& constant); } #endif diff --git a/include/Nazara/Shader/Ast/Enums.hpp b/include/Nazara/Shader/Ast/Enums.hpp new file mode 100644 index 000000000..830353ae0 --- /dev/null +++ b/include/Nazara/Shader/Ast/Enums.hpp @@ -0,0 +1,139 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADER_AST_ENUMS_HPP +#define NAZARA_SHADER_AST_ENUMS_HPP + +#include +#include + +namespace Nz +{ + namespace ShaderAst + { + enum class AssignType + { + Simple //< = + }; + + enum class AttributeType + { + Binding, //< Binding (external var only) - has argument index + Builtin, //< Builtin (struct member only) - has argument type + DepthWrite, //< Depth write mode (function only) - has argument type + EarlyFragmentTests, //< Entry point (function only) - has argument on/off + Entry, //< Entry point (function only) - has argument type + Layout, //< Struct layout (struct only) - has argument style + Location, //< Location (struct member only) - has argument index + Option, //< Conditional compilation option - has argument expr + }; + + enum class BinaryType + { + Add, //< + + Subtract, //< - + Multiply, //< * + Divide, //< / + + CompEq, //< == + CompGe, //< >= + CompGt, //< > + CompLe, //< <= + CompLt, //< < + CompNe //< <= + }; + + enum class BuiltinEntry + { + FragCoord = 1, // gl_FragCoord + FragDepth = 2, // gl_FragDepth + VertexPosition = 0, // gl_Position + }; + + enum class DepthWriteMode + { + Greater, + Less, + Replace, + Unchanged, + }; + + enum class ExpressionCategory + { + LValue, + RValue + }; + + enum class FunctionFlag + { + DoesDiscard, + DoesWriteFragDepth, + + Max = DoesWriteFragDepth + }; + } + + template<> + struct EnumAsFlags + { + static constexpr ShaderAst::FunctionFlag max = ShaderAst::FunctionFlag::Max; + }; + + namespace ShaderAst + { + using FunctionFlags = Flags; + + enum class IntrinsicType + { + CrossProduct = 0, + DotProduct = 1, + Length = 3, + Max = 4, + Min = 5, + Pow = 6, + SampleTexture = 2, + }; + + enum class MemoryLayout + { + Std140 + }; + + enum class NodeType + { + None = -1, + +#define NAZARA_SHADERAST_NODE(Node) Node, +#define NAZARA_SHADERAST_STATEMENT_LAST(Node) Node, Max = Node +#include + }; + + enum class PrimitiveType + { + Boolean, //< bool + Float32, //< f32 + Int32, //< i32 + UInt32, //< ui32 + }; + + enum class SwizzleComponent + { + First, + Second, + Third, + Fourth + }; + + enum class UnaryType + { + LogicalNot, //< !v + Minus, //< -v + Plus, //< +v + }; + } +} + +#endif // NAZARA_SHADER_ENUMS_HPP diff --git a/include/Nazara/Shader/Ast/ExpressionType.hpp b/include/Nazara/Shader/Ast/ExpressionType.hpp new file mode 100644 index 000000000..e7a949e5b --- /dev/null +++ b/include/Nazara/Shader/Ast/ExpressionType.hpp @@ -0,0 +1,108 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADER_AST_EXPRESSIONTYPE_HPP +#define NAZARA_SHADER_AST_EXPRESSIONTYPE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz::ShaderAst +{ + struct IdentifierType //< Alias or struct + { + std::string name; + + inline bool operator==(const IdentifierType& rhs) const; + inline bool operator!=(const IdentifierType& rhs) const; + }; + + struct MatrixType + { + std::size_t columnCount; + std::size_t rowCount; + PrimitiveType type; + + inline bool operator==(const MatrixType& rhs) const; + inline bool operator!=(const MatrixType& rhs) const; + }; + + struct NoType + { + inline bool operator==(const NoType& rhs) const; + inline bool operator!=(const NoType& rhs) const; + }; + + struct SamplerType + { + ImageType dim; + PrimitiveType sampledType; + + inline bool operator==(const SamplerType& rhs) const; + inline bool operator!=(const SamplerType& rhs) const; + }; + + struct StructType + { + std::size_t structIndex; + + inline bool operator==(const StructType& rhs) const; + inline bool operator!=(const StructType& rhs) const; + }; + + struct UniformType + { + std::variant containedType; + + inline bool operator==(const UniformType& rhs) const; + inline bool operator!=(const UniformType& rhs) const; + }; + + struct VectorType + { + std::size_t componentCount; + PrimitiveType type; + + inline bool operator==(const VectorType& rhs) const; + inline bool operator!=(const VectorType& rhs) const; + }; + + using ExpressionType = std::variant; + + struct StructDescription + { + struct StructMember + { + std::optional builtin; + std::optional locationIndex; + std::string name; + ExpressionType type; + }; + + std::optional layout; + std::string name; + std::vector members; + }; + + inline bool IsIdentifierType(const ExpressionType& type); + inline bool IsMatrixType(const ExpressionType& type); + inline bool IsNoType(const ExpressionType& type); + inline bool IsPrimitiveType(const ExpressionType& type); + inline bool IsSamplerType(const ExpressionType& type); + inline bool IsStructType(const ExpressionType& type); + inline bool IsUniformType(const ExpressionType& type); + inline bool IsVectorType(const ExpressionType& type); +} + +#include + +#endif diff --git a/include/Nazara/Shader/Ast/ExpressionType.inl b/include/Nazara/Shader/Ast/ExpressionType.inl new file mode 100644 index 000000000..ec9580616 --- /dev/null +++ b/include/Nazara/Shader/Ast/ExpressionType.inl @@ -0,0 +1,128 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz::ShaderAst +{ + inline bool IdentifierType::operator==(const IdentifierType& rhs) const + { + return name == rhs.name; + } + + inline bool IdentifierType::operator!=(const IdentifierType& rhs) const + { + return !operator==(rhs); + } + + + inline bool MatrixType::operator==(const MatrixType& rhs) const + { + return columnCount == rhs.columnCount && rowCount == rhs.rowCount && type == rhs.type; + } + + inline bool MatrixType::operator!=(const MatrixType& rhs) const + { + return !operator==(rhs); + } + + + inline bool NoType::operator==(const NoType& /*rhs*/) const + { + return true; + } + + inline bool NoType::operator!=(const NoType& /*rhs*/) const + { + return false; + } + + + inline bool SamplerType::operator==(const SamplerType& rhs) const + { + return dim == rhs.dim && sampledType == rhs.sampledType; + } + + inline bool SamplerType::operator!=(const SamplerType& rhs) const + { + return !operator==(rhs); + } + + + inline bool StructType::operator==(const StructType& rhs) const + { + return structIndex == rhs.structIndex; + } + + inline bool StructType::operator!=(const StructType& rhs) const + { + return !operator==(rhs); + } + + inline bool UniformType::operator==(const UniformType& rhs) const + { + return containedType == rhs.containedType; + } + + inline bool UniformType::operator!=(const UniformType& rhs) const + { + return !operator==(rhs); + } + + + inline bool VectorType::operator==(const VectorType& rhs) const + { + return componentCount == rhs.componentCount && type == rhs.type; + } + + inline bool VectorType::operator!=(const VectorType& rhs) const + { + return !operator==(rhs); + } + + + inline bool IsIdentifierType(const ExpressionType& type) + { + return std::holds_alternative(type); + } + + inline bool IsMatrixType(const ExpressionType& type) + { + return std::holds_alternative(type); + } + + inline bool IsNoType(const ExpressionType& type) + { + return std::holds_alternative(type); + } + + inline bool IsPrimitiveType(const ExpressionType& type) + { + return std::holds_alternative(type); + } + + inline bool IsSamplerType(const ExpressionType& type) + { + return std::holds_alternative(type); + } + + bool IsStructType(const ExpressionType& type) + { + return std::holds_alternative(type); + } + + bool IsUniformType(const ExpressionType& type) + { + return std::holds_alternative(type); + } + + bool IsVectorType(const ExpressionType& type) + { + return std::holds_alternative(type); + } +} + +#include diff --git a/include/Nazara/Shader/Ast/Nodes.hpp b/include/Nazara/Shader/Ast/Nodes.hpp new file mode 100644 index 000000000..9a9974a0b --- /dev/null +++ b/include/Nazara/Shader/Ast/Nodes.hpp @@ -0,0 +1,361 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADER_AST_NODES_HPP +#define NAZARA_SHADER_AST_NODES_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz::ShaderAst +{ + class AstExpressionVisitor; + class AstStatementVisitor; + + struct Node; + + using NodePtr = std::unique_ptr; + + struct NAZARA_SHADER_API Node + { + Node() = default; + Node(const Node&) = delete; + Node(Node&&) noexcept = default; + virtual ~Node(); + + virtual NodeType GetType() const = 0; + + Node& operator=(const Node&) = delete; + Node& operator=(Node&&) noexcept = default; + }; + + // Expressions + + struct Expression; + + using ExpressionPtr = std::unique_ptr; + + struct NAZARA_SHADER_API Expression : Node + { + Expression() = default; + Expression(const Expression&) = delete; + Expression(Expression&&) noexcept = default; + ~Expression() = default; + + virtual void Visit(AstExpressionVisitor& visitor) = 0; + + Expression& operator=(const Expression&) = delete; + Expression& operator=(Expression&&) noexcept = default; + + std::optional cachedExpressionType; + }; + + struct NAZARA_SHADER_API AccessIdentifierExpression : public Expression + { + NodeType GetType() const override; + void Visit(AstExpressionVisitor& visitor) override; + + ExpressionPtr expr; + std::vector identifiers; + }; + + struct NAZARA_SHADER_API AccessIndexExpression : public Expression + { + NodeType GetType() const override; + void Visit(AstExpressionVisitor& visitor) override; + + ExpressionPtr expr; + std::vector indices; + }; + + struct NAZARA_SHADER_API AssignExpression : public Expression + { + NodeType GetType() const override; + void Visit(AstExpressionVisitor& visitor) override; + + AssignType op; + ExpressionPtr left; + ExpressionPtr right; + }; + + struct NAZARA_SHADER_API BinaryExpression : public Expression + { + NodeType GetType() const override; + void Visit(AstExpressionVisitor& visitor) override; + + BinaryType op; + ExpressionPtr left; + ExpressionPtr right; + }; + + struct NAZARA_SHADER_API CallFunctionExpression : public Expression + { + NodeType GetType() const override; + void Visit(AstExpressionVisitor& visitor) override; + + std::variant targetFunction; + std::vector parameters; + }; + + struct NAZARA_SHADER_API CallMethodExpression : public Expression + { + NodeType GetType() const override; + void Visit(AstExpressionVisitor& visitor) override; + + ExpressionPtr object; + std::string methodName; + std::vector parameters; + }; + + struct NAZARA_SHADER_API CastExpression : public Expression + { + NodeType GetType() const override; + void Visit(AstExpressionVisitor& visitor) override; + + ExpressionType targetType; + std::array expressions; + }; + + struct NAZARA_SHADER_API ConditionalExpression : public Expression + { + NodeType GetType() const override; + void Visit(AstExpressionVisitor& visitor) override; + + std::size_t optionIndex; + ExpressionPtr falsePath; + ExpressionPtr truePath; + }; + + struct NAZARA_SHADER_API ConstantExpression : public Expression + { + NodeType GetType() const override; + void Visit(AstExpressionVisitor& visitor) override; + + ShaderAst::ConstantValue value; + }; + + struct NAZARA_SHADER_API IdentifierExpression : public Expression + { + NodeType GetType() const override; + void Visit(AstExpressionVisitor& visitor) override; + + std::string identifier; + }; + + struct NAZARA_SHADER_API IntrinsicExpression : public Expression + { + NodeType GetType() const override; + void Visit(AstExpressionVisitor& visitor) override; + + IntrinsicType intrinsic; + std::vector parameters; + }; + + struct NAZARA_SHADER_API SelectOptionExpression : public Expression + { + NodeType GetType() const override; + void Visit(AstExpressionVisitor& visitor) override; + + std::string optionName; + ExpressionPtr falsePath; + ExpressionPtr truePath; + }; + + struct NAZARA_SHADER_API SwizzleExpression : public Expression + { + NodeType GetType() const override; + void Visit(AstExpressionVisitor& visitor) override; + + std::array components; + std::size_t componentCount; + ExpressionPtr expression; + }; + + struct NAZARA_SHADER_API VariableExpression : Expression + { + NodeType GetType() const override; + void Visit(AstExpressionVisitor& visitor) override; + + std::size_t variableId; + }; + + struct NAZARA_SHADER_API UnaryExpression : public Expression + { + NodeType GetType() const override; + void Visit(AstExpressionVisitor& visitor) override; + + UnaryType op; + ExpressionPtr expression; + }; + + // Statements + + struct Statement; + + using StatementPtr = std::unique_ptr; + + struct NAZARA_SHADER_API Statement : Node + { + Statement() = default; + Statement(const Statement&) = delete; + Statement(Statement&&) noexcept = default; + ~Statement() = default; + + virtual void Visit(AstStatementVisitor& visitor) = 0; + + Statement& operator=(const Statement&) = delete; + Statement& operator=(Statement&&) noexcept = default; + }; + + struct NAZARA_SHADER_API BranchStatement : public Statement + { + NodeType GetType() const override; + void Visit(AstStatementVisitor& visitor) override; + + struct ConditionalStatement + { + ExpressionPtr condition; + StatementPtr statement; + }; + + std::vector condStatements; + StatementPtr elseStatement; + }; + + struct NAZARA_SHADER_API ConditionalStatement : Statement + { + NodeType GetType() const override; + void Visit(AstStatementVisitor& visitor) override; + + std::size_t optionIndex; + StatementPtr statement; + }; + + struct NAZARA_SHADER_API DeclareExternalStatement : Statement + { + NodeType GetType() const override; + void Visit(AstStatementVisitor& visitor) override; + + struct ExternalVar + { + std::optional bindingIndex; + std::string name; + ExpressionType type; + }; + + std::optional varIndex; + std::vector externalVars; + }; + + struct NAZARA_SHADER_API DeclareFunctionStatement : Statement + { + NodeType GetType() const override; + void Visit(AstStatementVisitor& visitor) override; + + struct Parameter + { + std::string name; + ExpressionType type; + }; + + std::optional depthWrite; + std::optional earlyFragmentTests; + std::optional entryStage; + std::optional funcIndex; + std::optional varIndex; + std::string optionName; + std::string name; + std::vector parameters; + std::vector statements; + ExpressionType returnType; + }; + + struct NAZARA_SHADER_API DeclareOptionStatement : Statement + { + NodeType GetType() const override; + void Visit(AstStatementVisitor& visitor) override; + + std::optional optIndex; + std::string optName; + ExpressionPtr initialValue; + ExpressionType optType; + }; + + struct NAZARA_SHADER_API DeclareStructStatement : Statement + { + NodeType GetType() const override; + void Visit(AstStatementVisitor& visitor) override; + + std::optional structIndex; + StructDescription description; + }; + + struct NAZARA_SHADER_API DeclareVariableStatement : Statement + { + NodeType GetType() const override; + void Visit(AstStatementVisitor& visitor) override; + + std::optional varIndex; + std::string varName; + ExpressionPtr initialExpression; + ExpressionType varType; + }; + + struct NAZARA_SHADER_API DiscardStatement : Statement + { + NodeType GetType() const override; + void Visit(AstStatementVisitor& visitor) override; + }; + + struct NAZARA_SHADER_API ExpressionStatement : Statement + { + NodeType GetType() const override; + void Visit(AstStatementVisitor& visitor) override; + + ExpressionPtr expression; + }; + + struct NAZARA_SHADER_API MultiStatement : Statement + { + NodeType GetType() const override; + void Visit(AstStatementVisitor& visitor) override; + + std::vector statements; + }; + + struct NAZARA_SHADER_API NoOpStatement : Statement + { + NodeType GetType() const override; + void Visit(AstStatementVisitor& visitor) override; + }; + + struct NAZARA_SHADER_API ReturnStatement : Statement + { + NodeType GetType() const override; + void Visit(AstStatementVisitor& visitor) override; + + ExpressionPtr returnExpr; + }; + + inline const ShaderAst::ExpressionType& GetExpressionType(ShaderAst::Expression& expr); + inline bool IsExpression(NodeType nodeType); + inline bool IsStatement(NodeType nodeType); +} + +#include + +#endif diff --git a/include/Nazara/Shader/Ast/Nodes.inl b/include/Nazara/Shader/Ast/Nodes.inl new file mode 100644 index 000000000..7484f2ac4 --- /dev/null +++ b/include/Nazara/Shader/Ast/Nodes.inl @@ -0,0 +1,41 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz::ShaderAst +{ + const ShaderAst::ExpressionType& GetExpressionType(ShaderAst::Expression& expr) + { + assert(expr.cachedExpressionType); + return expr.cachedExpressionType.value(); + } + + inline bool IsExpression(NodeType nodeType) + { + switch (nodeType) + { +#define NAZARA_SHADERAST_EXPRESSION(Node) case NodeType::Node: return true; +#include + + default: + return false; + } + } + + inline bool IsStatement(NodeType nodeType) + { + switch (nodeType) + { +#define NAZARA_SHADERAST_STATEMENT(Node) case NodeType::Node: return true; +#include + + default: + return false; + } + } +} + +#include diff --git a/include/Nazara/Shader/Ast/SanitizeVisitor.hpp b/include/Nazara/Shader/Ast/SanitizeVisitor.hpp new file mode 100644 index 000000000..8c3afb17b --- /dev/null +++ b/include/Nazara/Shader/Ast/SanitizeVisitor.hpp @@ -0,0 +1,150 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADERAST_TRANSFORMVISITOR_HPP +#define NAZARA_SHADERAST_TRANSFORMVISITOR_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace Nz::ShaderAst +{ + class NAZARA_SHADER_API SanitizeVisitor final : AstCloner + { + public: + struct Options; + + SanitizeVisitor() = default; + SanitizeVisitor(const SanitizeVisitor&) = delete; + SanitizeVisitor(SanitizeVisitor&&) = delete; + ~SanitizeVisitor() = default; + + inline StatementPtr Sanitize(const StatementPtr& statement, std::string* error = nullptr); + StatementPtr Sanitize(const StatementPtr& statement, const Options& options, std::string* error = nullptr); + + SanitizeVisitor& operator=(const SanitizeVisitor&) = delete; + SanitizeVisitor& operator=(SanitizeVisitor&&) = delete; + + struct Options + { + std::unordered_set reservedIdentifiers; + bool removeOptionDeclaration = true; + }; + + private: + struct FunctionData; + struct Identifier; + + using AstCloner::CloneExpression; + + ExpressionPtr Clone(AccessIdentifierExpression& node) override; + ExpressionPtr Clone(AccessIndexExpression& node) override; + ExpressionPtr Clone(AssignExpression& node) override; + ExpressionPtr Clone(BinaryExpression& node) override; + ExpressionPtr Clone(CallFunctionExpression& node) override; + ExpressionPtr Clone(CastExpression& node) override; + ExpressionPtr Clone(ConditionalExpression& node) override; + ExpressionPtr Clone(ConstantExpression& node) override; + ExpressionPtr Clone(IdentifierExpression& node) override; + ExpressionPtr Clone(IntrinsicExpression& node) override; + ExpressionPtr Clone(SelectOptionExpression& node) override; + ExpressionPtr Clone(SwizzleExpression& node) override; + ExpressionPtr Clone(UnaryExpression& node) override; + + StatementPtr Clone(BranchStatement& node) override; + StatementPtr Clone(ConditionalStatement& node) override; + StatementPtr Clone(DeclareExternalStatement& node) override; + StatementPtr Clone(DeclareFunctionStatement& node) override; + StatementPtr Clone(DeclareOptionStatement& node) override; + StatementPtr Clone(DeclareStructStatement& node) override; + StatementPtr Clone(DeclareVariableStatement& node) override; + StatementPtr Clone(DiscardStatement& node) override; + StatementPtr Clone(ExpressionStatement& node) override; + StatementPtr Clone(MultiStatement& node) override; + + inline const Identifier* FindIdentifier(const std::string_view& identifierName) const; + + Expression& MandatoryExpr(ExpressionPtr& node); + Statement& MandatoryStatement(StatementPtr& node); + void TypeMustMatch(ExpressionPtr& left, ExpressionPtr& right); + void TypeMustMatch(const ExpressionType& left, const ExpressionType& right); + + void PushScope(); + void PopScope(); + + std::size_t DeclareFunction(DeclareFunctionStatement* funcDecl); + + void PropagateFunctionFlags(std::size_t funcIndex, FunctionFlags flags, Bitset<>& seen); + + FunctionData& RegisterFunction(std::size_t functionIndex); + std::size_t RegisterIntrinsic(std::string name, IntrinsicType type); + std::size_t RegisterOption(std::string name, ExpressionType type); + std::size_t RegisterStruct(std::string name, StructDescription description); + std::size_t RegisterVariable(std::string name, ExpressionType type); + + void ResolveFunctions(); + + std::size_t ResolveStruct(const ExpressionType& exprType); + std::size_t ResolveStruct(const IdentifierType& identifierType); + std::size_t ResolveStruct(const StructType& structType); + std::size_t ResolveStruct(const UniformType& uniformType); + ExpressionType ResolveType(const ExpressionType& exprType); + + void SanitizeIdentifier(std::string& identifier); + + void Validate(AccessIndexExpression& node); + void Validate(CallFunctionExpression& node, const DeclareFunctionStatement* referenceDeclaration); + void Validate(IntrinsicExpression& node); + + struct FunctionData + { + Bitset<> calledByFunctions; + DeclareFunctionStatement* node; + FunctionFlags flags; + bool defined = false; + }; + + struct Identifier + { + enum class Type + { + Alias, + Function, + Intrinsic, + Option, + Struct, + Variable + }; + + std::string name; + std::size_t index; + Type type; + }; + + std::vector m_identifiersInScope; + std::vector m_functions; + std::vector m_intrinsics; + std::vector m_options; + std::vector m_structs; + std::vector m_variableTypes; + std::vector m_scopeSizes; + + struct Context; + Context* m_context; + }; + + inline StatementPtr Sanitize(const StatementPtr& ast, std::string* error = nullptr); + inline StatementPtr Sanitize(const StatementPtr& ast, const SanitizeVisitor::Options& options, std::string* error = nullptr); +} + +#include + +#endif diff --git a/include/Nazara/Shader/Ast/SanitizeVisitor.inl b/include/Nazara/Shader/Ast/SanitizeVisitor.inl new file mode 100644 index 000000000..4bc69711a --- /dev/null +++ b/include/Nazara/Shader/Ast/SanitizeVisitor.inl @@ -0,0 +1,37 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz::ShaderAst +{ + inline StatementPtr SanitizeVisitor::Sanitize(const StatementPtr& statement, std::string* error) + { + return Sanitize(statement, {}, error); + } + + inline auto SanitizeVisitor::FindIdentifier(const std::string_view& identifierName) const -> const Identifier* + { + auto it = std::find_if(m_identifiersInScope.rbegin(), m_identifiersInScope.rend(), [&](const Identifier& identifier) { return identifier.name == identifierName; }); + if (it == m_identifiersInScope.rend()) + return nullptr; + + return &*it; + } + + inline StatementPtr Sanitize(const StatementPtr& ast, std::string* error) + { + SanitizeVisitor sanitizer; + return sanitizer.Sanitize(ast, error); + } + + inline StatementPtr Sanitize(const StatementPtr& ast, const SanitizeVisitor::Options& options, std::string* error) + { + SanitizeVisitor sanitizer; + return sanitizer.Sanitize(ast, options, error); + } +} + +#include diff --git a/include/Nazara/Shader/GlslWriter.hpp b/include/Nazara/Shader/GlslWriter.hpp index ad76fbe18..72cc2d768 100644 --- a/include/Nazara/Shader/GlslWriter.hpp +++ b/include/Nazara/Shader/GlslWriter.hpp @@ -9,29 +9,29 @@ #include #include -#include -#include -#include #include +#include +#include #include #include #include -#include +#include namespace Nz { - class NAZARA_SHADER_API GlslWriter : public ShaderWriter, public ShaderVarVisitor, public ShaderAstVisitor + class NAZARA_SHADER_API GlslWriter : public ShaderWriter, public ShaderAst::ExpressionVisitorExcept, public ShaderAst::StatementVisitorExcept { public: struct Environment; using ExtSupportCallback = std::function; - GlslWriter(); + inline GlslWriter(); GlslWriter(const GlslWriter&) = delete; GlslWriter(GlslWriter&&) = delete; ~GlslWriter() = default; - std::string Generate(const ShaderAst& shader) override; + inline std::string Generate(ShaderAst::StatementPtr& shader, const States& states = {}); + std::string Generate(std::optional shaderStage, ShaderAst::StatementPtr& shader, const States& states = {}); void SetEnv(Environment environment); @@ -44,62 +44,71 @@ namespace Nz bool flipYPosition = false; }; - private: - void Append(ShaderExpressionType type); - void Append(ShaderNodes::BuiltinEntry builtin); - void Append(ShaderNodes::BasicType type); - void Append(ShaderNodes::MemoryLayout layout); - template void Append(const T& param); - void AppendCommentSection(const std::string& section); - void AppendField(const std::string& structName, std::size_t* memberIndex, std::size_t remainingMembers); - void AppendFunction(const ShaderAst::Function& func); - void AppendFunctionPrototype(const ShaderAst::Function& func); - void AppendLine(const std::string& txt = {}); + static const char* GetFlipYUniformName(); - template void DeclareVariables(const ShaderAst& shader, const std::vector& variables, const std::string& keyword = {}, const std::string& section = {}); + private: + void Append(const ShaderAst::ExpressionType& type); + void Append(ShaderAst::BuiltinEntry builtin); + void Append(const ShaderAst::IdentifierType& identifierType); + void Append(const ShaderAst::MatrixType& matrixType); + void Append(ShaderAst::MemoryLayout layout); + void Append(ShaderAst::NoType); + void Append(ShaderAst::PrimitiveType type); + void Append(const ShaderAst::SamplerType& samplerType); + void Append(const ShaderAst::StructType& structType); + void Append(const ShaderAst::UniformType& uniformType); + void Append(const ShaderAst::VectorType& vecType); + template void Append(const T& param); + template void Append(const T1& firstParam, const T2& secondParam, Args&&... params); + void AppendCommentSection(const std::string& section); + void AppendFunctionDeclaration(const ShaderAst::DeclareFunctionStatement& node, bool forward = false); + void AppendField(std::size_t structIndex, const ShaderAst::ExpressionPtr* memberIndices, std::size_t remainingMembers); + void AppendHeader(); + void AppendLine(const std::string& txt = {}); + template void AppendLine(Args&&... params); + void AppendStatementList(std::vector& statements); void EnterScope(); - void LeaveScope(); + void LeaveScope(bool skipLine = true); - using ShaderVarVisitor::Visit; - using ShaderAstVisitor::Visit; - void Visit(ShaderNodes::ExpressionPtr& expr, bool encloseIfRequired = false); - void Visit(ShaderNodes::AccessMember& node) override; - void Visit(ShaderNodes::AssignOp& node) override; - void Visit(ShaderNodes::Branch& node) override; - void Visit(ShaderNodes::BinaryOp& node) override; - void Visit(ShaderNodes::BuiltinVariable& var) override; - void Visit(ShaderNodes::Cast& node) override; - void Visit(ShaderNodes::Constant& node) override; - void Visit(ShaderNodes::DeclareVariable& node) override; - void Visit(ShaderNodes::ExpressionStatement& node) override; - void Visit(ShaderNodes::Identifier& node) override; - void Visit(ShaderNodes::InputVariable& var) override; - void Visit(ShaderNodes::IntrinsicCall& node) override; - void Visit(ShaderNodes::LocalVariable& var) override; - void Visit(ShaderNodes::ParameterVariable& var) override; - void Visit(ShaderNodes::OutputVariable& var) override; - void Visit(ShaderNodes::Sample2D& node) override; - void Visit(ShaderNodes::StatementBlock& node) override; - void Visit(ShaderNodes::SwizzleOp& node) override; - void Visit(ShaderNodes::UniformVariable& var) override; + void HandleEntryPoint(ShaderAst::DeclareFunctionStatement& node); + void HandleInOut(); - static bool HasExplicitBinding(const ShaderAst& shader); - static bool HasExplicitLocation(const ShaderAst& shader); + void RegisterStruct(std::size_t structIndex, ShaderAst::StructDescription desc); + void RegisterVariable(std::size_t varIndex, std::string varName); - struct Context - { - const ShaderAst* shader = nullptr; - const ShaderAst::Function* currentFunction = nullptr; - }; + void Visit(ShaderAst::ExpressionPtr& expr, bool encloseIfRequired = false); - struct State - { - std::stringstream stream; - unsigned int indentLevel = 0; - }; + void Visit(ShaderAst::AccessIndexExpression& node) override; + void Visit(ShaderAst::AssignExpression& node) override; + void Visit(ShaderAst::BinaryExpression& node) override; + void Visit(ShaderAst::CallFunctionExpression& node) override; + void Visit(ShaderAst::CastExpression& node) override; + void Visit(ShaderAst::ConditionalExpression& node) override; + void Visit(ShaderAst::ConstantExpression& node) override; + void Visit(ShaderAst::IntrinsicExpression& node) override; + void Visit(ShaderAst::SwizzleExpression& node) override; + void Visit(ShaderAst::VariableExpression& node) override; + void Visit(ShaderAst::UnaryExpression& node) override; + + void Visit(ShaderAst::BranchStatement& node) override; + void Visit(ShaderAst::ConditionalStatement& node) override; + void Visit(ShaderAst::DeclareExternalStatement& node) override; + void Visit(ShaderAst::DeclareFunctionStatement& node) override; + void Visit(ShaderAst::DeclareOptionStatement& node) override; + void Visit(ShaderAst::DeclareStructStatement& node) override; + void Visit(ShaderAst::DeclareVariableStatement& node) override; + void Visit(ShaderAst::DiscardStatement& node) override; + void Visit(ShaderAst::ExpressionStatement& node) override; + void Visit(ShaderAst::MultiStatement& node) override; + void Visit(ShaderAst::NoOpStatement& node) override; + void Visit(ShaderAst::ReturnStatement& node) override; + + static bool HasExplicitBinding(ShaderAst::StatementPtr& shader); + static bool HasExplicitLocation(ShaderAst::StatementPtr& shader); + + struct State; - Context m_context; Environment m_environment; State* m_currentState; }; diff --git a/include/Nazara/Shader/GlslWriter.inl b/include/Nazara/Shader/GlslWriter.inl index fd5cbe094..dc736e182 100644 --- a/include/Nazara/Shader/GlslWriter.inl +++ b/include/Nazara/Shader/GlslWriter.inl @@ -3,129 +3,18 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include -#include #include namespace Nz { - template - void GlslWriter::Append(const T& param) + inline GlslWriter::GlslWriter() : + m_currentState(nullptr) { - NazaraAssert(m_currentState, "This function should only be called while processing an AST"); - - m_currentState->stream << param; } - template - void GlslWriter::DeclareVariables(const ShaderAst& shader, const std::vector& variables, const std::string& keyword, const std::string& section) + inline std::string GlslWriter::Generate(ShaderAst::StatementPtr& shader, const States& states) { - if (!variables.empty()) - { - if (!section.empty()) - AppendCommentSection(section); - - for (const auto& var : variables) - { - if constexpr (std::is_same_v) - { - if (var.locationIndex) - { - Append("layout(location = "); - Append(*var.locationIndex); - Append(") "); - } - - if (!keyword.empty()) - { - Append(keyword); - Append(" "); - } - - Append(var.type); - Append(" "); - Append(var.name); - AppendLine(";"); - } - else if constexpr (std::is_same_v) - { - if (var.bindingIndex || var.memoryLayout) - { - Append("layout("); - - bool first = true; - if (var.bindingIndex) - { - if (!first) - Append(", "); - - Append("binding = "); - Append(*var.bindingIndex); - - first = false; - } - - if (var.memoryLayout) - { - if (!first) - Append(", "); - - Append(*var.memoryLayout); - - first = false; - } - - Append(") "); - } - - if (!keyword.empty()) - { - Append(keyword); - Append(" "); - } - - std::visit([&](auto&& arg) - { - using U = std::decay_t; - if constexpr (std::is_same_v) - { - Append(arg); - Append(" "); - Append(var.name); - } - else if constexpr (std::is_same_v) - { - const auto& structs = shader.GetStructs(); - auto it = std::find_if(structs.begin(), structs.end(), [&](const auto& s) { return s.name == arg; }); - if (it == structs.end()) - throw std::runtime_error("struct " + arg + " has not been defined"); - - const auto& s = *it; - - AppendLine(var.name + "_interface"); - AppendLine("{"); - for (const auto& m : s.members) - { - Append("\t"); - Append(m.type); - Append(" "); - Append(m.name); - AppendLine(";"); - } - Append("} "); - Append(var.name); - } - else - static_assert(AlwaysFalse::value, "non-exhaustive visitor"); - - }, var.type); - - AppendLine(";"); - AppendLine(); - } - } - - AppendLine(); - } + return Generate(std::nullopt, shader, states); } } diff --git a/include/Nazara/Shader/LangWriter.hpp b/include/Nazara/Shader/LangWriter.hpp new file mode 100644 index 000000000..ae25399db --- /dev/null +++ b/include/Nazara/Shader/LangWriter.hpp @@ -0,0 +1,116 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_LANGWRITER_HPP +#define NAZARA_LANGWRITER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_SHADER_API LangWriter : public ShaderWriter, public ShaderAst::ExpressionVisitorExcept, public ShaderAst::StatementVisitorExcept + { + public: + struct Environment; + + inline LangWriter(); + LangWriter(const LangWriter&) = delete; + LangWriter(LangWriter&&) = delete; + ~LangWriter() = default; + + std::string Generate(ShaderAst::StatementPtr& shader, const States& conditions = {}); + + void SetEnv(Environment environment); + + struct Environment + { + }; + + private: + struct BindingAttribute; + struct BuiltinAttribute; + struct DepthWriteAttribute; + struct EarlyFragmentTestsAttribute; + struct EntryAttribute; + struct LayoutAttribute; + struct LocationAttribute; + + void Append(const ShaderAst::ExpressionType& type); + void Append(const ShaderAst::IdentifierType& identifierType); + void Append(const ShaderAst::MatrixType& matrixType); + void Append(ShaderAst::NoType); + void Append(ShaderAst::PrimitiveType type); + void Append(const ShaderAst::SamplerType& samplerType); + void Append(const ShaderAst::StructType& structType); + void Append(const ShaderAst::UniformType& uniformType); + void Append(const ShaderAst::VectorType& vecType); + template void Append(const T& param); + template void Append(const T1& firstParam, const T2& secondParam, Args&&... params); + template void AppendAttributes(bool appendLine, Args&&... params); + void AppendAttribute(BindingAttribute binding); + void AppendAttribute(BuiltinAttribute builtin); + void AppendAttribute(DepthWriteAttribute depthWrite); + void AppendAttribute(EarlyFragmentTestsAttribute earlyFragmentTests); + void AppendAttribute(EntryAttribute entry); + void AppendAttribute(LayoutAttribute layout); + void AppendAttribute(LocationAttribute location); + void AppendCommentSection(const std::string& section); + void AppendField(std::size_t structIndex, const ShaderAst::ExpressionPtr* memberIndices, std::size_t remainingMembers); + void AppendHeader(); + void AppendLine(const std::string& txt = {}); + template void AppendLine(Args&&... params); + void AppendStatementList(std::vector& statements); + + void EnterScope(); + void LeaveScope(bool skipLine = true); + + void RegisterOption(std::size_t optionIndex, std::string optionName); + void RegisterStruct(std::size_t structIndex, ShaderAst::StructDescription desc); + void RegisterVariable(std::size_t varIndex, std::string varName); + + void Visit(ShaderAst::ExpressionPtr& expr, bool encloseIfRequired = false); + + void Visit(ShaderAst::AccessIndexExpression& node) override; + void Visit(ShaderAst::AssignExpression& node) override; + void Visit(ShaderAst::BinaryExpression& node) override; + void Visit(ShaderAst::CastExpression& node) override; + void Visit(ShaderAst::ConditionalExpression& node) override; + void Visit(ShaderAst::ConstantExpression& node) override; + void Visit(ShaderAst::IntrinsicExpression& node) override; + void Visit(ShaderAst::SwizzleExpression& node) override; + void Visit(ShaderAst::VariableExpression& node) override; + void Visit(ShaderAst::UnaryExpression& node) override; + + void Visit(ShaderAst::BranchStatement& node) override; + void Visit(ShaderAst::ConditionalStatement& node) override; + void Visit(ShaderAst::DeclareExternalStatement& node) override; + void Visit(ShaderAst::DeclareFunctionStatement& node) override; + void Visit(ShaderAst::DeclareOptionStatement& node) override; + void Visit(ShaderAst::DeclareStructStatement& node) override; + void Visit(ShaderAst::DeclareVariableStatement& node) override; + void Visit(ShaderAst::DiscardStatement& node) override; + void Visit(ShaderAst::ExpressionStatement& node) override; + void Visit(ShaderAst::MultiStatement& node) override; + void Visit(ShaderAst::NoOpStatement& node) override; + void Visit(ShaderAst::ReturnStatement& node) override; + + struct State; + + Environment m_environment; + State* m_currentState; + }; +} + +#include + +#endif diff --git a/include/Nazara/Shader/ShaderAstValidator.inl b/include/Nazara/Shader/LangWriter.inl similarity index 67% rename from include/Nazara/Shader/ShaderAstValidator.inl rename to include/Nazara/Shader/LangWriter.inl index eed116766..adc74afe4 100644 --- a/include/Nazara/Shader/ShaderAstValidator.inl +++ b/include/Nazara/Shader/LangWriter.inl @@ -2,13 +2,13 @@ // This file is part of the "Nazara Engine - Shader generator" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include namespace Nz { - ShaderAstValidator::ShaderAstValidator(const ShaderAst& shader) : - m_shader(shader) + inline LangWriter::LangWriter() : + m_currentState(nullptr) { } } diff --git a/include/Nazara/Shader/ShaderAst.hpp b/include/Nazara/Shader/ShaderAst.hpp deleted file mode 100644 index 30ed90fac..000000000 --- a/include/Nazara/Shader/ShaderAst.hpp +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_SHADER_AST_HPP -#define NAZARA_SHADER_AST_HPP - -#include -#include -#include -#include -#include -#include -#include - -namespace Nz -{ - class NAZARA_SHADER_API ShaderAst - { - public: - struct Function; - struct FunctionParameter; - struct InputOutput; - struct Struct; - struct StructMember; - struct Uniform; - struct VariableBase; - - inline ShaderAst(ShaderStageType shaderStage); - ShaderAst(const ShaderAst&) = default; - ShaderAst(ShaderAst&&) noexcept = default; - ~ShaderAst() = default; - - void AddFunction(std::string name, ShaderNodes::StatementPtr statement, std::vector parameters = {}, ShaderNodes::BasicType returnType = ShaderNodes::BasicType::Void); - void AddInput(std::string name, ShaderExpressionType type, std::optional locationIndex = {}); - void AddOutput(std::string name, ShaderExpressionType type, std::optional locationIndex = {}); - void AddStruct(std::string name, std::vector members); - void AddUniform(std::string name, ShaderExpressionType type, std::optional bindingIndex = {}, std::optional memoryLayout = {}); - - inline const Function& GetFunction(std::size_t i) const; - inline std::size_t GetFunctionCount() const; - inline const std::vector& GetFunctions() const; - inline const InputOutput& GetInput(std::size_t i) const; - inline std::size_t GetInputCount() const; - inline const std::vector& GetInputs() const; - inline const InputOutput& GetOutput(std::size_t i) const; - inline std::size_t GetOutputCount() const; - inline const std::vector& GetOutputs() const; - inline ShaderStageType GetStage() const; - inline const Struct& GetStruct(std::size_t i) const; - inline std::size_t GetStructCount() const; - inline const std::vector& GetStructs() const; - inline const Uniform& GetUniform(std::size_t i) const; - inline std::size_t GetUniformCount() const; - inline const std::vector& GetUniforms() const; - - ShaderAst& operator=(const ShaderAst&) = default; - ShaderAst& operator=(ShaderAst&&) noexcept = default; - - struct VariableBase - { - std::string name; - ShaderExpressionType type; - }; - - struct FunctionParameter : VariableBase - { - }; - - struct Function - { - std::string name; - std::vector parameters; - ShaderNodes::BasicType returnType; - ShaderNodes::StatementPtr statement; - }; - - struct InputOutput : VariableBase - { - std::optional locationIndex; - }; - - struct Uniform : VariableBase - { - std::optional bindingIndex; - std::optional memoryLayout; - }; - - struct Struct - { - std::string name; - std::vector members; - }; - - struct StructMember - { - std::string name; - ShaderExpressionType type; - }; - - private: - std::vector m_functions; - std::vector m_inputs; - std::vector m_outputs; - std::vector m_structs; - std::vector m_uniforms; - ShaderStageType m_stage; - }; -} - -#include - -#endif // NAZARA_SHADER_AST_HPP diff --git a/include/Nazara/Shader/ShaderAst.inl b/include/Nazara/Shader/ShaderAst.inl deleted file mode 100644 index 4c6c42833..000000000 --- a/include/Nazara/Shader/ShaderAst.inl +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include - -namespace Nz -{ - inline ShaderAst::ShaderAst(ShaderStageType shaderStage) : - m_stage(shaderStage) - { - } - - inline auto ShaderAst::GetFunction(std::size_t i) const -> const Function& - { - assert(i < m_functions.size()); - return m_functions[i]; - } - - inline std::size_t ShaderAst::GetFunctionCount() const - { - return m_functions.size(); - } - - inline auto ShaderAst::GetFunctions() const -> const std::vector& - { - return m_functions; - } - - inline auto ShaderAst::GetInput(std::size_t i) const -> const InputOutput& - { - assert(i < m_inputs.size()); - return m_inputs[i]; - } - - inline std::size_t ShaderAst::GetInputCount() const - { - return m_inputs.size(); - } - - inline auto ShaderAst::GetInputs() const -> const std::vector& - { - return m_inputs; - } - - inline auto ShaderAst::GetOutput(std::size_t i) const -> const InputOutput& - { - assert(i < m_outputs.size()); - return m_outputs[i]; - } - - inline std::size_t ShaderAst::GetOutputCount() const - { - return m_outputs.size(); - } - - inline auto ShaderAst::GetOutputs() const -> const std::vector& - { - return m_outputs; - } - - inline ShaderStageType ShaderAst::GetStage() const - { - return m_stage; - } - - inline auto ShaderAst::GetStruct(std::size_t i) const -> const Struct& - { - assert(i < m_structs.size()); - return m_structs[i]; - } - - inline std::size_t ShaderAst::GetStructCount() const - { - return m_structs.size(); - } - - inline auto ShaderAst::GetStructs() const -> const std::vector& - { - return m_structs; - } - - inline auto ShaderAst::GetUniform(std::size_t i) const -> const Uniform& - { - assert(i < m_uniforms.size()); - return m_uniforms[i]; - } - - inline std::size_t ShaderAst::GetUniformCount() const - { - return m_uniforms.size(); - } - - inline auto ShaderAst::GetUniforms() const -> const std::vector& - { - return m_uniforms; - } -} - -#include diff --git a/include/Nazara/Shader/ShaderAstCloner.hpp b/include/Nazara/Shader/ShaderAstCloner.hpp deleted file mode 100644 index 34336e9ba..000000000 --- a/include/Nazara/Shader/ShaderAstCloner.hpp +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_SHADERASTCLONER_HPP -#define NAZARA_SHADERASTCLONER_HPP - -#include -#include -#include -#include -#include - -namespace Nz -{ - class NAZARA_SHADER_API ShaderAstCloner : public ShaderAstVisitor, public ShaderVarVisitor - { - public: - ShaderAstCloner() = default; - ShaderAstCloner(const ShaderAstCloner&) = delete; - ShaderAstCloner(ShaderAstCloner&&) = delete; - ~ShaderAstCloner() = default; - - ShaderNodes::StatementPtr Clone(const ShaderNodes::StatementPtr& statement); - - ShaderAstCloner& operator=(const ShaderAstCloner&) = delete; - ShaderAstCloner& operator=(ShaderAstCloner&&) = delete; - - protected: - ShaderNodes::ExpressionPtr CloneExpression(const ShaderNodes::ExpressionPtr& expr); - ShaderNodes::StatementPtr CloneStatement(const ShaderNodes::StatementPtr& statement); - ShaderNodes::VariablePtr CloneVariable(const ShaderNodes::VariablePtr& statement); - - void Visit(ShaderNodes::AccessMember& node) override; - void Visit(ShaderNodes::AssignOp& node) override; - void Visit(ShaderNodes::BinaryOp& node) override; - void Visit(ShaderNodes::Branch& node) override; - void Visit(ShaderNodes::Cast& node) override; - void Visit(ShaderNodes::Constant& node) override; - void Visit(ShaderNodes::DeclareVariable& node) override; - void Visit(ShaderNodes::ExpressionStatement& node) override; - void Visit(ShaderNodes::Identifier& node) override; - void Visit(ShaderNodes::IntrinsicCall& node) override; - void Visit(ShaderNodes::Sample2D& node) override; - void Visit(ShaderNodes::StatementBlock& node) override; - void Visit(ShaderNodes::SwizzleOp& node) override; - - void Visit(ShaderNodes::BuiltinVariable& var) override; - void Visit(ShaderNodes::InputVariable& var) override; - void Visit(ShaderNodes::LocalVariable& var) override; - void Visit(ShaderNodes::OutputVariable& var) override; - void Visit(ShaderNodes::ParameterVariable& var) override; - void Visit(ShaderNodes::UniformVariable& var) override; - - void PushExpression(ShaderNodes::ExpressionPtr expression); - void PushStatement(ShaderNodes::StatementPtr statement); - void PushVariable(ShaderNodes::VariablePtr variable); - - ShaderNodes::ExpressionPtr PopExpression(); - ShaderNodes::StatementPtr PopStatement(); - ShaderNodes::VariablePtr PopVariable(); - - private: - std::vector m_expressionStack; - std::vector m_statementStack; - std::vector m_variableStack; - }; -} - -#include - -#endif diff --git a/include/Nazara/Shader/ShaderAstRecursiveVisitor.hpp b/include/Nazara/Shader/ShaderAstRecursiveVisitor.hpp deleted file mode 100644 index 367f9b4ca..000000000 --- a/include/Nazara/Shader/ShaderAstRecursiveVisitor.hpp +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_SHADER_RECURSIVE_VISITOR_HPP -#define NAZARA_SHADER_RECURSIVE_VISITOR_HPP - -#include -#include -#include - -namespace Nz -{ - class NAZARA_SHADER_API ShaderAstRecursiveVisitor : public ShaderAstVisitor - { - public: - ShaderAstRecursiveVisitor() = default; - ~ShaderAstRecursiveVisitor() = default; - - using ShaderAstVisitor::Visit; - - void Visit(ShaderNodes::AccessMember& node) override; - void Visit(ShaderNodes::AssignOp& node) override; - void Visit(ShaderNodes::BinaryOp& node) override; - void Visit(ShaderNodes::Branch& node) override; - void Visit(ShaderNodes::Cast& node) override; - void Visit(ShaderNodes::Constant& node) override; - void Visit(ShaderNodes::DeclareVariable& node) override; - void Visit(ShaderNodes::ExpressionStatement& node) override; - void Visit(ShaderNodes::Identifier& node) override; - void Visit(ShaderNodes::IntrinsicCall& node) override; - void Visit(ShaderNodes::Sample2D& node) override; - void Visit(ShaderNodes::StatementBlock& node) override; - void Visit(ShaderNodes::SwizzleOp& node) override; - }; -} - -#include - -#endif diff --git a/include/Nazara/Shader/ShaderAstValidator.hpp b/include/Nazara/Shader/ShaderAstValidator.hpp deleted file mode 100644 index 8195494b6..000000000 --- a/include/Nazara/Shader/ShaderAstValidator.hpp +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_SHADERVALIDATOR_HPP -#define NAZARA_SHADERVALIDATOR_HPP - -#include -#include -#include -#include -#include -#include -#include - -namespace Nz -{ - class NAZARA_SHADER_API ShaderAstValidator : public ShaderAstRecursiveVisitor, public ShaderVarVisitor - { - public: - inline ShaderAstValidator(const ShaderAst& shader); - ShaderAstValidator(const ShaderAstValidator&) = delete; - ShaderAstValidator(ShaderAstValidator&&) = delete; - ~ShaderAstValidator() = default; - - bool Validate(std::string* error = nullptr); - - private: - const ShaderNodes::ExpressionPtr& MandatoryExpr(const ShaderNodes::ExpressionPtr& node); - const ShaderNodes::NodePtr& MandatoryNode(const ShaderNodes::NodePtr& node); - void TypeMustMatch(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right); - void TypeMustMatch(const ShaderExpressionType& left, const ShaderExpressionType& right); - - const ShaderAst::StructMember& CheckField(const std::string& structName, std::size_t* memberIndex, std::size_t remainingMembers); - - using ShaderAstRecursiveVisitor::Visit; - void Visit(ShaderNodes::AccessMember& node) override; - void Visit(ShaderNodes::AssignOp& node) override; - void Visit(ShaderNodes::BinaryOp& node) override; - void Visit(ShaderNodes::Branch& node) override; - void Visit(ShaderNodes::Cast& node) override; - void Visit(ShaderNodes::Constant& node) override; - void Visit(ShaderNodes::DeclareVariable& node) override; - void Visit(ShaderNodes::ExpressionStatement& node) override; - void Visit(ShaderNodes::Identifier& node) override; - void Visit(ShaderNodes::IntrinsicCall& node) override; - void Visit(ShaderNodes::Sample2D& node) override; - void Visit(ShaderNodes::StatementBlock& node) override; - void Visit(ShaderNodes::SwizzleOp& node) override; - - using ShaderVarVisitor::Visit; - void Visit(ShaderNodes::BuiltinVariable& var) override; - void Visit(ShaderNodes::InputVariable& var) override; - void Visit(ShaderNodes::LocalVariable& var) override; - void Visit(ShaderNodes::OutputVariable& var) override; - void Visit(ShaderNodes::ParameterVariable& var) override; - void Visit(ShaderNodes::UniformVariable& var) override; - - struct Context; - - const ShaderAst& m_shader; - Context* m_context; - }; - - NAZARA_SHADER_API bool ValidateShader(const ShaderAst& shader, std::string* error = nullptr); -} - -#include - -#endif diff --git a/include/Nazara/Shader/ShaderAstVisitor.hpp b/include/Nazara/Shader/ShaderAstVisitor.hpp deleted file mode 100644 index decd3a2f9..000000000 --- a/include/Nazara/Shader/ShaderAstVisitor.hpp +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_SHADERASTVISITOR_HPP -#define NAZARA_SHADERASTVISITOR_HPP - -#include -#include -#include -#include -#include - -namespace Nz -{ - class NAZARA_SHADER_API ShaderAstVisitor - { - public: - ShaderAstVisitor() = default; - ShaderAstVisitor(const ShaderAstVisitor&) = delete; - ShaderAstVisitor(ShaderAstVisitor&&) = delete; - virtual ~ShaderAstVisitor(); - - void EnableCondition(const std::string& name, bool cond); - - bool IsConditionEnabled(const std::string& name) const; - - void Visit(const ShaderNodes::NodePtr& node); - virtual void Visit(ShaderNodes::AccessMember& node) = 0; - virtual void Visit(ShaderNodes::AssignOp& node) = 0; - virtual void Visit(ShaderNodes::BinaryOp& node) = 0; - virtual void Visit(ShaderNodes::Branch& node) = 0; - virtual void Visit(ShaderNodes::Cast& node) = 0; - virtual void Visit(ShaderNodes::Constant& node) = 0; - virtual void Visit(ShaderNodes::DeclareVariable& node) = 0; - virtual void Visit(ShaderNodes::ExpressionStatement& node) = 0; - virtual void Visit(ShaderNodes::Identifier& node) = 0; - virtual void Visit(ShaderNodes::IntrinsicCall& node) = 0; - virtual void Visit(ShaderNodes::Sample2D& node) = 0; - virtual void Visit(ShaderNodes::StatementBlock& node) = 0; - virtual void Visit(ShaderNodes::SwizzleOp& node) = 0; - - ShaderAstVisitor& operator=(const ShaderAstVisitor&) = delete; - ShaderAstVisitor& operator=(ShaderAstVisitor&&) = delete; - - private: - std::unordered_set m_conditions; - }; -} - -#endif diff --git a/include/Nazara/Shader/ShaderAstVisitorExcept.hpp b/include/Nazara/Shader/ShaderAstVisitorExcept.hpp deleted file mode 100644 index 40635477c..000000000 --- a/include/Nazara/Shader/ShaderAstVisitorExcept.hpp +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_SHADERASTVISITOREXCEPT_HPP -#define NAZARA_SHADERASTVISITOREXCEPT_HPP - -#include -#include -#include - -namespace Nz -{ - class NAZARA_SHADER_API ShaderAstVisitorExcept : public ShaderAstVisitor - { - public: - using ShaderAstVisitor::Visit; - void Visit(ShaderNodes::AccessMember& node) override; - void Visit(ShaderNodes::AssignOp& node) override; - void Visit(ShaderNodes::BinaryOp& node) override; - void Visit(ShaderNodes::Branch& node) override; - void Visit(ShaderNodes::Cast& node) override; - void Visit(ShaderNodes::Constant& node) override; - void Visit(ShaderNodes::DeclareVariable& node) override; - void Visit(ShaderNodes::ExpressionStatement& node) override; - void Visit(ShaderNodes::Identifier& node) override; - void Visit(ShaderNodes::IntrinsicCall& node) override; - void Visit(ShaderNodes::Sample2D& node) override; - void Visit(ShaderNodes::StatementBlock& node) override; - void Visit(ShaderNodes::SwizzleOp& node) override; - }; -} - -#endif diff --git a/include/Nazara/Shader/ShaderBuilder.hpp b/include/Nazara/Shader/ShaderBuilder.hpp index 074434a44..d4fd91862 100644 --- a/include/Nazara/Shader/ShaderBuilder.hpp +++ b/include/Nazara/Shader/ShaderBuilder.hpp @@ -8,67 +8,162 @@ #define NAZARA_SHADER_BUILDER_HPP #include -#include +#include +#include #include +#include namespace Nz::ShaderBuilder { - template - struct AssignOpBuilder + namespace Impl { - constexpr AssignOpBuilder() = default; + struct AccessIndex + { + inline std::unique_ptr operator()(ShaderAst::ExpressionPtr expr, const std::vector& indexConstants) const; + inline std::unique_ptr operator()(ShaderAst::ExpressionPtr expr, std::vector indexExpressions) const; + }; - std::shared_ptr operator()(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right) const; - }; + struct AccessMember + { + inline std::unique_ptr operator()(ShaderAst::ExpressionPtr expr, std::vector memberIdentifiers) const; + }; - template - struct BinOpBuilder - { - constexpr BinOpBuilder() = default; + struct Assign + { + inline std::unique_ptr operator()(ShaderAst::AssignType op, ShaderAst::ExpressionPtr left, ShaderAst::ExpressionPtr right) const; + }; - std::shared_ptr operator()(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right) const; - }; + struct Binary + { + inline std::unique_ptr operator()(ShaderAst::BinaryType op, ShaderAst::ExpressionPtr left, ShaderAst::ExpressionPtr right) const; + }; - struct BuiltinBuilder - { - constexpr BuiltinBuilder() = default; + struct Branch + { + inline std::unique_ptr operator()(ShaderAst::ExpressionPtr condition, ShaderAst::StatementPtr truePath, ShaderAst::StatementPtr falsePath = nullptr) const; + inline std::unique_ptr operator()(std::vector condStatements, ShaderAst::StatementPtr elseStatement = nullptr) const; + }; - inline std::shared_ptr operator()(ShaderNodes::BuiltinEntry builtin) const; - }; + struct CallFunction + { + inline std::unique_ptr operator()(std::string functionName, std::vector parameters) const; + }; - template - struct GenBuilder - { - constexpr GenBuilder() = default; + struct Cast + { + inline std::unique_ptr operator()(ShaderAst::ExpressionType targetType, std::array expressions) const; + inline std::unique_ptr operator()(ShaderAst::ExpressionType targetType, std::vector expressions) const; + }; - template std::shared_ptr operator()(Args&&... args) const; - }; + struct ConditionalExpression + { + inline std::unique_ptr operator()(std::size_t optionIndex, ShaderAst::ExpressionPtr truePath, ShaderAst::ExpressionPtr falsePath) const; + }; - constexpr GenBuilder AccessMember; - constexpr BinOpBuilder Add; - constexpr AssignOpBuilder Assign; - constexpr BuiltinBuilder Builtin; - constexpr GenBuilder Block; - constexpr GenBuilder Branch; - constexpr GenBuilder ConditionalStatement; - constexpr GenBuilder Constant; - constexpr GenBuilder DeclareVariable; - constexpr BinOpBuilder Divide; - constexpr BinOpBuilder Equal; - constexpr GenBuilder ExprStatement; - constexpr GenBuilder Identifier; - constexpr GenBuilder IntrinsicCall; - constexpr GenBuilder Input; - constexpr GenBuilder Local; - constexpr BinOpBuilder Multiply; - constexpr GenBuilder Output; - constexpr GenBuilder Parameter; - constexpr GenBuilder Sample2D; - constexpr GenBuilder Swizzle; - constexpr BinOpBuilder Substract; - constexpr GenBuilder Uniform; + struct ConditionalStatement + { + inline std::unique_ptr operator()(std::size_t optionIndex, ShaderAst::StatementPtr statement) const; + }; - template std::shared_ptr Cast(Args&&... args); + struct Constant + { + inline std::unique_ptr operator()(ShaderAst::ConstantValue value) const; + }; + + struct DeclareFunction + { + inline std::unique_ptr operator()(std::string name, ShaderAst::StatementPtr statement) const; + inline std::unique_ptr operator()(std::string name, std::vector parameters, std::vector statements, ShaderAst::ExpressionType returnType = ShaderAst::NoType{}) const; + inline std::unique_ptr operator()(std::optional entryStage, std::string name, std::vector parameters, std::vector statements, ShaderAst::ExpressionType returnType = ShaderAst::NoType{}) const; + }; + + struct DeclareOption + { + inline std::unique_ptr operator()(std::string name, ShaderAst::ExpressionType type, ShaderAst::ExpressionPtr initialValue = nullptr) const; + }; + + struct DeclareStruct + { + inline std::unique_ptr operator()(ShaderAst::StructDescription description) const; + }; + + struct DeclareVariable + { + inline std::unique_ptr operator()(std::string name, ShaderAst::ExpressionPtr initialValue) const; + inline std::unique_ptr operator()(std::string name, ShaderAst::ExpressionType type, ShaderAst::ExpressionPtr initialValue = nullptr) const; + }; + + struct ExpressionStatement + { + inline std::unique_ptr operator()(ShaderAst::ExpressionPtr expression) const; + }; + + struct Identifier + { + inline std::unique_ptr operator()(std::string name) const; + }; + + struct Intrinsic + { + inline std::unique_ptr operator()(ShaderAst::IntrinsicType intrinsicType, std::vector parameters) const; + }; + + struct Multi + { + inline std::unique_ptr operator()(std::vector statements = {}) const; + }; + + template + struct NoParam + { + inline std::unique_ptr operator()() const; + }; + + struct Return + { + inline std::unique_ptr operator()(ShaderAst::ExpressionPtr expr = nullptr) const; + }; + + struct SelectOption + { + inline std::unique_ptr operator()(std::string optionName, ShaderAst::ExpressionPtr truePath, ShaderAst::ExpressionPtr falsePath) const; + }; + + struct Swizzle + { + inline std::unique_ptr operator()(ShaderAst::ExpressionPtr expression, std::vector swizzleComponents) const; + }; + + struct Unary + { + inline std::unique_ptr operator()(ShaderAst::UnaryType op, ShaderAst::ExpressionPtr expression) const; + }; + } + + constexpr Impl::AccessIndex AccessIndex; + constexpr Impl::AccessMember AccessMember; + constexpr Impl::Assign Assign; + constexpr Impl::Binary Binary; + constexpr Impl::Branch Branch; + constexpr Impl::CallFunction CallFunction; + constexpr Impl::Cast Cast; + constexpr Impl::ConditionalExpression ConditionalExpression; + constexpr Impl::ConditionalStatement ConditionalStatement; + constexpr Impl::Constant Constant; + constexpr Impl::DeclareFunction DeclareFunction; + constexpr Impl::DeclareOption DeclareOption; + constexpr Impl::DeclareStruct DeclareStruct; + constexpr Impl::DeclareVariable DeclareVariable; + constexpr Impl::ExpressionStatement ExpressionStatement; + constexpr Impl::NoParam Discard; + constexpr Impl::Identifier Identifier; + constexpr Impl::Intrinsic Intrinsic; + constexpr Impl::Multi MultiStatement; + constexpr Impl::NoParam NoOp; + constexpr Impl::Return Return; + constexpr Impl::SelectOption SelectOption; + constexpr Impl::Swizzle Swizzle; + constexpr Impl::Unary Unary; } #include diff --git a/include/Nazara/Shader/ShaderBuilder.inl b/include/Nazara/Shader/ShaderBuilder.inl index c3221c84f..9b9ecc510 100644 --- a/include/Nazara/Shader/ShaderBuilder.inl +++ b/include/Nazara/Shader/ShaderBuilder.inl @@ -7,45 +7,281 @@ namespace Nz::ShaderBuilder { + inline std::unique_ptr Impl::AccessMember::operator()(ShaderAst::ExpressionPtr expr, std::vector memberIdentifiers) const + { + auto accessMemberNode = std::make_unique(); + accessMemberNode->expr = std::move(expr); + accessMemberNode->identifiers = std::move(memberIdentifiers); + + return accessMemberNode; + } + + inline std::unique_ptr Impl::AccessIndex::operator()(ShaderAst::ExpressionPtr expr, const std::vector& indexConstants) const + { + auto accessMemberNode = std::make_unique(); + accessMemberNode->expr = std::move(expr); + + accessMemberNode->indices.reserve(indexConstants.size()); + for (Int32 index : indexConstants) + accessMemberNode->indices.push_back(ShaderBuilder::Constant(index)); + + return accessMemberNode; + } + + inline std::unique_ptr Impl::AccessIndex::operator()(ShaderAst::ExpressionPtr expr, std::vector indexExpressions) const + { + auto accessMemberNode = std::make_unique(); + accessMemberNode->expr = std::move(expr); + accessMemberNode->indices = std::move(indexExpressions); + + return accessMemberNode; + } + + inline std::unique_ptr Impl::Assign::operator()(ShaderAst::AssignType op, ShaderAst::ExpressionPtr left, ShaderAst::ExpressionPtr right) const + { + auto assignNode = std::make_unique(); + assignNode->op = op; + assignNode->left = std::move(left); + assignNode->right = std::move(right); + + return assignNode; + } + + inline std::unique_ptr Impl::Binary::operator()(ShaderAst::BinaryType op, ShaderAst::ExpressionPtr left, ShaderAst::ExpressionPtr right) const + { + auto binaryNode = std::make_unique(); + binaryNode->op = op; + binaryNode->left = std::move(left); + binaryNode->right = std::move(right); + + return binaryNode; + } + + inline std::unique_ptr Impl::Branch::operator()(ShaderAst::ExpressionPtr condition, ShaderAst::StatementPtr truePath, ShaderAst::StatementPtr falsePath) const + { + auto branchNode = std::make_unique(); + + auto& condStatement = branchNode->condStatements.emplace_back(); + condStatement.condition = std::move(condition); + condStatement.statement = std::move(truePath); + + branchNode->elseStatement = std::move(falsePath); + + return branchNode; + } + + inline std::unique_ptr Impl::Branch::operator()(std::vector condStatements, ShaderAst::StatementPtr elseStatement) const + { + auto branchNode = std::make_unique(); + branchNode->condStatements = std::move(condStatements); + branchNode->elseStatement = std::move(elseStatement); + + return branchNode; + } + + inline std::unique_ptr Impl::CallFunction::operator()(std::string functionName, std::vector parameters) const + { + auto callFunctionExpression = std::make_unique(); + callFunctionExpression->targetFunction = std::move(functionName); + callFunctionExpression->parameters = std::move(parameters); + + return callFunctionExpression; + } + + inline std::unique_ptr Impl::Cast::operator()(ShaderAst::ExpressionType targetType, std::array expressions) const + { + auto castNode = std::make_unique(); + castNode->expressions = std::move(expressions); + castNode->targetType = std::move(targetType); + + return castNode; + } + + inline std::unique_ptr Impl::Cast::operator()(ShaderAst::ExpressionType targetType, std::vector expressions) const + { + auto castNode = std::make_unique(); + castNode->targetType = std::move(targetType); + + assert(expressions.size() <= castNode->expressions.size()); + for (std::size_t i = 0; i < expressions.size(); ++i) + castNode->expressions[i] = std::move(expressions[i]); + + return castNode; + } + + inline std::unique_ptr Impl::ConditionalExpression::operator()(std::size_t optionIndex, ShaderAst::ExpressionPtr truePath, ShaderAst::ExpressionPtr falsePath) const + { + auto condExprNode = std::make_unique(); + condExprNode->optionIndex = optionIndex; + condExprNode->falsePath = std::move(falsePath); + condExprNode->truePath = std::move(truePath); + + return condExprNode; + } + + inline std::unique_ptr Impl::ConditionalStatement::operator()(std::size_t optionIndex, ShaderAst::StatementPtr statement) const + { + auto condStatementNode = std::make_unique(); + condStatementNode->optionIndex = optionIndex; + condStatementNode->statement = std::move(statement); + + return condStatementNode; + } + + inline std::unique_ptr Impl::Constant::operator()(ShaderAst::ConstantValue value) const + { + auto constantNode = std::make_unique(); + constantNode->value = std::move(value); + + return constantNode; + } + + inline std::unique_ptr Impl::DeclareFunction::operator()(std::string name, ShaderAst::StatementPtr statement) const + { + auto declareFunctionNode = std::make_unique(); + declareFunctionNode->name = std::move(name); + declareFunctionNode->statements.push_back(std::move(statement)); + + return declareFunctionNode; + } + + inline std::unique_ptr Impl::DeclareFunction::operator()(std::string name, std::vector parameters, std::vector statements, ShaderAst::ExpressionType returnType) const + { + auto declareFunctionNode = std::make_unique(); + declareFunctionNode->name = std::move(name); + declareFunctionNode->parameters = std::move(parameters); + declareFunctionNode->returnType = std::move(returnType); + declareFunctionNode->statements = std::move(statements); + + return declareFunctionNode; + } + + inline std::unique_ptr Impl::DeclareFunction::operator()(std::optional entryStage, std::string name, std::vector parameters, std::vector statements, ShaderAst::ExpressionType returnType) const + { + auto declareFunctionNode = std::make_unique(); + declareFunctionNode->entryStage = entryStage; + declareFunctionNode->name = std::move(name); + declareFunctionNode->parameters = std::move(parameters); + declareFunctionNode->returnType = std::move(returnType); + declareFunctionNode->statements = std::move(statements); + + return declareFunctionNode; + } + + inline std::unique_ptr Impl::DeclareOption::operator()(std::string name, ShaderAst::ExpressionType type, ShaderAst::ExpressionPtr initialValue) const + { + auto declareOptionNode = std::make_unique(); + declareOptionNode->optName = std::move(name); + declareOptionNode->optType = std::move(type); + declareOptionNode->initialValue = std::move(initialValue); + + return declareOptionNode; + } + + inline std::unique_ptr Impl::DeclareStruct::operator()(ShaderAst::StructDescription description) const + { + auto declareStructNode = std::make_unique(); + declareStructNode->description = std::move(description); + + return declareStructNode; + } + + inline std::unique_ptr Impl::DeclareVariable::operator()(std::string name, ShaderAst::ExpressionPtr initialValue) const + { + auto declareVariableNode = std::make_unique(); + declareVariableNode->varName = std::move(name); + declareVariableNode->initialExpression = std::move(initialValue); + + return declareVariableNode; + } + + inline std::unique_ptr Impl::DeclareVariable::operator()(std::string name, ShaderAst::ExpressionType type, ShaderAst::ExpressionPtr initialValue) const + { + auto declareVariableNode = std::make_unique(); + declareVariableNode->varName = std::move(name); + declareVariableNode->varType = std::move(type); + declareVariableNode->initialExpression = std::move(initialValue); + + return declareVariableNode; + } + + inline std::unique_ptr Impl::ExpressionStatement::operator()(ShaderAst::ExpressionPtr expression) const + { + auto expressionStatementNode = std::make_unique(); + expressionStatementNode->expression = std::move(expression); + + return expressionStatementNode; + } + + inline std::unique_ptr Impl::Identifier::operator()(std::string name) const + { + auto identifierNode = std::make_unique(); + identifierNode->identifier = std::move(name); + + return identifierNode; + } + + inline std::unique_ptr Impl::Intrinsic::operator()(ShaderAst::IntrinsicType intrinsicType, std::vector parameters) const + { + auto intrinsicExpression = std::make_unique(); + intrinsicExpression->intrinsic = intrinsicType; + intrinsicExpression->parameters = std::move(parameters); + + return intrinsicExpression; + } + + inline std::unique_ptr Impl::Multi::operator()(std::vector statements) const + { + auto multiStatement = std::make_unique(); + multiStatement->statements = std::move(statements); + + return multiStatement; + } + template - template - std::shared_ptr GenBuilder::operator()(Args&&... args) const + std::unique_ptr Impl::NoParam::operator()() const { - return T::Build(std::forward(args)...); + return std::make_unique(); } - template - std::shared_ptr AssignOpBuilder::operator()(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right) const + inline std::unique_ptr Impl::Return::operator()(ShaderAst::ExpressionPtr expr) const { - return ShaderNodes::AssignOp::Build(op, left, right); + auto returnNode = std::make_unique(); + returnNode->returnExpr = std::move(expr); + + return returnNode; } - template - std::shared_ptr BinOpBuilder::operator()(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right) const + inline std::unique_ptr Impl::SelectOption::operator()(std::string optionName, ShaderAst::ExpressionPtr truePath, ShaderAst::ExpressionPtr falsePath) const { - return ShaderNodes::BinaryOp::Build(op, left, right); + auto selectOptNode = std::make_unique(); + selectOptNode->optionName = std::move(optionName); + selectOptNode->falsePath = std::move(falsePath); + selectOptNode->truePath = std::move(truePath); + + return selectOptNode; } - inline std::shared_ptr BuiltinBuilder::operator()(ShaderNodes::BuiltinEntry builtin) const + inline std::unique_ptr Impl::Swizzle::operator()(ShaderAst::ExpressionPtr expression, std::vector swizzleComponents) const { - ShaderNodes::BasicType exprType = ShaderNodes::BasicType::Void; + auto swizzleNode = std::make_unique(); + swizzleNode->expression = std::move(expression); - switch (builtin) - { - case ShaderNodes::BuiltinEntry::VertexPosition: - exprType = ShaderNodes::BasicType::Float4; - break; - } + assert(swizzleComponents.size() <= swizzleNode->components.size()); + swizzleNode->componentCount = swizzleComponents.size(); + for (std::size_t i = 0; i < swizzleNode->componentCount; ++i) + swizzleNode->components[i] = swizzleComponents[i]; - NazaraAssert(exprType != ShaderNodes::BasicType::Void, "Unhandled builtin"); - - return ShaderNodes::BuiltinVariable::Build(builtin, exprType); + return swizzleNode; } - template - std::shared_ptr Cast(Args&&... args) + inline std::unique_ptr Impl::Unary::operator()(ShaderAst::UnaryType op, ShaderAst::ExpressionPtr expression) const { - return ShaderNodes::Cast::Build(Type, std::forward(args)...); + auto unaryNode = std::make_unique(); + unaryNode->expression = std::move(expression); + unaryNode->op = op; + + return unaryNode; } } diff --git a/include/Nazara/Shader/ShaderEnums.hpp b/include/Nazara/Shader/ShaderEnums.hpp deleted file mode 100644 index ed322e3e6..000000000 --- a/include/Nazara/Shader/ShaderEnums.hpp +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_SHADER_ENUMS_HPP -#define NAZARA_SHADER_ENUMS_HPP - -#include - -namespace Nz::ShaderNodes -{ - enum class AssignType - { - Simple //< = - }; - - enum class BasicType - { - Boolean, //< bool - Float1, //< float - Float2, //< vec2 - Float3, //< vec3 - Float4, //< vec4 - Int1, //< int - Int2, //< ivec2 - Int3, //< ivec3 - Int4, //< ivec4 - Mat4x4, //< mat4 - Sampler2D, //< sampler2D - Void, //< void - UInt1, //< uint - UInt2, //< uvec2 - UInt3, //< uvec3 - UInt4 //< uvec4 - }; - - enum class BinaryType - { - Add, //< + - Substract, //< - - Multiply, //< * - Divide, //< / - - Equality //< == - }; - - enum class BuiltinEntry - { - VertexPosition, // gl_Position - }; - - enum class ExpressionCategory - { - LValue, - RValue - }; - - enum class IntrinsicType - { - CrossProduct, - DotProduct - }; - - enum class MemoryLayout - { - Std140 - }; - - enum class NodeType - { - None = -1, - - AccessMember, - AssignOp, - BinaryOp, - Branch, - Cast, - Constant, - ConditionalStatement, - DeclareVariable, - ExpressionStatement, - Identifier, - IntrinsicCall, - Sample2D, - SwizzleOp, - StatementBlock - }; - - enum class SsaInstruction - { - OpAdd, - OpDiv, - OpMul, - OpSub, - OpSample - }; - - enum class SwizzleComponent - { - First, - Second, - Third, - Fourth - }; - - enum class VariableType - { - None = -1, - - BuiltinVariable, - InputVariable, - LocalVariable, - OutputVariable, - ParameterVariable, - UniformVariable - }; -} - -#endif // NAZARA_SHADER_ENUMS_HPP diff --git a/include/Nazara/Shader/ShaderExpressionType.hpp b/include/Nazara/Shader/ShaderExpressionType.hpp deleted file mode 100644 index 6d5385121..000000000 --- a/include/Nazara/Shader/ShaderExpressionType.hpp +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_SHADER_EXPRESSIONTYPE_HPP -#define NAZARA_SHADER_EXPRESSIONTYPE_HPP - -#include -#include -#include -#include - -namespace Nz -{ - using ShaderExpressionType = std::variant; - - inline bool IsBasicType(const ShaderExpressionType& type); - inline bool IsMatrixType(const ShaderExpressionType& type); - inline bool IsSamplerType(const ShaderExpressionType& type); - inline bool IsStructType(const ShaderExpressionType& type); -} - -#include - -#endif // NAZARA_SHADER_EXPRESSIONTYPE_HPP diff --git a/include/Nazara/Shader/ShaderExpressionType.inl b/include/Nazara/Shader/ShaderExpressionType.inl deleted file mode 100644 index 8f72fb376..000000000 --- a/include/Nazara/Shader/ShaderExpressionType.inl +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include -#include - -namespace Nz -{ - inline bool IsBasicType(const ShaderExpressionType& type) - { - return std::visit([&](auto&& arg) - { - using T = std::decay_t; - if constexpr (std::is_same_v) - return true; - else if constexpr (std::is_same_v) - return false; - else - static_assert(AlwaysFalse::value, "non-exhaustive visitor"); - - }, type); - } - - inline bool IsMatrixType(const ShaderExpressionType& type) - { - using namespace ShaderNodes; - - if (!IsBasicType(type)) - return false; - - switch (std::get(type)) - { - case BasicType::Mat4x4: - return true; - - case BasicType::Boolean: - case BasicType::Float1: - case BasicType::Float2: - case BasicType::Float3: - case BasicType::Float4: - case BasicType::Int1: - case BasicType::Int2: - case BasicType::Int3: - case BasicType::Int4: - case BasicType::Sampler2D: - case BasicType::Void: - case BasicType::UInt1: - case BasicType::UInt2: - case BasicType::UInt3: - case BasicType::UInt4: - return false; - } - - return false; - } - - inline bool IsSamplerType(const ShaderExpressionType& type) - { - using namespace ShaderNodes; - - if (!IsBasicType(type)) - return false; - - switch (std::get(type)) - { - case BasicType::Sampler2D: - return true; - - case BasicType::Boolean: - case BasicType::Float1: - case BasicType::Float2: - case BasicType::Float3: - case BasicType::Float4: - case BasicType::Int1: - case BasicType::Int2: - case BasicType::Int3: - case BasicType::Int4: - case BasicType::Mat4x4: - case BasicType::Void: - case BasicType::UInt1: - case BasicType::UInt2: - case BasicType::UInt3: - case BasicType::UInt4: - return false; - } - - return false; - } - - inline bool IsStructType(const ShaderExpressionType& type) - { - return std::visit([&](auto&& arg) - { - using T = std::decay_t; - if constexpr (std::is_same_v) - return false; - else if constexpr (std::is_same_v) - return true; - else - static_assert(AlwaysFalse::value, "non-exhaustive visitor"); - - }, type); - } -} - -#include diff --git a/include/Nazara/Shader/ShaderLangLexer.hpp b/include/Nazara/Shader/ShaderLangLexer.hpp new file mode 100644 index 000000000..10c63d31a --- /dev/null +++ b/include/Nazara/Shader/ShaderLangLexer.hpp @@ -0,0 +1,56 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADER_LANGLEXER_HPP +#define NAZARA_SHADER_LANGLEXER_HPP + +#include +#include +#include +#include +#include +#include + +namespace Nz::ShaderLang +{ + enum class TokenType + { +#define NAZARA_SHADERLANG_TOKEN(X) X, + +#include + }; + + struct Token + { + unsigned int column; + unsigned int line; + TokenType type; + std::variant data; + }; + + class BadNumber : public std::exception + { + using exception::exception; + }; + + class NumberOutOfRange : public std::exception + { + using exception::exception; + }; + + class UnrecognizedToken : public std::exception + { + using exception::exception; + }; + + NAZARA_SHADER_API std::vector Tokenize(const std::string_view& str); + NAZARA_SHADER_API const char* ToString(TokenType tokenType); + NAZARA_SHADER_API std::string ToString(const std::vector& tokens, bool pretty = true); +} + +#include + +#endif diff --git a/include/Nazara/Shader/ShaderAstCloner.inl b/include/Nazara/Shader/ShaderLangLexer.inl similarity index 85% rename from include/Nazara/Shader/ShaderAstCloner.inl rename to include/Nazara/Shader/ShaderLangLexer.inl index 1182f110d..6767d0351 100644 --- a/include/Nazara/Shader/ShaderAstCloner.inl +++ b/include/Nazara/Shader/ShaderLangLexer.inl @@ -2,7 +2,7 @@ // This file is part of the "Nazara Engine - Shader generator" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include namespace Nz diff --git a/include/Nazara/Shader/ShaderLangParser.hpp b/include/Nazara/Shader/ShaderLangParser.hpp new file mode 100644 index 000000000..525906b0c --- /dev/null +++ b/include/Nazara/Shader/ShaderLangParser.hpp @@ -0,0 +1,135 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADER_LANGPARSER_HPP +#define NAZARA_SHADER_LANGPARSER_HPP + +#include +#include +#include +#include +#include +#include + +namespace Nz::ShaderLang +{ + class AttributeError : public std::runtime_error + { + public: + using runtime_error::runtime_error; + }; + + class ExpectedToken : public std::exception + { + public: + using exception::exception; + }; + + class DuplicateIdentifier : public std::runtime_error + { + public: + using runtime_error::runtime_error; + }; + + class ReservedKeyword : public std::exception + { + public: + using exception::exception; + }; + + class UnknownAttribute : public std::exception + { + public: + using exception::exception; + }; + + class UnknownType : public std::exception + { + public: + using exception::exception; + }; + + class UnexpectedToken : public std::exception + { + public: + using exception::exception; + }; + + class NAZARA_SHADER_API Parser + { + public: + inline Parser(); + ~Parser() = default; + + ShaderAst::StatementPtr Parse(const std::vector& tokens); + + private: + // Flow control + const Token& Advance(); + void Consume(std::size_t count = 1); + std::optional DecodeType(const std::string& identifier); + void EnterScope(); + const Token& Expect(const Token& token, TokenType type); + const Token& ExpectNot(const Token& token, TokenType type); + const Token& Expect(TokenType type); + void LeaveScope(); + bool IsVariableInScope(const std::string_view& identifier) const; + void RegisterVariable(std::string identifier); + const Token& Peek(std::size_t advance = 0); + + std::vector ParseAttributes(); + + // Statements + ShaderAst::StatementPtr ParseExternalBlock(std::vector attributes = {}); + std::vector ParseFunctionBody(); + ShaderAst::StatementPtr ParseFunctionDeclaration(std::vector attributes = {}); + ShaderAst::DeclareFunctionStatement::Parameter ParseFunctionParameter(); + ShaderAst::StatementPtr ParseOptionDeclaration(); + ShaderAst::StatementPtr ParseStructDeclaration(std::vector attributes = {}); + ShaderAst::StatementPtr ParseReturnStatement(); + ShaderAst::StatementPtr ParseStatement(); + std::vector ParseStatementList(); + ShaderAst::StatementPtr ParseVariableDeclaration(); + + // Expressions + ShaderAst::ExpressionPtr ParseBinOpRhs(int exprPrecedence, ShaderAst::ExpressionPtr lhs); + ShaderAst::ExpressionPtr ParseExpression(); + ShaderAst::ExpressionPtr ParseFloatingPointExpression(); + ShaderAst::ExpressionPtr ParseIdentifier(); + ShaderAst::ExpressionPtr ParseIntegerExpression(); + std::vector ParseParameters(); + ShaderAst::ExpressionPtr ParseParenthesisExpression(); + ShaderAst::ExpressionPtr ParsePrimaryExpression(); + ShaderAst::ExpressionPtr ParseSelectOptExpression(); + ShaderAst::ExpressionPtr ParseVariableAssignation(); + + ShaderAst::AttributeType ParseIdentifierAsAttributeType(); + const std::string& ParseIdentifierAsName(); + ShaderAst::PrimitiveType ParsePrimitiveType(); + ShaderAst::ExpressionType ParseType(); + + static int GetTokenPrecedence(TokenType token); + + struct Context + { + std::size_t tokenCount; + std::size_t tokenIndex = 0; + std::vector scopeSizes; + std::vector identifiersInScope; + std::unique_ptr root; + const Token* tokens; + }; + + Context* m_context; + }; + + inline ShaderAst::StatementPtr Parse(const std::vector& tokens); + NAZARA_SHADER_API ShaderAst::StatementPtr Parse(const std::filesystem::path& sourcePath); +} + +#include + +#endif diff --git a/include/Nazara/Shader/ShaderLangParser.inl b/include/Nazara/Shader/ShaderLangParser.inl new file mode 100644 index 000000000..a8f0ca69f --- /dev/null +++ b/include/Nazara/Shader/ShaderLangParser.inl @@ -0,0 +1,22 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz::ShaderLang +{ + inline Parser::Parser() : + m_context(nullptr) + { + } + + inline ShaderAst::StatementPtr Parse(const std::vector& tokens) + { + Parser parser; + return parser.Parse(tokens); + } +} + +#include diff --git a/include/Nazara/Shader/ShaderLangTokenList.hpp b/include/Nazara/Shader/ShaderLangTokenList.hpp new file mode 100644 index 000000000..a7b8c50f7 --- /dev/null +++ b/include/Nazara/Shader/ShaderLangTokenList.hpp @@ -0,0 +1,50 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#if !defined(NAZARA_SHADERLANG_TOKEN) +#error You must define NAZARA_SHADERLANG_TOKEN before including this file +#endif + +#ifndef NAZARA_SHADERLANG_TOKEN_LAST +#define NAZARA_SHADERLANG_TOKEN_LAST(X) NAZARA_SHADERLANG_TOKEN(X) +#endif + +NAZARA_SHADERLANG_TOKEN(Assign) +NAZARA_SHADERLANG_TOKEN(BoolFalse) +NAZARA_SHADERLANG_TOKEN(BoolTrue) +NAZARA_SHADERLANG_TOKEN(ClosingParenthesis) +NAZARA_SHADERLANG_TOKEN(ClosingCurlyBracket) +NAZARA_SHADERLANG_TOKEN(ClosingSquareBracket) +NAZARA_SHADERLANG_TOKEN(Colon) +NAZARA_SHADERLANG_TOKEN(Comma) +NAZARA_SHADERLANG_TOKEN(Divide) +NAZARA_SHADERLANG_TOKEN(Dot) +NAZARA_SHADERLANG_TOKEN(Equal) +NAZARA_SHADERLANG_TOKEN(External) +NAZARA_SHADERLANG_TOKEN(FloatingPointValue) +NAZARA_SHADERLANG_TOKEN(EndOfStream) +NAZARA_SHADERLANG_TOKEN(FunctionDeclaration) +NAZARA_SHADERLANG_TOKEN(FunctionReturn) +NAZARA_SHADERLANG_TOKEN(GreatherThan) +NAZARA_SHADERLANG_TOKEN(GreatherThanEqual) +NAZARA_SHADERLANG_TOKEN(IntegerValue) +NAZARA_SHADERLANG_TOKEN(Identifier) +NAZARA_SHADERLANG_TOKEN(LessThan) +NAZARA_SHADERLANG_TOKEN(LessThanEqual) +NAZARA_SHADERLANG_TOKEN(Let) +NAZARA_SHADERLANG_TOKEN(Multiply) +NAZARA_SHADERLANG_TOKEN(Minus) +NAZARA_SHADERLANG_TOKEN(NotEqual) +NAZARA_SHADERLANG_TOKEN(Plus) +NAZARA_SHADERLANG_TOKEN(OpenCurlyBracket) +NAZARA_SHADERLANG_TOKEN(OpenSquareBracket) +NAZARA_SHADERLANG_TOKEN(OpenParenthesis) +NAZARA_SHADERLANG_TOKEN(Option) +NAZARA_SHADERLANG_TOKEN(Semicolon) +NAZARA_SHADERLANG_TOKEN(Return) +NAZARA_SHADERLANG_TOKEN(SelectOpt) +NAZARA_SHADERLANG_TOKEN(Struct) + +#undef NAZARA_SHADERLANG_TOKEN +#undef NAZARA_SHADERLANG_TOKEN_LAST diff --git a/include/Nazara/Shader/ShaderNodes.hpp b/include/Nazara/Shader/ShaderNodes.hpp deleted file mode 100644 index b3af5f1aa..000000000 --- a/include/Nazara/Shader/ShaderNodes.hpp +++ /dev/null @@ -1,283 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_SHADER_NODES_HPP -#define NAZARA_SHADER_NODES_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Nz -{ - class ShaderAstVisitor; - - namespace ShaderNodes - { - class Node; - - using NodePtr = std::shared_ptr; - - class NAZARA_SHADER_API Node - { - public: - virtual ~Node(); - - inline NodeType GetType() const; - inline bool IsStatement() const; - - virtual void Visit(ShaderAstVisitor& visitor) = 0; - - static inline unsigned int GetComponentCount(BasicType type); - static inline BasicType GetComponentType(BasicType type); - - protected: - inline Node(NodeType type, bool isStatement); - - private: - NodeType m_type; - bool m_isStatement; - }; - - class Expression; - - using ExpressionPtr = std::shared_ptr; - - class NAZARA_SHADER_API Expression : public Node - { - public: - inline Expression(NodeType type); - - virtual ExpressionCategory GetExpressionCategory() const; - virtual ShaderExpressionType GetExpressionType() const = 0; - }; - - class Statement; - - using StatementPtr = std::shared_ptr; - - class NAZARA_SHADER_API Statement : public Node - { - public: - inline Statement(NodeType type); - }; - - struct NAZARA_SHADER_API ExpressionStatement : public Statement - { - inline ExpressionStatement(); - - void Visit(ShaderAstVisitor& visitor) override; - - ExpressionPtr expression; - - static inline std::shared_ptr Build(ExpressionPtr expr); - }; - - ////////////////////////////////////////////////////////////////////////// - - struct NAZARA_SHADER_API ConditionalStatement : public Statement - { - inline ConditionalStatement(); - - void Visit(ShaderAstVisitor& visitor) override; - - std::string conditionName; - StatementPtr statement; - - static inline std::shared_ptr Build(std::string condition, StatementPtr statementPtr); - }; - - struct NAZARA_SHADER_API StatementBlock : public Statement - { - inline StatementBlock(); - - void Visit(ShaderAstVisitor& visitor) override; - - std::vector statements; - - static inline std::shared_ptr Build(std::vector statements); - template static std::shared_ptr Build(Args&&... args); - }; - - struct NAZARA_SHADER_API DeclareVariable : public Statement - { - inline DeclareVariable(); - - void Visit(ShaderAstVisitor& visitor) override; - - ExpressionPtr expression; - VariablePtr variable; - - static inline std::shared_ptr Build(VariablePtr variable, ExpressionPtr expression = nullptr); - }; - - struct NAZARA_SHADER_API Identifier : public Expression - { - inline Identifier(); - - ExpressionCategory GetExpressionCategory() const override; - ShaderExpressionType GetExpressionType() const override; - void Visit(ShaderAstVisitor& visitor) override; - - VariablePtr var; - - static inline std::shared_ptr Build(VariablePtr variable); - }; - - struct NAZARA_SHADER_API AccessMember : public Expression - { - inline AccessMember(); - - ExpressionCategory GetExpressionCategory() const override; - ShaderExpressionType GetExpressionType() const override; - void Visit(ShaderAstVisitor& visitor) override; - - ExpressionPtr structExpr; - ShaderExpressionType exprType; - std::vector memberIndices; - - static inline std::shared_ptr Build(ExpressionPtr structExpr, std::size_t memberIndex, ShaderExpressionType exprType); - static inline std::shared_ptr Build(ExpressionPtr structExpr, std::vector memberIndices, ShaderExpressionType exprType); - }; - - ////////////////////////////////////////////////////////////////////////// - - struct NAZARA_SHADER_API AssignOp : public Expression - { - inline AssignOp(); - - ShaderExpressionType GetExpressionType() const override; - void Visit(ShaderAstVisitor& visitor) override; - - AssignType op; - ExpressionPtr left; - ExpressionPtr right; - - static inline std::shared_ptr Build(AssignType op, ExpressionPtr left, ExpressionPtr right); - }; - - struct NAZARA_SHADER_API BinaryOp : public Expression - { - inline BinaryOp(); - - ShaderExpressionType GetExpressionType() const override; - void Visit(ShaderAstVisitor& visitor) override; - - BinaryType op; - ExpressionPtr left; - ExpressionPtr right; - - static inline std::shared_ptr Build(BinaryType op, ExpressionPtr left, ExpressionPtr right); - }; - - struct NAZARA_SHADER_API Branch : public Statement - { - struct ConditionalStatement; - - inline Branch(); - - void Visit(ShaderAstVisitor& visitor) override; - - std::vector condStatements; - StatementPtr elseStatement; - - struct ConditionalStatement - { - ExpressionPtr condition; - StatementPtr statement; - }; - - static inline std::shared_ptr Build(ExpressionPtr condition, StatementPtr trueStatement, StatementPtr falseStatement = nullptr); - static inline std::shared_ptr Build(std::vector statements, StatementPtr elseStatement = nullptr); - }; - - struct NAZARA_SHADER_API Cast : public Expression - { - inline Cast(); - - ShaderExpressionType GetExpressionType() const override; - void Visit(ShaderAstVisitor& visitor) override; - - BasicType exprType; - std::array expressions; - - static inline std::shared_ptr Build(BasicType castTo, ExpressionPtr first, ExpressionPtr second = nullptr, ExpressionPtr third = nullptr, ExpressionPtr fourth = nullptr); - static inline std::shared_ptr Build(BasicType castTo, ExpressionPtr* expressions, std::size_t expressionCount); - }; - - struct NAZARA_SHADER_API Constant : public Expression - { - inline Constant(); - - ShaderExpressionType GetExpressionType() const override; - void Visit(ShaderAstVisitor& visitor) override; - - ShaderConstantValue value; - - template static std::shared_ptr Build(const T& value); - }; - - struct NAZARA_SHADER_API SwizzleOp : public Expression - { - inline SwizzleOp(); - - ExpressionCategory GetExpressionCategory() const override; - ShaderExpressionType GetExpressionType() const override; - void Visit(ShaderAstVisitor& visitor) override; - - std::array components; - std::size_t componentCount; - ExpressionPtr expression; - - static inline std::shared_ptr Build(ExpressionPtr expressionPtr, SwizzleComponent swizzleComponent); - static inline std::shared_ptr Build(ExpressionPtr expressionPtr, std::initializer_list swizzleComponents); - static inline std::shared_ptr Build(ExpressionPtr expressionPtr, const SwizzleComponent* components, std::size_t componentCount); - }; - - ////////////////////////////////////////////////////////////////////////// - - struct NAZARA_SHADER_API Sample2D : public Expression - { - inline Sample2D(); - - ShaderExpressionType GetExpressionType() const override; - void Visit(ShaderAstVisitor& visitor) override; - - ExpressionPtr sampler; - ExpressionPtr coordinates; - - static inline std::shared_ptr Build(ExpressionPtr samplerPtr, ExpressionPtr coordinatesPtr); - }; - - ////////////////////////////////////////////////////////////////////////// - - struct NAZARA_SHADER_API IntrinsicCall : public Expression - { - inline IntrinsicCall(); - - ShaderExpressionType GetExpressionType() const override; - void Visit(ShaderAstVisitor& visitor) override; - - IntrinsicType intrinsic; - std::vector parameters; - - static inline std::shared_ptr Build(IntrinsicType intrinsic, std::vector parameters); - }; - } -} - -#include - -#endif diff --git a/include/Nazara/Shader/ShaderNodes.inl b/include/Nazara/Shader/ShaderNodes.inl deleted file mode 100644 index 1e0817b62..000000000 --- a/include/Nazara/Shader/ShaderNodes.inl +++ /dev/null @@ -1,348 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include - -namespace Nz::ShaderNodes -{ - inline Node::Node(NodeType type, bool isStatement) : - m_type(type), - m_isStatement(isStatement) - { - } - - inline NodeType ShaderNodes::Node::GetType() const - { - return m_type; - } - - inline bool Node::IsStatement() const - { - return m_isStatement; - } - - inline unsigned int Node::GetComponentCount(BasicType type) - { - switch (type) - { - case BasicType::Float2: - case BasicType::Int2: - return 2; - - case BasicType::Float3: - case BasicType::Int3: - return 3; - - case BasicType::Float4: - case BasicType::Int4: - return 4; - - case BasicType::Mat4x4: - return 4; - - default: - return 1; - } - } - - inline BasicType Node::GetComponentType(BasicType type) - { - switch (type) - { - case BasicType::Float2: - case BasicType::Float3: - case BasicType::Float4: - return BasicType::Float1; - - case BasicType::Int2: - case BasicType::Int3: - case BasicType::Int4: - return BasicType::Int1; - - case BasicType::Mat4x4: - return BasicType::Float4; - - default: - return type; - } - } - - - inline Expression::Expression(NodeType type) : - Node(type, false) - { - } - - inline Statement::Statement(NodeType type) : - Node(type, true) - { - } - - - - inline ExpressionStatement::ExpressionStatement() : - Statement(NodeType::ExpressionStatement) - { - } - - inline std::shared_ptr ExpressionStatement::Build(ExpressionPtr expr) - { - auto node = std::make_shared(); - node->expression = std::move(expr); - - return node; - } - - inline ConditionalStatement::ConditionalStatement() : - Statement(NodeType::ConditionalStatement) - { - } - - inline std::shared_ptr ConditionalStatement::Build(std::string condition, StatementPtr statementPtr) - { - auto node = std::make_shared(); - node->conditionName = std::move(condition); - node->statement = std::move(statementPtr); - - return node; - } - - - inline StatementBlock::StatementBlock() : - Statement(NodeType::StatementBlock) - { - } - - inline std::shared_ptr StatementBlock::Build(std::vector statements) - { - auto node = std::make_shared(); - node->statements = std::move(statements); - - return node; - } - - template - std::shared_ptr StatementBlock::Build(Args&&... args) - { - auto node = std::make_shared(); - node->statements = std::vector({ std::forward(args)... }); - - return node; - } - - - inline DeclareVariable::DeclareVariable() : - Statement(NodeType::DeclareVariable) - { - } - - inline std::shared_ptr DeclareVariable::Build(VariablePtr variable, ExpressionPtr expression) - { - auto node = std::make_shared(); - node->expression = std::move(expression); - node->variable = std::move(variable); - - return node; - } - - - inline Identifier::Identifier() : - Expression(NodeType::Identifier) - { - } - - inline std::shared_ptr Identifier::Build(VariablePtr variable) - { - auto node = std::make_shared(); - node->var = std::move(variable); - - return node; - } - - - inline AccessMember::AccessMember() : - Expression(NodeType::AccessMember) - { - } - - inline std::shared_ptr AccessMember::Build(ExpressionPtr structExpr, std::size_t memberIndex, ShaderExpressionType exprType) - { - return Build(std::move(structExpr), std::vector{ memberIndex }, exprType); - } - - inline std::shared_ptr AccessMember::Build(ExpressionPtr structExpr, std::vector memberIndices, ShaderExpressionType exprType) - { - auto node = std::make_shared(); - node->exprType = std::move(exprType); - node->memberIndices = std::move(memberIndices); - node->structExpr = std::move(structExpr); - - return node; - } - - - inline AssignOp::AssignOp() : - Expression(NodeType::AssignOp) - { - } - - inline std::shared_ptr AssignOp::Build(AssignType op, ExpressionPtr left, ExpressionPtr right) - { - auto node = std::make_shared(); - node->op = op; - node->left = std::move(left); - node->right = std::move(right); - - return node; - } - - - inline BinaryOp::BinaryOp() : - Expression(NodeType::BinaryOp) - { - } - - inline std::shared_ptr BinaryOp::Build(BinaryType op, ExpressionPtr left, ExpressionPtr right) - { - auto node = std::make_shared(); - node->op = op; - node->left = std::move(left); - node->right = std::move(right); - - return node; - } - - - inline Branch::Branch() : - Statement(NodeType::Branch) - { - } - - inline std::shared_ptr Branch::Build(ExpressionPtr condition, StatementPtr trueStatement, StatementPtr falseStatement) - { - auto node = std::make_shared(); - node->condStatements.emplace_back(ConditionalStatement{ std::move(condition), std::move(trueStatement) }); - node->elseStatement = std::move(falseStatement); - - return node; - } - - inline std::shared_ptr Branch::Build(std::vector statements, StatementPtr elseStatement) - { - auto node = std::make_shared(); - node->condStatements = std::move(statements); - node->elseStatement = std::move(elseStatement); - - return node; - } - - - inline Cast::Cast() : - Expression(NodeType::Cast) - { - } - - inline std::shared_ptr Cast::Build(BasicType castTo, ExpressionPtr first, ExpressionPtr second, ExpressionPtr third, ExpressionPtr fourth) - { - auto node = std::make_shared(); - node->exprType = castTo; - node->expressions = { {first, second, third, fourth} }; - - return node; - } - - inline std::shared_ptr Cast::Build(BasicType castTo, ExpressionPtr* Expressions, std::size_t expressionCount) - { - auto node = std::make_shared(); - node->exprType = castTo; - for (std::size_t i = 0; i < expressionCount; ++i) - node->expressions[i] = Expressions[i]; - - return node; - } - - - inline Constant::Constant() : - Expression(NodeType::Constant) - { - } - - template - std::shared_ptr Nz::ShaderNodes::Constant::Build(const T& value) - { - auto node = std::make_shared(); - node->value = value; - - return node; - } - - - inline SwizzleOp::SwizzleOp() : - Expression(NodeType::SwizzleOp) - { - } - - inline std::shared_ptr SwizzleOp::Build(ExpressionPtr expressionPtr, SwizzleComponent swizzleComponent) - { - return Build(std::move(expressionPtr), { swizzleComponent }); - } - - inline std::shared_ptr SwizzleOp::Build(ExpressionPtr expressionPtr, std::initializer_list swizzleComponents) - { - auto node = std::make_shared(); - node->componentCount = swizzleComponents.size(); - node->expression = std::move(expressionPtr); - - std::copy(swizzleComponents.begin(), swizzleComponents.end(), node->components.begin()); - - return node; - } - - inline std::shared_ptr SwizzleOp::Build(ExpressionPtr expressionPtr, const SwizzleComponent* components, std::size_t componentCount) - { - auto node = std::make_shared(); - - assert(componentCount < node->components.size()); - - node->componentCount = componentCount; - node->expression = std::move(expressionPtr); - - std::copy(components, components + componentCount, node->components.begin()); - - return node; - } - - - inline Sample2D::Sample2D() : - Expression(NodeType::Sample2D) - { - } - - inline std::shared_ptr Sample2D::Build(ExpressionPtr samplerPtr, ExpressionPtr coordinatesPtr) - { - auto node = std::make_shared(); - node->coordinates = std::move(coordinatesPtr); - node->sampler = std::move(samplerPtr); - - return node; - } - - - inline IntrinsicCall::IntrinsicCall() : - Expression(NodeType::IntrinsicCall) - { - } - - inline std::shared_ptr IntrinsicCall::Build(IntrinsicType intrinsic, std::vector parameters) - { - auto node = std::make_shared(); - node->intrinsic = intrinsic; - node->parameters = std::move(parameters); - - return node; - } -} - -#include diff --git a/include/Nazara/Shader/ShaderVarVisitor.hpp b/include/Nazara/Shader/ShaderVarVisitor.hpp deleted file mode 100644 index babfb2b1e..000000000 --- a/include/Nazara/Shader/ShaderVarVisitor.hpp +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_SHADERVARVISITOR_HPP -#define NAZARA_SHADERVARVISITOR_HPP - -#include -#include -#include - -namespace Nz -{ - class NAZARA_SHADER_API ShaderVarVisitor - { - public: - ShaderVarVisitor() = default; - ShaderVarVisitor(const ShaderVarVisitor&) = delete; - ShaderVarVisitor(ShaderVarVisitor&&) = delete; - virtual ~ShaderVarVisitor(); - - void Visit(const ShaderNodes::VariablePtr& node); - - virtual void Visit(ShaderNodes::BuiltinVariable& var) = 0; - virtual void Visit(ShaderNodes::InputVariable& var) = 0; - virtual void Visit(ShaderNodes::LocalVariable& var) = 0; - virtual void Visit(ShaderNodes::OutputVariable& var) = 0; - virtual void Visit(ShaderNodes::ParameterVariable& var) = 0; - virtual void Visit(ShaderNodes::UniformVariable& var) = 0; - - ShaderVarVisitor& operator=(const ShaderVarVisitor&) = delete; - ShaderVarVisitor& operator=(ShaderVarVisitor&&) = delete; - }; -} - -#endif diff --git a/include/Nazara/Shader/ShaderVarVisitorExcept.hpp b/include/Nazara/Shader/ShaderVarVisitorExcept.hpp deleted file mode 100644 index 3fa769e21..000000000 --- a/include/Nazara/Shader/ShaderVarVisitorExcept.hpp +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_SHADERVARVISITOREXCEPT_HPP -#define NAZARA_SHADERVARVISITOREXCEPT_HPP - -#include -#include - -namespace Nz -{ - class NAZARA_SHADER_API ShaderVarVisitorExcept : public ShaderVarVisitor - { - public: - using ShaderVarVisitor::Visit; - void Visit(ShaderNodes::BuiltinVariable& var) override; - void Visit(ShaderNodes::InputVariable& var) override; - void Visit(ShaderNodes::LocalVariable& var) override; - void Visit(ShaderNodes::OutputVariable& var) override; - void Visit(ShaderNodes::ParameterVariable& var) override; - void Visit(ShaderNodes::UniformVariable& var) override; - }; -} - -#endif diff --git a/include/Nazara/Shader/ShaderVariables.hpp b/include/Nazara/Shader/ShaderVariables.hpp deleted file mode 100644 index eb0bc8ede..000000000 --- a/include/Nazara/Shader/ShaderVariables.hpp +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_SHADER_VARIABLES_HPP -#define NAZARA_SHADER_VARIABLES_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Nz -{ - class ShaderVarVisitor; - - namespace ShaderNodes - { - struct Variable; - - using VariablePtr = std::shared_ptr; - - struct NAZARA_SHADER_API Variable : std::enable_shared_from_this - { - virtual ~Variable(); - - virtual VariableType GetType() const = 0; - virtual void Visit(ShaderVarVisitor& visitor) = 0; - - ShaderExpressionType type; - }; - - struct BuiltinVariable; - - using BuiltinVariablePtr = std::shared_ptr; - - struct NAZARA_SHADER_API BuiltinVariable : public Variable - { - BuiltinEntry entry; - - VariableType GetType() const override; - void Visit(ShaderVarVisitor& visitor) override; - - static inline std::shared_ptr Build(BuiltinEntry entry, ShaderExpressionType varType); - }; - - struct NamedVariable; - - using NamedVariablePtr = std::shared_ptr; - - struct NAZARA_SHADER_API NamedVariable : public Variable - { - std::string name; - }; - - struct InputVariable; - - using InputVariablePtr = std::shared_ptr; - - struct NAZARA_SHADER_API InputVariable : public NamedVariable - { - VariableType GetType() const override; - void Visit(ShaderVarVisitor& visitor) override; - - static inline std::shared_ptr Build(std::string varName, ShaderExpressionType varType); - }; - - struct LocalVariable; - - using LocalVariablePtr = std::shared_ptr; - - struct NAZARA_SHADER_API LocalVariable : public NamedVariable - { - VariableType GetType() const override; - void Visit(ShaderVarVisitor& visitor) override; - - static inline std::shared_ptr Build(std::string varName, ShaderExpressionType varType); - }; - - struct OutputVariable; - - using OutputVariablePtr = std::shared_ptr; - - struct NAZARA_SHADER_API OutputVariable : public NamedVariable - { - VariableType GetType() const override; - void Visit(ShaderVarVisitor& visitor) override; - - static inline std::shared_ptr Build(std::string varName, ShaderExpressionType varType); - }; - - struct ParameterVariable; - - using ParameterVariablePtr = std::shared_ptr; - - struct NAZARA_SHADER_API ParameterVariable : public NamedVariable - { - VariableType GetType() const override; - void Visit(ShaderVarVisitor& visitor) override; - - static inline std::shared_ptr Build(std::string varName, ShaderExpressionType varType); - }; - - struct UniformVariable; - - using UniformVariablePtr = std::shared_ptr; - - struct NAZARA_SHADER_API UniformVariable : public NamedVariable - { - VariableType GetType() const override; - void Visit(ShaderVarVisitor& visitor) override; - - static inline std::shared_ptr Build(std::string varName, ShaderExpressionType varType); - }; - } -} - -#include - -#endif diff --git a/include/Nazara/Shader/ShaderVariables.inl b/include/Nazara/Shader/ShaderVariables.inl deleted file mode 100644 index 9f2415708..000000000 --- a/include/Nazara/Shader/ShaderVariables.inl +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include - -namespace Nz::ShaderNodes -{ - inline std::shared_ptr BuiltinVariable::Build(BuiltinEntry variable, ShaderExpressionType varType) - { - auto node = std::make_shared(); - node->entry = variable; - node->type = varType; - - return node; - } - - inline std::shared_ptr InputVariable::Build(std::string varName, ShaderExpressionType varType) - { - auto node = std::make_shared(); - node->name = std::move(varName); - node->type = varType; - - return node; - } - - inline std::shared_ptr LocalVariable::Build(std::string varName, ShaderExpressionType varType) - { - auto node = std::make_shared(); - node->name = std::move(varName); - node->type = varType; - - return node; - } - - inline std::shared_ptr OutputVariable::Build(std::string varName, ShaderExpressionType varType) - { - auto node = std::make_shared(); - node->name = std::move(varName); - node->type = varType; - - return node; - } - - inline std::shared_ptr ParameterVariable::Build(std::string varName, ShaderExpressionType varType) - { - auto node = std::make_shared(); - node->name = std::move(varName); - node->type = varType; - - return node; - } - - inline std::shared_ptr UniformVariable::Build(std::string varName, ShaderExpressionType varType) - { - auto node = std::make_shared(); - node->name = std::move(varName); - node->type = varType; - - return node; - } -} - -#include diff --git a/include/Nazara/Shader/ShaderWriter.hpp b/include/Nazara/Shader/ShaderWriter.hpp index 0e896fa40..e50bd8d50 100644 --- a/include/Nazara/Shader/ShaderWriter.hpp +++ b/include/Nazara/Shader/ShaderWriter.hpp @@ -10,20 +10,26 @@ #include #include #include +#include namespace Nz { - class ShaderAst; - class NAZARA_SHADER_API ShaderWriter { public: + struct States; + ShaderWriter() = default; ShaderWriter(const ShaderWriter&) = default; ShaderWriter(ShaderWriter&&) = default; virtual ~ShaderWriter(); - virtual std::string Generate(const ShaderAst& shader) = 0; + struct States + { + Nz::UInt64 enabledOptions = 0; + bool optimize = false; + bool sanitized = false; + }; }; } diff --git a/include/Nazara/Shader/SpirvAstVisitor.hpp b/include/Nazara/Shader/SpirvAstVisitor.hpp index 743dd5130..d6301d5f3 100644 --- a/include/Nazara/Shader/SpirvAstVisitor.hpp +++ b/include/Nazara/Shader/SpirvAstVisitor.hpp @@ -4,51 +4,158 @@ #pragma once -#ifndef NAZARA_SPIRVEXPRESSIONLOAD_HPP -#define NAZARA_SPIRVEXPRESSIONLOAD_HPP +#ifndef NAZARA_SPIRVASTVISITOR_HPP +#define NAZARA_SPIRVASTVISITOR_HPP #include #include -#include -#include +#include +#include +#include +#include +#include #include namespace Nz { class SpirvWriter; - class NAZARA_SHADER_API SpirvAstVisitor : public ShaderAstVisitorExcept + class NAZARA_SHADER_API SpirvAstVisitor : public ShaderAst::ExpressionVisitorExcept, public ShaderAst::StatementVisitorExcept { public: - inline SpirvAstVisitor(SpirvWriter& writer); + struct EntryPoint; + struct FuncData; + struct Variable; + + inline SpirvAstVisitor(SpirvWriter& writer, SpirvSection& instructions, std::vector& funcData); SpirvAstVisitor(const SpirvAstVisitor&) = delete; SpirvAstVisitor(SpirvAstVisitor&&) = delete; ~SpirvAstVisitor() = default; - UInt32 EvaluateExpression(const ShaderNodes::ExpressionPtr& expr); + UInt32 AllocateResultId(); - using ShaderAstVisitorExcept::Visit; - void Visit(ShaderNodes::AccessMember& node) override; - void Visit(ShaderNodes::AssignOp& node) override; - void Visit(ShaderNodes::BinaryOp& node) override; - void Visit(ShaderNodes::Cast& node) override; - void Visit(ShaderNodes::Constant& node) override; - void Visit(ShaderNodes::DeclareVariable& node) override; - void Visit(ShaderNodes::ExpressionStatement& node) override; - void Visit(ShaderNodes::Identifier& node) override; - void Visit(ShaderNodes::IntrinsicCall& node) override; - void Visit(ShaderNodes::Sample2D& node) override; - void Visit(ShaderNodes::StatementBlock& node) override; - void Visit(ShaderNodes::SwizzleOp& node) override; + UInt32 EvaluateExpression(ShaderAst::ExpressionPtr& expr); + + const Variable& GetVariable(std::size_t varIndex) const; + + using ExpressionVisitorExcept::Visit; + using StatementVisitorExcept::Visit; + + void Visit(ShaderAst::AccessIndexExpression& node) override; + void Visit(ShaderAst::AssignExpression& node) override; + void Visit(ShaderAst::BinaryExpression& node) override; + void Visit(ShaderAst::BranchStatement& node) override; + void Visit(ShaderAst::CallFunctionExpression& node) override; + void Visit(ShaderAst::CastExpression& node) override; + void Visit(ShaderAst::ConditionalExpression& node) override; + void Visit(ShaderAst::ConditionalStatement& node) override; + void Visit(ShaderAst::ConstantExpression& node) override; + void Visit(ShaderAst::DeclareExternalStatement& node) override; + void Visit(ShaderAst::DeclareFunctionStatement& node) override; + void Visit(ShaderAst::DeclareOptionStatement& node) override; + void Visit(ShaderAst::DeclareStructStatement& node) override; + void Visit(ShaderAst::DeclareVariableStatement& node) override; + void Visit(ShaderAst::DiscardStatement& node) override; + void Visit(ShaderAst::ExpressionStatement& node) override; + void Visit(ShaderAst::IntrinsicExpression& node) override; + void Visit(ShaderAst::MultiStatement& node) override; + void Visit(ShaderAst::NoOpStatement& node) override; + void Visit(ShaderAst::ReturnStatement& node) override; + void Visit(ShaderAst::SwizzleExpression& node) override; + void Visit(ShaderAst::VariableExpression& node) override; + void Visit(ShaderAst::UnaryExpression& node) override; SpirvAstVisitor& operator=(const SpirvAstVisitor&) = delete; SpirvAstVisitor& operator=(SpirvAstVisitor&&) = delete; + struct EntryPoint + { + struct Input + { + UInt32 memberIndexConstantId; + UInt32 memberPointerId; + UInt32 varId; + }; + + struct Output + { + Int32 memberIndex; + UInt32 typeId; + UInt32 varId; + }; + + struct InputStruct + { + UInt32 pointerId; + UInt32 typeId; + }; + + ShaderStageType stageType; + std::optional inputStruct; + std::optional outputStructTypeId; + std::vector inputs; + std::vector outputs; + std::vector executionModes; + }; + + struct FuncData + { + std::optional entryPointData; + + struct FuncCall + { + std::size_t firstVarIndex; + }; + + struct Parameter + { + UInt32 pointerTypeId; + UInt32 typeId; + }; + + struct Variable + { + UInt32 typeId; + UInt32 varId; + }; + + std::size_t funcIndex; + std::string name; + std::vector funcCalls; + std::vector parameters; + std::vector variables; + std::unordered_map varIndexToVarId; + UInt32 funcId; + UInt32 funcTypeId; + UInt32 returnTypeId; + }; + + struct Variable + { + SpirvStorageClass storage; + UInt32 pointerId; + UInt32 pointedTypeId; + }; + private: void PushResultId(UInt32 value); UInt32 PopResultId(); + inline void RegisterExternalVariable(std::size_t varIndex, const ShaderAst::ExpressionType& type); + inline void RegisterStruct(std::size_t structIndex, ShaderAst::StructDescription structDesc); + inline void RegisterVariable(std::size_t varIndex, UInt32 typeId, UInt32 pointerId, SpirvStorageClass storageClass); + + std::size_t m_extVarIndex; + std::size_t m_funcCallIndex; + std::size_t m_funcIndex; + std::vector m_scopeSizes; + std::vector& m_funcData; + std::vector m_structs; + std::vector> m_variables; + std::vector m_functionBlocks; std::vector m_resultIds; + SpirvBlock* m_currentBlock; + SpirvSection& m_instructions; SpirvWriter& m_writer; }; } diff --git a/include/Nazara/Shader/SpirvAstVisitor.inl b/include/Nazara/Shader/SpirvAstVisitor.inl index 87dc93a54..f67692f6f 100644 --- a/include/Nazara/Shader/SpirvAstVisitor.inl +++ b/include/Nazara/Shader/SpirvAstVisitor.inl @@ -7,10 +7,43 @@ namespace Nz { - inline SpirvAstVisitor::SpirvAstVisitor(SpirvWriter& writer) : + inline SpirvAstVisitor::SpirvAstVisitor(SpirvWriter& writer, SpirvSection& instructions, std::vector& funcData) : + m_extVarIndex(0), + m_funcIndex(0), + m_funcData(funcData), + m_currentBlock(nullptr), + m_instructions(instructions), m_writer(writer) { } + + void SpirvAstVisitor::RegisterExternalVariable(std::size_t varIndex, const ShaderAst::ExpressionType& type) + { + UInt32 pointerId = m_writer.GetExtVarPointerId(varIndex); + SpirvStorageClass storageClass = (IsSamplerType(type)) ? SpirvStorageClass::UniformConstant : SpirvStorageClass::Uniform; + + RegisterVariable(varIndex, m_writer.GetTypeId(type), pointerId, storageClass); + } + + inline void SpirvAstVisitor::RegisterStruct(std::size_t structIndex, ShaderAst::StructDescription structDesc) + { + if (structIndex >= m_structs.size()) + m_structs.resize(structIndex + 1); + + m_structs[structIndex] = std::move(structDesc); + } + + inline void SpirvAstVisitor::RegisterVariable(std::size_t varIndex, UInt32 typeId, UInt32 pointerId, SpirvStorageClass storageClass) + { + if (varIndex >= m_variables.size()) + m_variables.resize(varIndex + 1); + + m_variables[varIndex] = Variable{ + storageClass, + pointerId, + typeId + }; + } } #include diff --git a/include/Nazara/Shader/SpirvBlock.hpp b/include/Nazara/Shader/SpirvBlock.hpp new file mode 100644 index 000000000..6c6a9310d --- /dev/null +++ b/include/Nazara/Shader/SpirvBlock.hpp @@ -0,0 +1,49 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SPIRVBLOCK_HPP +#define NAZARA_SPIRVBLOCK_HPP + +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_SHADER_API SpirvBlock : public SpirvSectionBase + { + public: + inline SpirvBlock(SpirvWriter& writer); + SpirvBlock(const SpirvBlock&) = default; + SpirvBlock(SpirvBlock&&) = default; + ~SpirvBlock() = default; + + inline std::size_t Append(SpirvOp opcode, const OpSize& wordCount); + template std::size_t Append(SpirvOp opcode, Args&&... args); + template std::size_t AppendVariadic(SpirvOp opcode, F&& callback); + + inline UInt32 GetLabelId() const; + + inline bool IsTerminated() const; + + SpirvBlock& operator=(const SpirvBlock&) = delete; + SpirvBlock& operator=(SpirvBlock&&) = default; + + static inline bool IsTerminationInstruction(SpirvOp op); + + private: + inline void HandleSpirvOp(SpirvOp op); + + UInt32 m_labelId; + bool m_isTerminated; + }; +} + +#include + +#endif diff --git a/include/Nazara/Shader/SpirvBlock.inl b/include/Nazara/Shader/SpirvBlock.inl new file mode 100644 index 000000000..2dc50e76b --- /dev/null +++ b/include/Nazara/Shader/SpirvBlock.inl @@ -0,0 +1,76 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + inline SpirvBlock::SpirvBlock(SpirvWriter& writer) : + m_isTerminated(false) + { + m_labelId = writer.AllocateResultId(); + Append(SpirvOp::OpLabel, m_labelId); + } + + inline std::size_t SpirvBlock::Append(SpirvOp opcode, const OpSize& wordCount) + { + HandleSpirvOp(opcode); + + return SpirvSectionBase::Append(opcode, wordCount); + } + + template + std::size_t SpirvBlock::Append(SpirvOp opcode, Args&&... args) + { + HandleSpirvOp(opcode); + + return SpirvSectionBase::Append(opcode, std::forward(args)...); + } + + template + std::size_t SpirvBlock::AppendVariadic(SpirvOp opcode, F&& callback) + { + HandleSpirvOp(opcode); + + return SpirvSectionBase::AppendVariadic(opcode, std::forward(callback)); + } + + inline UInt32 SpirvBlock::GetLabelId() const + { + return m_labelId; + } + + inline bool SpirvBlock::IsTerminated() const + { + return m_isTerminated; + } + + inline bool SpirvBlock::IsTerminationInstruction(SpirvOp op) + { + switch (op) + { + case SpirvOp::OpBranch: + case SpirvOp::OpBranchConditional: + case SpirvOp::OpKill: + case SpirvOp::OpReturn: + case SpirvOp::OpReturnValue: + case SpirvOp::OpSwitch: + case SpirvOp::OpUnreachable: + return true; + + default: + return false; + } + } + + inline void SpirvBlock::HandleSpirvOp(SpirvOp op) + { + assert(!m_isTerminated); + if (IsTerminationInstruction(op)) + m_isTerminated = true; + } +} + +#include diff --git a/include/Nazara/Shader/SpirvConstantCache.hpp b/include/Nazara/Shader/SpirvConstantCache.hpp index 279f71b07..bc2d97b6c 100644 --- a/include/Nazara/Shader/SpirvConstantCache.hpp +++ b/include/Nazara/Shader/SpirvConstantCache.hpp @@ -8,9 +8,9 @@ #define NAZARA_SPIRVCONSTANTCACHE_HPP #include -#include -#include -#include +#include +#include +#include #include #include #include @@ -20,18 +20,20 @@ namespace Nz { - class ShaderAst; class SpirvSection; class NAZARA_SHADER_API SpirvConstantCache { public: + using StructCallback = std::function; + SpirvConstantCache(UInt32& resultId); SpirvConstantCache(const SpirvConstantCache& cache) = delete; SpirvConstantCache(SpirvConstantCache&& cache) noexcept; ~SpirvConstantCache(); struct Constant; + struct Identifier; struct Type; using ConstantPtr = std::shared_ptr; @@ -70,10 +72,10 @@ namespace Nz std::optional depth; std::optional sampled; SpirvDim dim; - SpirvImageFormat format; + SpirvImageFormat format = SpirvImageFormat::Unknown; TypePtr sampledType; - bool arrayed; - bool multisampled; + bool arrayed = false; + bool multisampled = false; }; struct Pointer @@ -127,10 +129,11 @@ namespace Nz struct Variable { + std::optional funcId; //< For inputs/outputs + std::optional initializer; std::string debugName; TypePtr type; SpirvStorageClass storageClass; - std::optional initializer; }; using BaseType = std::variant; @@ -159,6 +162,21 @@ namespace Nz AnyType type; }; + ConstantPtr BuildConstant(const ShaderAst::ConstantValue& value) const; + TypePtr BuildFunctionType(const ShaderAst::ExpressionType& retType, const std::vector& parameters) const; + TypePtr BuildPointerType(const ShaderAst::PrimitiveType& type, SpirvStorageClass storageClass) const; + TypePtr BuildPointerType(const ShaderAst::ExpressionType& type, SpirvStorageClass storageClass) const; + TypePtr BuildType(const ShaderAst::ExpressionType& type) const; + TypePtr BuildType(const ShaderAst::IdentifierType& type) const; + TypePtr BuildType(const ShaderAst::MatrixType& type) const; + TypePtr BuildType(const ShaderAst::NoType& type) const; + TypePtr BuildType(const ShaderAst::PrimitiveType& type) const; + TypePtr BuildType(const ShaderAst::SamplerType& type) const; + TypePtr BuildType(const ShaderAst::StructType& type) const; + TypePtr BuildType(const ShaderAst::StructDescription& structDesc) const; + TypePtr BuildType(const ShaderAst::VectorType& type) const; + TypePtr BuildType(const ShaderAst::UniformType& type) const; + UInt32 GetId(const Constant& c); UInt32 GetId(const Type& t); UInt32 GetId(const Variable& v); @@ -167,17 +185,13 @@ namespace Nz UInt32 Register(Type t); UInt32 Register(Variable v); + void SetStructCallback(StructCallback callback); + void Write(SpirvSection& annotations, SpirvSection& constants, SpirvSection& debugInfos); SpirvConstantCache& operator=(const SpirvConstantCache& cache) = delete; SpirvConstantCache& operator=(SpirvConstantCache&& cache) noexcept; - static ConstantPtr BuildConstant(const ShaderConstantValue& value); - static TypePtr BuildPointerType(const ShaderNodes::BasicType& type, SpirvStorageClass storageClass); - static TypePtr BuildPointerType(const ShaderAst& shader, const ShaderExpressionType& type, SpirvStorageClass storageClass); - static TypePtr BuildType(const ShaderNodes::BasicType& type); - static TypePtr BuildType(const ShaderAst& shader, const ShaderExpressionType& type); - private: struct DepRegisterer; struct Eq; diff --git a/include/Nazara/Shader/SpirvData.hpp b/include/Nazara/Shader/SpirvData.hpp index eccc122ad..aaacc4631 100644 --- a/include/Nazara/Shader/SpirvData.hpp +++ b/include/Nazara/Shader/SpirvData.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 Jérôme Leclercq +// Copyright (C) 2021 Jérôme Leclercq // This file is part of the "Nazara Engine - Shader generator" // For conditions of distribution and use, see copyright notice in Config.hpp" @@ -10,10 +10,17 @@ #define NAZARA_SPIRVDATA_HPP #include +#include #include namespace Nz { + constexpr UInt32 SpirvMagicNumber = 0x07230203; + constexpr UInt32 SpirvMajorVersion = 1; + constexpr UInt32 SpirvMinorVersion = 5; + constexpr UInt32 SpirvRevision = 4; + constexpr UInt32 SpirvVersion = (SpirvMajorVersion << 16) | (SpirvMinorVersion << 8); + enum class SpirvOp { OpNop = 0, @@ -367,7 +374,12 @@ namespace Nz OpSubgroupAnyKHR = 4429, OpSubgroupAllEqualKHR = 4430, OpSubgroupReadInvocationKHR = 4432, - OpTypeRayQueryProvisionalKHR = 4472, + OpTraceRayKHR = 4445, + OpExecuteCallableKHR = 4446, + OpConvertUToAccelerationStructureKHR = 4447, + OpIgnoreIntersectionKHR = 4448, + OpTerminateRayKHR = 4449, + OpTypeRayQueryKHR = 4472, OpRayQueryInitializeKHR = 4473, OpRayQueryTerminateKHR = 4474, OpRayQueryGenerateIntersectionKHR = 4475, @@ -391,15 +403,11 @@ namespace Nz OpReportIntersectionNV = 5334, OpReportIntersectionKHR = 5334, OpIgnoreIntersectionNV = 5335, - OpIgnoreIntersectionKHR = 5335, OpTerminateRayNV = 5336, - OpTerminateRayKHR = 5336, OpTraceNV = 5337, - OpTraceRayKHR = 5337, OpTypeAccelerationStructureNV = 5341, OpTypeAccelerationStructureKHR = 5341, OpExecuteCallableNV = 5344, - OpExecuteCallableKHR = 5344, OpTypeCooperativeMatrixNV = 5358, OpCooperativeMatrixLoadNV = 5359, OpCooperativeMatrixStoreNV = 5360, @@ -433,8 +441,15 @@ namespace Nz OpUSubSatINTEL = 5596, OpIMul32x16INTEL = 5597, OpUMul32x16INTEL = 5598, - OpFunctionPointerINTEL = 5600, + OpConstFunctionPointerINTEL = 5600, OpFunctionPointerCallINTEL = 5601, + OpAsmTargetINTEL = 5609, + OpAsmINTEL = 5610, + OpAsmCallINTEL = 5611, + OpAtomicFMinEXT = 5614, + OpAtomicFMaxEXT = 5615, + OpAssumeTrueKHR = 5630, + OpExpectKHR = 5631, OpDecorateString = 5632, OpDecorateStringGOOGLE = 5632, OpMemberDecorateString = 5633, @@ -557,7 +572,12 @@ namespace Nz OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL = 5814, OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL = 5815, OpSubgroupAvcSicGetInterRawSadsINTEL = 5816, + OpVariableLengthArrayINTEL = 5818, + OpSaveMemoryINTEL = 5819, + OpRestoreMemoryINTEL = 5820, OpLoopControlINTEL = 5887, + OpPtrCastToCrossWorkgroupINTEL = 5934, + OpCrossWorkgroupCastToPtrINTEL = 5938, OpReadPipeBlockingINTEL = 5946, OpWritePipeBlockingINTEL = 5947, OpFPGARegINTEL = 5949, @@ -579,6 +599,10 @@ namespace Nz OpRayQueryGetIntersectionObjectToWorldKHR = 6031, OpRayQueryGetIntersectionWorldToObjectKHR = 6032, OpAtomicFAddEXT = 6035, + OpTypeBufferSurfaceINTEL = 6086, + OpTypeStructContinuedINTEL = 6090, + OpConstantCompositeContinuedINTEL = 6091, + OpSpecConstantCompositeContinuedINTEL = 6092, }; enum class SpirvOperandKind @@ -592,6 +616,7 @@ namespace Nz MemoryAccess, KernelProfilingInfo, RayFlags, + FragmentShadingRate, SourceLanguage, ExecutionModel, AddressingModel, @@ -605,6 +630,8 @@ namespace Nz ImageChannelOrder, ImageChannelDataType, FPRoundingMode, + FPDenormMode, + FPOperationMode, LinkageType, AccessQualifier, FunctionParameterAttribute, @@ -632,6 +659,235 @@ namespace Nz PairIdRefIdRef, }; + enum class SpirvImageOperands + { + None = 0x0000, + Bias = 0x0001, + Lod = 0x0002, + Grad = 0x0004, + ConstOffset = 0x0008, + Offset = 0x0010, + ConstOffsets = 0x0020, + Sample = 0x0040, + MinLod = 0x0080, + MakeTexelAvailable = 0x0100, + MakeTexelAvailableKHR = 0x0100, + MakeTexelVisible = 0x0200, + MakeTexelVisibleKHR = 0x0200, + NonPrivateTexel = 0x0400, + NonPrivateTexelKHR = 0x0400, + VolatileTexel = 0x0800, + VolatileTexelKHR = 0x0800, + SignExtend = 0x1000, + ZeroExtend = 0x2000, + }; + + template<> + struct EnumAsFlags + { + static constexpr SpirvImageOperands max = SpirvImageOperands::ZeroExtend; + + static constexpr bool AutoFlag = false; + }; + + + enum class SpirvFPFastMathMode + { + None = 0x0000, + NotNaN = 0x0001, + NotInf = 0x0002, + NSZ = 0x0004, + AllowRecip = 0x0008, + Fast = 0x0010, + AllowContractFastINTEL = 0x10000, + AllowReassocINTEL = 0x20000, + }; + + template<> + struct EnumAsFlags + { + static constexpr SpirvFPFastMathMode max = SpirvFPFastMathMode::AllowReassocINTEL; + + static constexpr bool AutoFlag = false; + }; + + + enum class SpirvSelectionControl + { + None = 0x0000, + Flatten = 0x0001, + DontFlatten = 0x0002, + }; + + template<> + struct EnumAsFlags + { + static constexpr SpirvSelectionControl max = SpirvSelectionControl::DontFlatten; + + static constexpr bool AutoFlag = false; + }; + + + enum class SpirvLoopControl + { + None = 0x0000, + Unroll = 0x0001, + DontUnroll = 0x0002, + DependencyInfinite = 0x0004, + DependencyLength = 0x0008, + MinIterations = 0x0010, + MaxIterations = 0x0020, + IterationMultiple = 0x0040, + PeelCount = 0x0080, + PartialCount = 0x0100, + InitiationIntervalINTEL = 0x10000, + MaxConcurrencyINTEL = 0x20000, + DependencyArrayINTEL = 0x40000, + PipelineEnableINTEL = 0x80000, + LoopCoalesceINTEL = 0x100000, + MaxInterleavingINTEL = 0x200000, + SpeculatedIterationsINTEL = 0x400000, + NoFusionINTEL = 0x800000, + }; + + template<> + struct EnumAsFlags + { + static constexpr SpirvLoopControl max = SpirvLoopControl::NoFusionINTEL; + + static constexpr bool AutoFlag = false; + }; + + + enum class SpirvFunctionControl + { + None = 0x0000, + Inline = 0x0001, + DontInline = 0x0002, + Pure = 0x0004, + Const = 0x0008, + }; + + template<> + struct EnumAsFlags + { + static constexpr SpirvFunctionControl max = SpirvFunctionControl::Const; + + static constexpr bool AutoFlag = false; + }; + + + enum class SpirvMemorySemantics + { + Relaxed = 0x0000, + None = 0x0000, + Acquire = 0x0002, + Release = 0x0004, + AcquireRelease = 0x0008, + SequentiallyConsistent = 0x0010, + UniformMemory = 0x0040, + SubgroupMemory = 0x0080, + WorkgroupMemory = 0x0100, + CrossWorkgroupMemory = 0x0200, + AtomicCounterMemory = 0x0400, + ImageMemory = 0x0800, + OutputMemory = 0x1000, + OutputMemoryKHR = 0x1000, + MakeAvailable = 0x2000, + MakeAvailableKHR = 0x2000, + MakeVisible = 0x4000, + MakeVisibleKHR = 0x4000, + Volatile = 0x8000, + }; + + template<> + struct EnumAsFlags + { + static constexpr SpirvMemorySemantics max = SpirvMemorySemantics::Volatile; + + static constexpr bool AutoFlag = false; + }; + + + enum class SpirvMemoryAccess + { + None = 0x0000, + Volatile = 0x0001, + Aligned = 0x0002, + Nontemporal = 0x0004, + MakePointerAvailable = 0x0008, + MakePointerAvailableKHR = 0x0008, + MakePointerVisible = 0x0010, + MakePointerVisibleKHR = 0x0010, + NonPrivatePointer = 0x0020, + NonPrivatePointerKHR = 0x0020, + }; + + template<> + struct EnumAsFlags + { + static constexpr SpirvMemoryAccess max = SpirvMemoryAccess::NonPrivatePointerKHR; + + static constexpr bool AutoFlag = false; + }; + + + enum class SpirvKernelProfilingInfo + { + None = 0x0000, + CmdExecTime = 0x0001, + }; + + template<> + struct EnumAsFlags + { + static constexpr SpirvKernelProfilingInfo max = SpirvKernelProfilingInfo::CmdExecTime; + + static constexpr bool AutoFlag = false; + }; + + + enum class SpirvRayFlags + { + NoneKHR = 0x0000, + OpaqueKHR = 0x0001, + NoOpaqueKHR = 0x0002, + TerminateOnFirstHitKHR = 0x0004, + SkipClosestHitShaderKHR = 0x0008, + CullBackFacingTrianglesKHR = 0x0010, + CullFrontFacingTrianglesKHR = 0x0020, + CullOpaqueKHR = 0x0040, + CullNoOpaqueKHR = 0x0080, + SkipTrianglesKHR = 0x0100, + SkipAABBsKHR = 0x0200, + }; + + template<> + struct EnumAsFlags + { + static constexpr SpirvRayFlags max = SpirvRayFlags::SkipAABBsKHR; + + static constexpr bool AutoFlag = false; + }; + + + enum class SpirvFragmentShadingRate + { + Vertical2Pixels = 0x0001, + Vertical4Pixels = 0x0002, + Horizontal2Pixels = 0x0004, + Horizontal4Pixels = 0x0008, + }; + + template<> + struct EnumAsFlags + { + static constexpr SpirvFragmentShadingRate max = SpirvFragmentShadingRate::Horizontal4Pixels; + + static constexpr bool AutoFlag = false; + }; + + enum class SpirvSourceLanguage { Unknown = 0, @@ -743,10 +999,16 @@ namespace Nz SampleInterlockUnorderedEXT = 5369, ShadingRateInterlockOrderedEXT = 5370, ShadingRateInterlockUnorderedEXT = 5371, + SharedLocalMemorySizeINTEL = 5618, + RoundingModeRTPINTEL = 5620, + RoundingModeRTNINTEL = 5621, + FloatingPointModeALTINTEL = 5622, + FloatingPointModeIEEEINTEL = 5623, MaxWorkgroupSizeINTEL = 5893, MaxWorkDimINTEL = 5894, NoGlobalOffsetINTEL = 5895, NumSIMDWorkitemsINTEL = 5896, + SchedulerTargetFmaxMhzINTEL = 5903, }; enum class SpirvStorageClass @@ -779,6 +1041,8 @@ namespace Nz PhysicalStorageBuffer = 5349, PhysicalStorageBufferEXT = 5349, CodeSectionINTEL = 5605, + DeviceOnlyINTEL = 5936, + HostOnlyINTEL = 5937, }; enum class SpirvDim @@ -849,6 +1113,8 @@ namespace Nz Rg8ui = 37, R16ui = 38, R8ui = 39, + R64ui = 40, + R64i = 41, }; enum class SpirvImageChannelOrder @@ -904,10 +1170,23 @@ namespace Nz RTN = 3, }; + enum class SpirvFPDenormMode + { + Preserve = 0, + FlushToZero = 1, + }; + + enum class SpirvFPOperationMode + { + IEEE = 0, + ALT = 1, + }; + enum class SpirvLinkageType { Export = 0, Import = 1, + LinkOnceODR = 2, }; enum class SpirvAccessQualifier @@ -995,12 +1274,22 @@ namespace Nz RestrictPointerEXT = 5355, AliasedPointer = 5356, AliasedPointerEXT = 5356, + SIMTCallINTEL = 5599, ReferencedIndirectlyINTEL = 5602, + ClobberINTEL = 5607, + SideEffectsINTEL = 5608, + VectorComputeVariableINTEL = 5624, + FuncParamIOKindINTEL = 5625, + VectorComputeFunctionINTEL = 5626, + StackCallINTEL = 5627, + GlobalVariableOffsetINTEL = 5628, CounterBuffer = 5634, HlslCounterBufferGOOGLE = 5634, UserSemantic = 5635, HlslSemanticGOOGLE = 5635, UserTypeGOOGLE = 5636, + FunctionRoundingModeINTEL = 5822, + FunctionDenormModeINTEL = 5823, RegisterINTEL = 5825, MemoryINTEL = 5826, NumbanksINTEL = 5827, @@ -1013,6 +1302,17 @@ namespace Nz MergeINTEL = 5834, BankBitsINTEL = 5835, ForcePow2DepthINTEL = 5836, + BurstCoalesceINTEL = 5899, + CacheSizeINTEL = 5900, + DontStaticallyCoalesceINTEL = 5901, + PrefetchINTEL = 5902, + StallEnableINTEL = 5905, + FuseLoopsInFunctionINTEL = 5907, + BufferLocationINTEL = 5921, + IOPipeStorageINTEL = 5944, + FunctionFloatingPointModeINTEL = 6080, + SingleElementVectorINTEL = 6085, + VectorComputeCallableFunctionINTEL = 6087, }; enum class SpirvBuiltIn @@ -1059,20 +1359,22 @@ namespace Nz VertexIndex = 42, InstanceIndex = 43, SubgroupEqMask = 4416, - SubgroupGeMask = 4417, - SubgroupGtMask = 4418, - SubgroupLeMask = 4419, - SubgroupLtMask = 4420, SubgroupEqMaskKHR = 4416, + SubgroupGeMask = 4417, SubgroupGeMaskKHR = 4417, + SubgroupGtMask = 4418, SubgroupGtMaskKHR = 4418, + SubgroupLeMask = 4419, SubgroupLeMaskKHR = 4419, + SubgroupLtMask = 4420, SubgroupLtMaskKHR = 4420, BaseVertex = 4424, BaseInstance = 4425, DrawIndex = 4426, + PrimitiveShadingRateKHR = 4432, DeviceIndex = 4438, ViewIndex = 4440, + ShadingRateKHR = 4444, BaryCoordNoPerspAMD = 4992, BaryCoordNoPerspCentroidAMD = 4993, BaryCoordNoPerspSampleAMD = 4994, @@ -1124,7 +1426,6 @@ namespace Nz WorldToObjectNV = 5331, WorldToObjectKHR = 5331, HitTNV = 5332, - HitTKHR = 5332, HitKindNV = 5333, HitKindKHR = 5333, IncomingRayFlagsNV = 5351, @@ -1237,8 +1538,12 @@ namespace Nz GroupNonUniformQuad = 68, ShaderLayer = 69, ShaderViewportIndex = 70, + FragmentShadingRateKHR = 4422, SubgroupBallotKHR = 4423, DrawParameters = 4427, + WorkgroupMemoryExplicitLayoutKHR = 4428, + WorkgroupMemoryExplicitLayout8BitAccessKHR = 4429, + WorkgroupMemoryExplicitLayout16BitAccessKHR = 4430, SubgroupVoteKHR = 4431, StorageBuffer16BitAccess = 4433, StorageUniformBufferBlock16 = 4433, @@ -1261,12 +1566,15 @@ namespace Nz RoundingModeRTE = 4467, RoundingModeRTZ = 4468, RayQueryProvisionalKHR = 4471, - RayTraversalPrimitiveCullingProvisionalKHR = 4478, + RayQueryKHR = 4472, + RayTraversalPrimitiveCullingKHR = 4478, + RayTracingKHR = 4479, Float16ImageAMD = 5008, ImageGatherBiasLodAMD = 5009, FragmentMaskAMD = 5010, StencilExportEXT = 5013, ImageReadWriteLodAMD = 5015, + Int64ImageEXT = 5016, ShaderClockKHR = 5055, SampleMaskOverrideCoverageNV = 5249, GeometryShaderPassthroughNV = 5251, @@ -1326,21 +1634,41 @@ namespace Nz SubgroupBufferBlockIOINTEL = 5569, SubgroupImageBlockIOINTEL = 5570, SubgroupImageMediaBlockIOINTEL = 5579, + RoundToInfinityINTEL = 5582, + FloatingPointModeINTEL = 5583, IntegerFunctions2INTEL = 5584, FunctionPointersINTEL = 5603, IndirectReferencesINTEL = 5604, + AsmINTEL = 5606, + AtomicFloat32MinMaxEXT = 5612, + AtomicFloat64MinMaxEXT = 5613, + AtomicFloat16MinMaxEXT = 5616, + VectorComputeINTEL = 5617, + VectorAnyINTEL = 5619, + ExpectAssumeKHR = 5629, SubgroupAvcMotionEstimationINTEL = 5696, SubgroupAvcMotionEstimationIntraINTEL = 5697, SubgroupAvcMotionEstimationChromaINTEL = 5698, + VariableLengthArrayINTEL = 5817, + FunctionFloatControlINTEL = 5821, FPGAMemoryAttributesINTEL = 5824, + FPFastMathModeINTEL = 5837, + ArbitraryPrecisionIntegersINTEL = 5844, UnstructuredLoopControlsINTEL = 5886, FPGALoopControlsINTEL = 5888, KernelAttributesINTEL = 5892, FPGAKernelAttributesINTEL = 5897, + FPGAMemoryAccessesINTEL = 5898, + FPGAClusterAttributesINTEL = 5904, + LoopFuseINTEL = 5906, + FPGABufferLocationINTEL = 5920, + USMStorageClassesINTEL = 5935, + IOPipesINTEL = 5943, BlockingPipesINTEL = 5945, FPGARegINTEL = 5948, AtomicFloat32AddEXT = 6033, AtomicFloat64AddEXT = 6034, + LongConstantCompositeINTEL = 6089, }; enum class SpirvRayQueryIntersection @@ -1373,6 +1701,7 @@ namespace Nz SpirvOp op; const char* name; const Operand* operands; + const Operand* resultOperand; std::size_t minOperandCount; }; diff --git a/include/Nazara/Shader/SpirvDecoder.hpp b/include/Nazara/Shader/SpirvDecoder.hpp new file mode 100644 index 000000000..fc7ccd935 --- /dev/null +++ b/include/Nazara/Shader/SpirvDecoder.hpp @@ -0,0 +1,59 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SPIRVDECODER_HPP +#define NAZARA_SPIRVDECODER_HPP + +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_SHADER_API SpirvDecoder + { + public: + SpirvDecoder() = default; + SpirvDecoder(const SpirvDecoder&) = default; + SpirvDecoder(SpirvDecoder&&) = default; + ~SpirvDecoder() = default; + + void Decode(const UInt32* codepoints, std::size_t count); + + SpirvDecoder& operator=(const SpirvDecoder&) = default; + SpirvDecoder& operator=(SpirvDecoder&&) = default; + + protected: + struct SpirvHeader; + + inline const UInt32* GetCurrentPtr() const; + + virtual bool HandleHeader(const SpirvHeader& header); + virtual bool HandleOpcode(const SpirvInstruction& instruction, UInt32 wordCount) = 0; + + std::string ReadString(); + UInt32 ReadWord(); + + struct SpirvHeader + { + UInt32 generatorId; + UInt32 bound; + UInt32 schema; + UInt32 versionNumber; + }; + + private: + const UInt32* m_currentCodepoint; + const UInt32* m_codepointEnd; + }; +} + +#include + +#endif diff --git a/src/Nazara/Shader/ShaderVarVisitor.cpp b/include/Nazara/Shader/SpirvDecoder.inl similarity index 56% rename from src/Nazara/Shader/ShaderVarVisitor.cpp rename to include/Nazara/Shader/SpirvDecoder.inl index 108d5c69a..aa937bd5b 100644 --- a/src/Nazara/Shader/ShaderVarVisitor.cpp +++ b/include/Nazara/Shader/SpirvDecoder.inl @@ -2,15 +2,15 @@ // This file is part of the "Nazara Engine - Shader generator" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include namespace Nz { - ShaderVarVisitor::~ShaderVarVisitor() = default; - - void ShaderVarVisitor::Visit(const ShaderNodes::VariablePtr& node) + inline const UInt32* SpirvDecoder::GetCurrentPtr() const { - node->Visit(*this); + return m_currentCodepoint; } } + +#include diff --git a/include/Nazara/Shader/SpirvExpressionLoad.hpp b/include/Nazara/Shader/SpirvExpressionLoad.hpp index b237c720a..8ad84cb3d 100644 --- a/include/Nazara/Shader/SpirvExpressionLoad.hpp +++ b/include/Nazara/Shader/SpirvExpressionLoad.hpp @@ -4,38 +4,34 @@ #pragma once -#ifndef NAZARA_SPIRVEXPRESSIONLOADACCESSMEMBER_HPP -#define NAZARA_SPIRVEXPRESSIONLOADACCESSMEMBER_HPP +#ifndef NAZARA_SPIRVEXPRESSIONLOAD_HPP +#define NAZARA_SPIRVEXPRESSIONLOAD_HPP #include #include -#include -#include #include +#include #include namespace Nz { + class SpirvAstVisitor; + class SpirvBlock; class SpirvWriter; - class NAZARA_SHADER_API SpirvExpressionLoad : public ShaderAstVisitorExcept, public ShaderVarVisitorExcept + class NAZARA_SHADER_API SpirvExpressionLoad : public ShaderAst::ExpressionVisitorExcept { public: - inline SpirvExpressionLoad(SpirvWriter& writer); + inline SpirvExpressionLoad(SpirvWriter& writer, SpirvAstVisitor& visitor, SpirvBlock& block); SpirvExpressionLoad(const SpirvExpressionLoad&) = delete; SpirvExpressionLoad(SpirvExpressionLoad&&) = delete; ~SpirvExpressionLoad() = default; - UInt32 Evaluate(ShaderNodes::Expression& node); + UInt32 Evaluate(ShaderAst::Expression& node); - using ShaderAstVisitor::Visit; - void Visit(ShaderNodes::AccessMember& node) override; - void Visit(ShaderNodes::Identifier& node) override; - - using ShaderVarVisitor::Visit; - void Visit(ShaderNodes::InputVariable& var) override; - void Visit(ShaderNodes::LocalVariable& var) override; - void Visit(ShaderNodes::UniformVariable& var) override; + using ExpressionVisitorExcept::Visit; + void Visit(ShaderAst::AccessIndexExpression& node) override; + void Visit(ShaderAst::VariableExpression& node) override; SpirvExpressionLoad& operator=(const SpirvExpressionLoad&) = delete; SpirvExpressionLoad& operator=(SpirvExpressionLoad&&) = delete; @@ -44,7 +40,7 @@ namespace Nz struct Pointer { SpirvStorageClass storage; - UInt32 resultId; + UInt32 pointerId; UInt32 pointedTypeId; }; @@ -53,6 +49,8 @@ namespace Nz UInt32 resultId; }; + SpirvAstVisitor& m_visitor; + SpirvBlock& m_block; SpirvWriter& m_writer; std::variant m_value; }; diff --git a/include/Nazara/Shader/SpirvExpressionLoad.inl b/include/Nazara/Shader/SpirvExpressionLoad.inl index 966aae912..1522515b9 100644 --- a/include/Nazara/Shader/SpirvExpressionLoad.inl +++ b/include/Nazara/Shader/SpirvExpressionLoad.inl @@ -7,8 +7,10 @@ namespace Nz { - inline SpirvExpressionLoad::SpirvExpressionLoad(SpirvWriter& writer) : - m_writer(writer) + inline SpirvExpressionLoad::SpirvExpressionLoad(SpirvWriter& writer, SpirvAstVisitor& visitor, SpirvBlock& block) : + m_block(block), + m_writer(writer), + m_visitor(visitor) { } } diff --git a/include/Nazara/Shader/SpirvExpressionStore.hpp b/include/Nazara/Shader/SpirvExpressionStore.hpp index d7d37e39d..83c39e8e7 100644 --- a/include/Nazara/Shader/SpirvExpressionStore.hpp +++ b/include/Nazara/Shader/SpirvExpressionStore.hpp @@ -9,34 +9,29 @@ #include #include -#include -#include #include +#include namespace Nz { - class SpirvSection; + class SpirvAstVisitor; + class SpirvBlock; class SpirvWriter; - class NAZARA_SHADER_API SpirvExpressionStore : public ShaderAstVisitorExcept, public ShaderVarVisitorExcept + class NAZARA_SHADER_API SpirvExpressionStore : public ShaderAst::ExpressionVisitorExcept { public: - inline SpirvExpressionStore(SpirvWriter& writer); + inline SpirvExpressionStore(SpirvWriter& writer, SpirvAstVisitor& visitor, SpirvBlock& block); SpirvExpressionStore(const SpirvExpressionStore&) = delete; SpirvExpressionStore(SpirvExpressionStore&&) = delete; ~SpirvExpressionStore() = default; - void Store(const ShaderNodes::ExpressionPtr& node, UInt32 resultId); + void Store(ShaderAst::ExpressionPtr& node, UInt32 resultId); - using ShaderAstVisitorExcept::Visit; - void Visit(ShaderNodes::AccessMember& node) override; - void Visit(ShaderNodes::Identifier& node) override; - void Visit(ShaderNodes::SwizzleOp& node) override; - - using ShaderVarVisitorExcept::Visit; - void Visit(ShaderNodes::BuiltinVariable& var) override; - void Visit(ShaderNodes::LocalVariable& var) override; - void Visit(ShaderNodes::OutputVariable& var) override; + using ExpressionVisitorExcept::Visit; + void Visit(ShaderAst::AccessIndexExpression& node) override; + void Visit(ShaderAst::SwizzleExpression& node) override; + void Visit(ShaderAst::VariableExpression& node) override; SpirvExpressionStore& operator=(const SpirvExpressionStore&) = delete; SpirvExpressionStore& operator=(SpirvExpressionStore&&) = delete; @@ -50,9 +45,11 @@ namespace Nz struct Pointer { SpirvStorageClass storage; - UInt32 resultId; + UInt32 pointerId; }; + SpirvAstVisitor& m_visitor; + SpirvBlock& m_block; SpirvWriter& m_writer; std::variant m_value; }; diff --git a/include/Nazara/Shader/SpirvExpressionStore.inl b/include/Nazara/Shader/SpirvExpressionStore.inl index 558a2aee8..16326a438 100644 --- a/include/Nazara/Shader/SpirvExpressionStore.inl +++ b/include/Nazara/Shader/SpirvExpressionStore.inl @@ -7,8 +7,10 @@ namespace Nz { - inline SpirvExpressionStore::SpirvExpressionStore(SpirvWriter& writer) : - m_writer(writer) + inline SpirvExpressionStore::SpirvExpressionStore(SpirvWriter& writer, SpirvAstVisitor& visitor, SpirvBlock& block) : + m_block(block), + m_writer(writer), + m_visitor(visitor) { } } diff --git a/include/Nazara/Shader/SpirvPrinter.hpp b/include/Nazara/Shader/SpirvPrinter.hpp index fbfe0eeb2..014fce121 100644 --- a/include/Nazara/Shader/SpirvPrinter.hpp +++ b/include/Nazara/Shader/SpirvPrinter.hpp @@ -9,11 +9,13 @@ #include #include +#include #include +#include namespace Nz { - class NAZARA_SHADER_API SpirvPrinter + class NAZARA_SHADER_API SpirvPrinter : SpirvDecoder { public: struct Settings; @@ -23,7 +25,9 @@ namespace Nz SpirvPrinter(SpirvPrinter&&) = default; ~SpirvPrinter() = default; + inline std::string Print(const std::vector& codepoints); inline std::string Print(const UInt32* codepoints, std::size_t count); + inline std::string Print(const std::vector& codepoints, const Settings& settings); std::string Print(const UInt32* codepoints, std::size_t count, const Settings& settings); SpirvPrinter& operator=(const SpirvPrinter&) = default; @@ -36,9 +40,8 @@ namespace Nz }; private: - void AppendInstruction(); - std::string ReadString(); - UInt32 ReadWord(); + bool HandleHeader(const SpirvHeader& header) override; + bool HandleOpcode(const SpirvInstruction& instruction, UInt32 wordCount) override; struct State; diff --git a/include/Nazara/Shader/SpirvPrinter.inl b/include/Nazara/Shader/SpirvPrinter.inl index 1435293b0..866cc096f 100644 --- a/include/Nazara/Shader/SpirvPrinter.inl +++ b/include/Nazara/Shader/SpirvPrinter.inl @@ -12,11 +12,21 @@ namespace Nz { } + inline std::string SpirvPrinter::Print(const std::vector& codepoints) + { + return Print(codepoints.data(), codepoints.size()); + } + inline std::string SpirvPrinter::Print(const UInt32* codepoints, std::size_t count) { Settings settings; return Print(codepoints, count, settings); } + + inline std::string SpirvPrinter::Print(const std::vector& codepoints, const Settings& settings) + { + return Print(codepoints.data(), codepoints.size(), settings); + } } #include diff --git a/include/Nazara/Shader/SpirvSection.hpp b/include/Nazara/Shader/SpirvSection.hpp index b116b212f..498b4ec68 100644 --- a/include/Nazara/Shader/SpirvSection.hpp +++ b/include/Nazara/Shader/SpirvSection.hpp @@ -8,63 +8,25 @@ #define NAZARA_SPIRVSECTION_HPP #include -#include -#include -#include -#include +#include namespace Nz { - class NAZARA_SHADER_API SpirvSection + class NAZARA_SHADER_API SpirvSection : public SpirvSectionBase { public: - struct OpSize; - struct Raw; - SpirvSection() = default; - SpirvSection(const SpirvSection& cache) = default; - SpirvSection(SpirvSection&& cache) = default; + SpirvSection(const SpirvSection&) = default; + SpirvSection(SpirvSection&&) = default; ~SpirvSection() = default; - inline std::size_t Append(const char* str); - inline std::size_t Append(const std::string_view& str); - inline std::size_t Append(const std::string& str); - inline std::size_t Append(UInt32 value); - inline std::size_t Append(SpirvOp opcode, const OpSize& wordCount); - std::size_t Append(const Raw& raw); - inline std::size_t Append(std::initializer_list codepoints); - template std::size_t Append(SpirvOp opcode, const Args&... args); - template std::size_t AppendVariadic(SpirvOp opcode, F&& callback); - template std::size_t Append(T value); + using SpirvSectionBase::Append; + using SpirvSectionBase::AppendRaw; + using SpirvSectionBase::AppendSection; + using SpirvSectionBase::AppendVariadic; - inline unsigned int CountWord(const char* str); - inline unsigned int CountWord(const std::string_view& str); - inline unsigned int CountWord(const std::string& str); - inline unsigned int CountWord(const Raw& raw); - template unsigned int CountWord(const T& value); - template unsigned int CountWord(const T1& value, const T2& value2, const Args&... rest); - - inline const std::vector& GetBytecode() const; - inline std::size_t GetOutputOffset() const; - - SpirvSection& operator=(const SpirvSection& cache) = delete; - SpirvSection& operator=(SpirvSection&& cache) = default; - - struct OpSize - { - unsigned int wc; - }; - - struct Raw - { - const void* ptr; - std::size_t size; - }; - - static inline UInt32 BuildOpcode(SpirvOp opcode, unsigned int wordCount); - - private: - std::vector m_bytecode; + SpirvSection& operator=(const SpirvSection&) = delete; + SpirvSection& operator=(SpirvSection&&) = default; }; } diff --git a/include/Nazara/Shader/SpirvSection.inl b/include/Nazara/Shader/SpirvSection.inl index e86eb59ff..941659162 100644 --- a/include/Nazara/Shader/SpirvSection.inl +++ b/include/Nazara/Shader/SpirvSection.inl @@ -7,140 +7,6 @@ namespace Nz { - inline std::size_t SpirvSection::Append(const char* str) - { - return Append(std::string_view(str)); - } - - inline std::size_t SpirvSection::Append(const std::string_view& str) - { - std::size_t offset = GetOutputOffset(); - - std::size_t size4 = CountWord(str); - for (std::size_t i = 0; i < size4; ++i) - { - UInt32 codepoint = 0; - for (std::size_t j = 0; j < 4; ++j) - { - std::size_t pos = i * 4 + j; - if (pos < str.size()) - codepoint |= UInt32(str[pos]) << (j * 8); - } - - Append(codepoint); - } - - return offset; - } - - inline std::size_t SpirvSection::Append(const std::string& str) - { - return Append(std::string_view(str)); - } - - inline std::size_t SpirvSection::Append(UInt32 value) - { - std::size_t offset = GetOutputOffset(); - m_bytecode.push_back(value); - - return offset; - } - - inline std::size_t SpirvSection::Append(SpirvOp opcode, const OpSize& wordCount) - { - return Append(BuildOpcode(opcode, wordCount.wc)); - } - - inline std::size_t SpirvSection::Append(std::initializer_list codepoints) - { - std::size_t offset = GetOutputOffset(); - - for (UInt32 cp : codepoints) - Append(cp); - - return offset; - } - - template - std::size_t SpirvSection::Append(SpirvOp opcode, const Args&... args) - { - unsigned int wordCount = 1 + (CountWord(args) + ... + 0); - std::size_t offset = Append(opcode, OpSize{ wordCount }); - if constexpr (sizeof...(args) > 0) - (Append(args), ...); - - return offset; - } - - template std::size_t SpirvSection::AppendVariadic(SpirvOp opcode, F&& callback) - { - std::size_t offset = Append(0); //< Will be filled later - - unsigned int wordCount = 1; - auto appendFunctor = [&](const auto& value) - { - wordCount += CountWord(value); - Append(value); - }; - callback(appendFunctor); - - m_bytecode[offset] = BuildOpcode(opcode, wordCount); - - return offset; - } - - template - std::size_t SpirvSection::Append(T value) - { - return Append(static_cast(value)); - } - - template - unsigned int SpirvSection::CountWord(const T& /*value*/) - { - return 1; - } - - template - unsigned int SpirvSection::CountWord(const T1& value, const T2& value2, const Args&... rest) - { - return CountWord(value) + CountWord(value2) + (CountWord(rest) + ...); - } - - inline unsigned int SpirvSection::CountWord(const char* str) - { - return CountWord(std::string_view(str)); - } - - inline unsigned int Nz::SpirvSection::CountWord(const std::string& str) - { - return CountWord(std::string_view(str)); - } - - inline unsigned int SpirvSection::CountWord(const Raw& raw) - { - return static_cast((raw.size + sizeof(UInt32) - 1) / sizeof(UInt32)); - } - - inline unsigned int SpirvSection::CountWord(const std::string_view& str) - { - return (static_cast(str.size() + 1) + sizeof(UInt32) - 1) / sizeof(UInt32); //< + 1 for null character - } - - inline const std::vector& SpirvSection::GetBytecode() const - { - return m_bytecode; - } - - inline std::size_t SpirvSection::GetOutputOffset() const - { - return m_bytecode.size(); - } - - inline UInt32 SpirvSection::BuildOpcode(SpirvOp opcode, unsigned int wordCount) - { - return UInt32(opcode) | UInt32(wordCount) << 16; - } } #include diff --git a/include/Nazara/Shader/SpirvSectionBase.hpp b/include/Nazara/Shader/SpirvSectionBase.hpp new file mode 100644 index 000000000..8c16f773b --- /dev/null +++ b/include/Nazara/Shader/SpirvSectionBase.hpp @@ -0,0 +1,75 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SPIRVSECTIONBASE_HPP +#define NAZARA_SPIRVSECTIONBASE_HPP + +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_SHADER_API SpirvSectionBase + { + public: + struct OpSize; + struct Raw; + + SpirvSectionBase() = default; + SpirvSectionBase(const SpirvSectionBase&) = default; + SpirvSectionBase(SpirvSectionBase&&) = default; + ~SpirvSectionBase() = default; + + inline const std::vector& GetBytecode() const; + inline std::size_t GetOutputOffset() const; + + SpirvSectionBase& operator=(const SpirvSectionBase&) = delete; + SpirvSectionBase& operator=(SpirvSectionBase&&) = default; + + struct OpSize + { + unsigned int wc; + }; + + struct Raw + { + const void* ptr; + std::size_t size; + }; + + static inline UInt32 BuildOpcode(SpirvOp opcode, unsigned int wordCount); + + protected: + inline std::size_t Append(SpirvOp opcode, const OpSize& wordCount); + template std::size_t Append(SpirvOp opcode, const Args&... args); + template std::size_t AppendVariadic(SpirvOp opcode, F&& callback); + inline std::size_t AppendRaw(const char* str); + inline std::size_t AppendRaw(const std::string_view& str); + inline std::size_t AppendRaw(const std::string& str); + inline std::size_t AppendRaw(UInt32 value); + std::size_t AppendRaw(const Raw& raw); + inline std::size_t AppendRaw(std::initializer_list codepoints); + inline std::size_t AppendSection(const SpirvSectionBase& section); + template || std::is_enum_v>> std::size_t AppendRaw(T value); + + inline unsigned int CountWord(const char* str); + inline unsigned int CountWord(const std::string_view& str); + inline unsigned int CountWord(const std::string& str); + inline unsigned int CountWord(const Raw& raw); + template || std::is_enum_v>> unsigned int CountWord(const T& value); + template unsigned int CountWord(const T1& value, const T2& value2, const Args&... rest); + + private: + std::vector m_bytecode; + }; +} + +#include + +#endif diff --git a/include/Nazara/Shader/SpirvSectionBase.inl b/include/Nazara/Shader/SpirvSectionBase.inl new file mode 100644 index 000000000..760bfea6b --- /dev/null +++ b/include/Nazara/Shader/SpirvSectionBase.inl @@ -0,0 +1,157 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + inline std::size_t SpirvSectionBase::Append(SpirvOp opcode, const OpSize& wordCount) + { + return AppendRaw(BuildOpcode(opcode, wordCount.wc)); + } + + template + std::size_t SpirvSectionBase::Append(SpirvOp opcode, const Args&... args) + { + unsigned int wordCount = 1 + (CountWord(args) + ... + 0); + std::size_t offset = Append(opcode, OpSize{ wordCount }); + if constexpr (sizeof...(args) > 0) + (AppendRaw(args), ...); + + return offset; + } + + template std::size_t SpirvSectionBase::AppendVariadic(SpirvOp opcode, F&& callback) + { + std::size_t offset = AppendRaw(0); //< Will be filled later + + unsigned int wordCount = 1; + auto appendFunctor = [&](const auto& value) + { + wordCount += CountWord(value); + AppendRaw(value); + }; + callback(appendFunctor); + + m_bytecode[offset] = BuildOpcode(opcode, wordCount); + + return offset; + } + + inline std::size_t SpirvSectionBase::AppendRaw(const char* str) + { + return AppendRaw(std::string_view(str)); + } + + inline std::size_t SpirvSectionBase::AppendRaw(const std::string_view& str) + { + std::size_t offset = GetOutputOffset(); + + std::size_t size4 = CountWord(str); + for (std::size_t i = 0; i < size4; ++i) + { + UInt32 codepoint = 0; + for (std::size_t j = 0; j < 4; ++j) + { + std::size_t pos = i * 4 + j; + if (pos < str.size()) + codepoint |= UInt32(str[pos]) << (j * 8); + } + + AppendRaw(codepoint); + } + + return offset; + } + + inline std::size_t SpirvSectionBase::AppendRaw(const std::string& str) + { + return AppendRaw(std::string_view(str)); + } + + inline std::size_t SpirvSectionBase::AppendRaw(UInt32 value) + { + std::size_t offset = GetOutputOffset(); + m_bytecode.push_back(value); + + return offset; + } + + inline std::size_t SpirvSectionBase::AppendRaw(std::initializer_list codepoints) + { + std::size_t offset = GetOutputOffset(); + + for (UInt32 cp : codepoints) + AppendRaw(cp); + + return offset; + } + + inline std::size_t SpirvSectionBase::AppendSection(const SpirvSectionBase& section) + { + const std::vector& bytecode = section.GetBytecode(); + + std::size_t offset = GetOutputOffset(); + m_bytecode.resize(offset + bytecode.size()); + std::copy(bytecode.begin(), bytecode.end(), m_bytecode.begin() + offset); + + return offset; + } + + template + std::size_t SpirvSectionBase::AppendRaw(T value) + { + return AppendRaw(static_cast(value)); + } + + template + unsigned int SpirvSectionBase::CountWord(const T& /*value*/) + { + return 1; + } + + template + unsigned int SpirvSectionBase::CountWord(const T1& value, const T2& value2, const Args&... rest) + { + return CountWord(value) + CountWord(value2) + (CountWord(rest) + ...); + } + + inline unsigned int SpirvSectionBase::CountWord(const char* str) + { + return CountWord(std::string_view(str)); + } + + inline unsigned int Nz::SpirvSectionBase::CountWord(const std::string& str) + { + return CountWord(std::string_view(str)); + } + + inline unsigned int SpirvSectionBase::CountWord(const Raw& raw) + { + return static_cast((raw.size + sizeof(UInt32) - 1) / sizeof(UInt32)); + } + + inline unsigned int SpirvSectionBase::CountWord(const std::string_view& str) + { + return (static_cast(str.size() + 1) + sizeof(UInt32) - 1) / sizeof(UInt32); //< + 1 for null character + } + + inline const std::vector& SpirvSectionBase::GetBytecode() const + { + return m_bytecode; + } + + inline std::size_t SpirvSectionBase::GetOutputOffset() const + { + return m_bytecode.size(); + } + + inline UInt32 SpirvSectionBase::BuildOpcode(SpirvOp opcode, unsigned int wordCount) + { + return UInt32(opcode) | UInt32(wordCount) << 16; + } +} + +#include diff --git a/include/Nazara/Shader/SpirvWriter.hpp b/include/Nazara/Shader/SpirvWriter.hpp index 6b21de0ba..89f737afe 100644 --- a/include/Nazara/Shader/SpirvWriter.hpp +++ b/include/Nazara/Shader/SpirvWriter.hpp @@ -9,10 +9,8 @@ #include #include -#include -#include -#include -#include +#include +#include #include #include #include @@ -23,12 +21,12 @@ namespace Nz { class SpirvSection; - class NAZARA_SHADER_API SpirvWriter + class NAZARA_SHADER_API SpirvWriter : public ShaderWriter { friend class SpirvAstVisitor; + friend class SpirvBlock; friend class SpirvExpressionLoad; friend class SpirvExpressionStore; - friend class SpirvVisitor; public: struct Environment; @@ -38,7 +36,7 @@ namespace Nz SpirvWriter(SpirvWriter&&) = delete; ~SpirvWriter() = default; - std::vector Generate(const ShaderAst& shader); + std::vector Generate(ShaderAst::StatementPtr& shader, const States& states = {}); void SetEnv(Environment environment); @@ -49,53 +47,34 @@ namespace Nz }; private: - struct ExtVar; + struct FunctionParameter; struct OnlyCache {}; UInt32 AllocateResultId(); void AppendHeader(); - UInt32 GetConstantId(const ShaderConstantValue& value) const; - UInt32 GetFunctionTypeId(ShaderExpressionType retType, const std::vector& parameters); - const ExtVar& GetBuiltinVariable(ShaderNodes::BuiltinEntry builtin) const; - const ExtVar& GetInputVariable(const std::string& name) const; - const ExtVar& GetOutputVariable(const std::string& name) const; - const ExtVar& GetUniformVariable(const std::string& name) const; - SpirvSection& GetInstructions(); - UInt32 GetPointerTypeId(const ShaderExpressionType& type, SpirvStorageClass storageClass) const; - UInt32 GetTypeId(const ShaderExpressionType& type) const; + SpirvConstantCache::TypePtr BuildFunctionType(const ShaderAst::DeclareFunctionStatement& functionNode); - UInt32 ReadInputVariable(const std::string& name); - std::optional ReadInputVariable(const std::string& name, OnlyCache); - UInt32 ReadLocalVariable(const std::string& name); - std::optional ReadLocalVariable(const std::string& name, OnlyCache); - UInt32 ReadUniformVariable(const std::string& name); - std::optional ReadUniformVariable(const std::string& name, OnlyCache); - UInt32 ReadVariable(ExtVar& var); - std::optional ReadVariable(const ExtVar& var, OnlyCache); + UInt32 GetConstantId(const ShaderAst::ConstantValue& value) const; + UInt32 GetExtendedInstructionSet(const std::string& instructionSetName) const; + UInt32 GetExtVarPointerId(std::size_t varIndex) const; + UInt32 GetFunctionTypeId(const ShaderAst::DeclareFunctionStatement& functionNode); + UInt32 GetPointerTypeId(const ShaderAst::ExpressionType& type, SpirvStorageClass storageClass) const; + UInt32 GetTypeId(const ShaderAst::ExpressionType& type) const; - UInt32 RegisterConstant(const ShaderConstantValue& value); - UInt32 RegisterFunctionType(ShaderExpressionType retType, const std::vector& parameters); - UInt32 RegisterPointerType(ShaderExpressionType type, SpirvStorageClass storageClass); - UInt32 RegisterType(ShaderExpressionType type); + bool IsOptionEnabled(std::size_t optionIndex) const; - void WriteLocalVariable(std::string name, UInt32 resultId); + UInt32 RegisterConstant(const ShaderAst::ConstantValue& value); + UInt32 RegisterFunctionType(const ShaderAst::DeclareFunctionStatement& functionNode); + UInt32 RegisterPointerType(ShaderAst::ExpressionType type, SpirvStorageClass storageClass); + UInt32 RegisterType(ShaderAst::ExpressionType type); - static void MergeBlocks(std::vector& output, const SpirvSection& from); + static void MergeSections(std::vector& output, const SpirvSection& from); struct Context { - const ShaderAst* shader = nullptr; - const ShaderAst::Function* currentFunction = nullptr; - }; - - struct ExtVar - { - UInt32 pointerTypeId; - UInt32 typeId; - UInt32 varId; - std::optional valueId; + const States* states = nullptr; }; struct State; diff --git a/include/Nazara/Shader/SpirvWriter.inl b/include/Nazara/Shader/SpirvWriter.inl index 26012e0d1..0be50bead 100644 --- a/include/Nazara/Shader/SpirvWriter.inl +++ b/include/Nazara/Shader/SpirvWriter.inl @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include namespace Nz diff --git a/include/Nazara/Utility/AbstractImage.hpp b/include/Nazara/Utility/AbstractImage.hpp index 44ee7d4f8..f5e3f22ce 100644 --- a/include/Nazara/Utility/AbstractImage.hpp +++ b/include/Nazara/Utility/AbstractImage.hpp @@ -8,7 +8,6 @@ #define NAZARA_ABSTRACTIMAGE_HPP #include -#include #include #include #include @@ -19,14 +18,12 @@ namespace Nz { class AbstractImage; - using AbstractImageConstRef = ObjectRef; - using AbstractImageRef = ObjectRef; - - class NAZARA_UTILITY_API AbstractImage : public RefCounted + class NAZARA_UTILITY_API AbstractImage { public: AbstractImage() = default; - inline AbstractImage(const AbstractImage& image); + AbstractImage(const AbstractImage&) = default; + AbstractImage(AbstractImage&&) noexcept = default; virtual ~AbstractImage(); UInt8 GetBytesPerPixel() const; @@ -47,6 +44,9 @@ namespace Nz virtual bool Update(const UInt8* pixels, unsigned int srcWidth = 0, unsigned int srcHeight = 0, UInt8 level = 0) = 0; virtual bool Update(const UInt8* pixels, const Boxui& box, unsigned int srcWidth = 0, unsigned int srcHeight = 0, UInt8 level = 0) = 0; virtual bool Update(const UInt8* pixels, const Rectui& rect, unsigned int z = 0, unsigned int srcWidth = 0, unsigned int srcHeight = 0, UInt8 level = 0) = 0; + + AbstractImage& operator=(const AbstractImage&) = default; + AbstractImage& operator=(AbstractImage&&) noexcept = default; }; } diff --git a/include/Nazara/Utility/AbstractImage.inl b/include/Nazara/Utility/AbstractImage.inl index 772ba8418..219d06bbd 100644 --- a/include/Nazara/Utility/AbstractImage.inl +++ b/include/Nazara/Utility/AbstractImage.inl @@ -6,10 +6,6 @@ namespace Nz { - inline AbstractImage::AbstractImage(const AbstractImage&) : - RefCounted() - { - } } #include diff --git a/include/Nazara/Utility/AbstractTextDrawer.hpp b/include/Nazara/Utility/AbstractTextDrawer.hpp index a435ecc03..25e41d6c1 100644 --- a/include/Nazara/Utility/AbstractTextDrawer.hpp +++ b/include/Nazara/Utility/AbstractTextDrawer.hpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace Nz { @@ -30,7 +31,7 @@ namespace Nz virtual void Clear() = 0; virtual const Rectf& GetBounds() const = 0; - virtual Font* GetFont(std::size_t index) const = 0; + virtual const std::shared_ptr& GetFont(std::size_t index) const = 0; virtual std::size_t GetFontCount() const = 0; virtual const Glyph& GetGlyph(std::size_t index) const = 0; virtual std::size_t GetGlyphCount() const = 0; diff --git a/include/Nazara/Utility/Algorithm.inl b/include/Nazara/Utility/Algorithm.inl index e208d3021..d42ac41ae 100644 --- a/include/Nazara/Utility/Algorithm.inl +++ b/include/Nazara/Utility/Algorithm.inl @@ -14,20 +14,20 @@ namespace Nz return ComponentType{}; } - template<> constexpr ComponentType ComponentTypeId() { return ComponentType_Color; } - template<> constexpr ComponentType ComponentTypeId() { return ComponentType_Double1; } - template<> constexpr ComponentType ComponentTypeId() { return ComponentType_Double2; } - template<> constexpr ComponentType ComponentTypeId() { return ComponentType_Double3; } - template<> constexpr ComponentType ComponentTypeId() { return ComponentType_Double4; } - template<> constexpr ComponentType ComponentTypeId() { return ComponentType_Float1; } - template<> constexpr ComponentType ComponentTypeId() { return ComponentType_Float2; } - template<> constexpr ComponentType ComponentTypeId() { return ComponentType_Float3; } - template<> constexpr ComponentType ComponentTypeId() { return ComponentType_Float4; } - template<> constexpr ComponentType ComponentTypeId() { return ComponentType_Int1; } - template<> constexpr ComponentType ComponentTypeId() { return ComponentType_Int2; } - template<> constexpr ComponentType ComponentTypeId() { return ComponentType_Int3; } - template<> constexpr ComponentType ComponentTypeId() { return ComponentType_Int4; } - template<> constexpr ComponentType ComponentTypeId() { return ComponentType_Quaternion; } + template<> constexpr ComponentType ComponentTypeId() { return ComponentType::Color; } + template<> constexpr ComponentType ComponentTypeId() { return ComponentType::Double1; } + template<> constexpr ComponentType ComponentTypeId() { return ComponentType::Double2; } + template<> constexpr ComponentType ComponentTypeId() { return ComponentType::Double3; } + template<> constexpr ComponentType ComponentTypeId() { return ComponentType::Double4; } + template<> constexpr ComponentType ComponentTypeId() { return ComponentType::Float1; } + template<> constexpr ComponentType ComponentTypeId() { return ComponentType::Float2; } + template<> constexpr ComponentType ComponentTypeId() { return ComponentType::Float3; } + template<> constexpr ComponentType ComponentTypeId() { return ComponentType::Float4; } + template<> constexpr ComponentType ComponentTypeId() { return ComponentType::Int1; } + template<> constexpr ComponentType ComponentTypeId() { return ComponentType::Int2; } + template<> constexpr ComponentType ComponentTypeId() { return ComponentType::Int3; } + template<> constexpr ComponentType ComponentTypeId() { return ComponentType::Int4; } + template<> constexpr ComponentType ComponentTypeId() { return ComponentType::Quaternion; } template constexpr ComponentType GetComponentTypeOf() diff --git a/include/Nazara/Utility/Animation.hpp b/include/Nazara/Utility/Animation.hpp index 0bb90f548..4276bf3c0 100644 --- a/include/Nazara/Utility/Animation.hpp +++ b/include/Nazara/Utility/Animation.hpp @@ -10,8 +10,6 @@ #include #include #include -#include -#include #include #include #include @@ -38,23 +36,18 @@ namespace Nz struct SequenceJoint; class Skeleton; - using AnimationConstRef = ObjectRef; using AnimationLibrary = ObjectLibrary; using AnimationLoader = ResourceLoader; using AnimationManager = ResourceManager; - using AnimationRef = ObjectRef; struct AnimationImpl; - class NAZARA_UTILITY_API Animation : public RefCounted, public Resource + class NAZARA_UTILITY_API Animation : public Resource { - friend AnimationLibrary; - friend AnimationLoader; - friend AnimationManager; - friend class Utility; - public: - Animation() = default; + Animation(); + Animation(const Animation&) = delete; + Animation(Animation&&) noexcept; ~Animation(); bool AddSequence(const Sequence& sequence); @@ -86,26 +79,15 @@ namespace Nz void RemoveSequence(const std::string& sequenceName); void RemoveSequence(std::size_t index); - template static AnimationRef New(Args&&... args); + Animation& operator=(const Animation&) = delete; + Animation& operator=(Animation&&) noexcept; - static AnimationRef LoadFromFile(const std::filesystem::path& filePath, const AnimationParams& params = AnimationParams()); - static AnimationRef LoadFromMemory(const void* data, std::size_t size, const AnimationParams& params = AnimationParams()); - static AnimationRef LoadFromStream(Stream& stream, const AnimationParams& params = AnimationParams()); - - // Signals: - NazaraSignal(OnAnimationDestroy, const Animation* /*animation*/); - NazaraSignal(OnAnimationRelease, const Animation* /*animation*/); + static std::shared_ptr LoadFromFile(const std::filesystem::path& filePath, const AnimationParams& params = AnimationParams()); + static std::shared_ptr LoadFromMemory(const void* data, std::size_t size, const AnimationParams& params = AnimationParams()); + static std::shared_ptr LoadFromStream(Stream& stream, const AnimationParams& params = AnimationParams()); private: - static bool Initialize(); - static void Uninitialize(); - - MovablePtr m_impl = nullptr; - - static AnimationLibrary::LibraryMap s_library; - static AnimationLoader::LoaderList s_loaders; - static AnimationManager::ManagerMap s_managerMap; - static AnimationManager::ManagerParams s_managerParameters; + std::unique_ptr m_impl; }; } diff --git a/include/Nazara/Utility/Animation.inl b/include/Nazara/Utility/Animation.inl index 074080565..00631415c 100644 --- a/include/Nazara/Utility/Animation.inl +++ b/include/Nazara/Utility/Animation.inl @@ -2,19 +2,12 @@ // This file is part of the "Nazara Engine - Utility module" // For conditions of distribution and use, see copyright notice in Config.hpp +#include #include #include namespace Nz { - template - AnimationRef Animation::New(Args&&... args) - { - std::unique_ptr object(new Animation(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); - } } #include diff --git a/include/Nazara/Utility/Buffer.hpp b/include/Nazara/Utility/Buffer.hpp index 5cc4f173f..3be6680f7 100644 --- a/include/Nazara/Utility/Buffer.hpp +++ b/include/Nazara/Utility/Buffer.hpp @@ -8,37 +8,31 @@ #define NAZARA_BUFFER_HPP #include -#include -#include -#include #include #include #include #include +#include +#include namespace Nz { - class Buffer; - - using BufferConstRef = ObjectRef; - using BufferRef = ObjectRef; - - class NAZARA_UTILITY_API Buffer : public RefCounted + class NAZARA_UTILITY_API Buffer { friend class Utility; public: - using BufferFactory = AbstractBuffer* (*)(Buffer* parent, BufferType type); + using BufferFactory = std::function(Buffer* parent, BufferType type)>; Buffer(BufferType type); - Buffer(BufferType type, UInt32 size, DataStorage storage = DataStorage_Software, BufferUsageFlags usage = 0); + Buffer(BufferType type, UInt32 size, DataStorage storage = DataStorage::Software, BufferUsageFlags usage = 0); Buffer(const Buffer&) = delete; Buffer(Buffer&&) = delete; - ~Buffer(); + ~Buffer() = default; - bool CopyContent(const BufferRef& buffer); + bool CopyContent(const Buffer& buffer); - bool Create(UInt32 size, DataStorage storage = DataStorage_Software, BufferUsageFlags usage = 0); + bool Create(UInt32 size, DataStorage storage = DataStorage::Software, BufferUsageFlags usage = 0); void Destroy(); bool Fill(const void* data, UInt32 offset, UInt32 size); @@ -64,13 +58,8 @@ namespace Nz Buffer& operator=(Buffer&&) = delete; static bool IsStorageSupported(DataStorage storage); - template static BufferRef New(Args&&... args); static void SetBufferFactory(DataStorage storage, BufferFactory func); - // Signals: - NazaraSignal(OnBufferDestroy, const Buffer* /*buffer*/); - NazaraSignal(OnBufferRelease, const Buffer* /*buffer*/); - private: static bool Initialize(); static void Uninitialize(); @@ -80,7 +69,7 @@ namespace Nz BufferUsageFlags m_usage; UInt32 m_size; - static std::array s_bufferFactories; + static std::array s_bufferFactories; }; } diff --git a/include/Nazara/Utility/Buffer.inl b/include/Nazara/Utility/Buffer.inl index 4b02b35b7..262bea3d6 100644 --- a/include/Nazara/Utility/Buffer.inl +++ b/include/Nazara/Utility/Buffer.inl @@ -41,15 +41,6 @@ namespace Nz { return m_impl != nullptr; } - - template - BufferRef Buffer::New(Args&&... args) - { - std::unique_ptr object(new Buffer(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); - } } #include diff --git a/include/Nazara/Utility/Enums.hpp b/include/Nazara/Utility/Enums.hpp index ad0d11fe6..96bffcd50 100644 --- a/include/Nazara/Utility/Enums.hpp +++ b/include/Nazara/Utility/Enums.hpp @@ -11,303 +11,326 @@ namespace Nz { - enum AnimationType + enum class AnimationType { - AnimationType_Skeletal, - AnimationType_Static, + Skeletal, + Static, - AnimationType_Max = AnimationType_Static + Max = Static }; - enum BlendFunc + enum class BlendEquation { - BlendFunc_DestAlpha, - BlendFunc_DestColor, - BlendFunc_SrcAlpha, - BlendFunc_SrcColor, - BlendFunc_InvDestAlpha, - BlendFunc_InvDestColor, - BlendFunc_InvSrcAlpha, - BlendFunc_InvSrcColor, - BlendFunc_One, - BlendFunc_Zero, - - BlendFunc_Max = BlendFunc_Zero + Add, + Max, + Min, + ReverseSubtract, + Subtract, }; - enum BufferAccess + enum class BlendFunc { - BufferAccess_DiscardAndWrite, - BufferAccess_ReadOnly, - BufferAccess_ReadWrite, - BufferAccess_WriteOnly, - - BufferAccess_Max = BufferAccess_WriteOnly + ConstantColor, + ConstantAlpha, + DstAlpha, + DstColor, + SrcAlpha, + SrcColor, + InvConstantColor, + InvConstantAlpha, + InvDstAlpha, + InvDstColor, + InvSrcAlpha, + InvSrcColor, + One, + Zero }; - enum BufferType + enum class BufferAccess { - BufferType_Index, - BufferType_Vertex, - BufferType_Uniform, + DiscardAndWrite, + ReadOnly, + ReadWrite, + WriteOnly, - BufferType_Max = BufferType_Uniform + Max = WriteOnly }; - enum BufferUsage + enum class BufferType { - BufferUsage_DeviceLocal, - BufferUsage_DirectMapping, - BufferUsage_Dynamic, - BufferUsage_PersistentMapping, + Index, + Vertex, + Uniform, - BufferUsage_Max = BufferUsage_DirectMapping + Max = Uniform + }; + + enum class BufferUsage + { + DeviceLocal, + DirectMapping, + Dynamic, + PersistentMapping, + + Max = DirectMapping }; template<> struct EnumAsFlags { - static constexpr BufferUsage max = BufferUsage_Max; + static constexpr BufferUsage max = BufferUsage::Max; }; using BufferUsageFlags = Flags; - enum ComponentType + enum class ComponentType { - ComponentType_Color, - ComponentType_Double1, - ComponentType_Double2, - ComponentType_Double3, - ComponentType_Double4, - ComponentType_Float1, - ComponentType_Float2, - ComponentType_Float3, - ComponentType_Float4, - ComponentType_Int1, - ComponentType_Int2, - ComponentType_Int3, - ComponentType_Int4, - ComponentType_Quaternion, + Color, + Double1, + Double2, + Double3, + Double4, + Float1, + Float2, + Float3, + Float4, + Int1, + Int2, + Int3, + Int4, + Quaternion, - ComponentType_Max = ComponentType_Quaternion + Max = Quaternion }; - enum CubemapFace + constexpr std::size_t ComponentTypeCount = static_cast(ComponentType::Max) + 1; + + enum class CubemapFace { // This enumeration is intended to replace the "z" argument of Image's methods containing cubemap // The order is X, -X, Y, -Y, Z, -Z - CubemapFace_PositiveX = 0, - CubemapFace_PositiveY = 2, - CubemapFace_PositiveZ = 4, - CubemapFace_NegativeX = 1, - CubemapFace_NegativeY = 3, - CubemapFace_NegativeZ = 5, + PositiveX = 0, + PositiveY = 2, + PositiveZ = 4, + NegativeX = 1, + NegativeY = 3, + NegativeZ = 5, - CubemapFace_Max = CubemapFace_NegativeZ + Max = NegativeZ }; - enum DataStorage + enum class DataStorage { - DataStorage_Hardware, - DataStorage_Software, + Hardware, + Software, - DataStorage_Max = DataStorage_Software + Max = Software }; - enum FaceFilling - { - FaceFilling_Fill, - FaceFilling_Line, - FaceFilling_Point, + constexpr std::size_t DataStorageCount = static_cast(DataStorage::Max) + 1; - FaceFilling_Max = FaceFilling_Point + enum class FaceFilling + { + Fill, + Line, + Point, + + Max = Point }; - enum FaceSide + enum class FaceSide { - FaceSide_None, + None, - FaceSide_Back, - FaceSide_Front, - FaceSide_FrontAndBack, + Back, + Front, + FrontAndBack, - FaceSide_Max = FaceSide_FrontAndBack + Max = FrontAndBack }; - enum ImageType + enum class FrontFace { - ImageType_1D, - ImageType_1D_Array, - ImageType_2D, - ImageType_2D_Array, - ImageType_3D, - ImageType_Cubemap, + Clockwise, + CounterClockwise, - ImageType_Max = ImageType_Cubemap + Max = CounterClockwise }; - enum NodeType + enum class ImageType { - NodeType_Default, // Node - NodeType_Scene, // SceneNode (Graphics) - NodeType_Skeletal, ///TODO + E1D, + E1D_Array, + E2D, + E2D_Array, + E3D, + Cubemap, - NodeType_Max = NodeType_Skeletal + Max = Cubemap }; - enum PixelFormatContent + constexpr std::size_t ImageTypeCount = static_cast(ImageType::Max) + 1; + + enum class NodeType { - PixelFormatContent_Undefined = -1, + Default, // Node + Scene, // SceneNode (Graphics) + Skeletal, ///TODO - PixelFormatContent_ColorRGBA, - PixelFormatContent_DepthStencil, - PixelFormatContent_Stencil, - - PixelFormatContent_Max = PixelFormatContent_Stencil + Max = Skeletal }; - enum PixelFormat + enum class PixelFormatContent { - PixelFormat_Undefined = -1, + Undefined = -1, - PixelFormat_A8, // 1*uint8 - PixelFormat_BGR8, // 3*uint8 - PixelFormat_BGRA8, // 4*uint8 - PixelFormat_DXT1, - PixelFormat_DXT3, - PixelFormat_DXT5, - PixelFormat_L8, // 1*uint8 - PixelFormat_LA8, // 2*uint8 - PixelFormat_R8, // 1*uint8 - PixelFormat_R8I, // 1*int8 - PixelFormat_R8UI, // 1*uint8 - PixelFormat_R16, // 1*uint16 - PixelFormat_R16F, // 1*half - PixelFormat_R16I, // 1*int16 - PixelFormat_R16UI, // 1*uint16 - PixelFormat_R32F, // 1*float - PixelFormat_R32I, // 1*uint16 - PixelFormat_R32UI, // 1*uint32 - PixelFormat_RG8, // 2*int8 - PixelFormat_RG8I, // 2*int8 - PixelFormat_RG8UI, // 2*uint8 - PixelFormat_RG16, // 2*uint16 - PixelFormat_RG16F, // 2*half - PixelFormat_RG16I, // 2*int16 - PixelFormat_RG16UI, // 2*uint16 - PixelFormat_RG32F, // 2*float - PixelFormat_RG32I, // 2*uint16 - PixelFormat_RG32UI, // 2*uint32 - PixelFormat_RGB5A1, // 3*uint5 + alpha bit - PixelFormat_RGB8, // 3*uint8 - PixelFormat_RGB16F, // 3*half - PixelFormat_RGB16I, // 4*int16 - PixelFormat_RGB16UI, // 4*uint16 - PixelFormat_RGB32F, // 3*float - PixelFormat_RGB32I, // 4*int32 - PixelFormat_RGB32UI, // 4*uint32 - PixelFormat_RGBA4, // 4*uint4 - PixelFormat_RGBA8, // 4*uint8 - PixelFormat_RGBA16F, // 4*half - PixelFormat_RGBA16I, // 4*int16 - PixelFormat_RGBA16UI, // 4*uint16 - PixelFormat_RGBA32F, // 4*float - PixelFormat_RGBA32I, // 4*int32 - PixelFormat_RGBA32UI, // 4*uint32 - PixelFormat_Depth16, - PixelFormat_Depth24, - PixelFormat_Depth24Stencil8, - PixelFormat_Depth32, - PixelFormat_Stencil1, - PixelFormat_Stencil4, - PixelFormat_Stencil8, - PixelFormat_Stencil16, + ColorRGBA, + Depth, + DepthStencil, + Stencil, - PixelFormat_Max = PixelFormat_Stencil16 + Max = Stencil }; - enum PixelFormatSubType + enum class PixelFormat { - PixelFormatSubType_Compressed, // Opaque - PixelFormatSubType_Double, // F64 - PixelFormatSubType_Float, // F32 - PixelFormatSubType_Half, // F16 - PixelFormatSubType_Int, // Signed integer - PixelFormatSubType_Unsigned, // Unsigned integer + Undefined = -1, - PixelFormatSubType_Max = PixelFormatSubType_Unsigned + A8, // 1*uint8 + BGR8, // 3*uint8 + BGR8_SRGB, // 3*uint8 + BGRA8, // 4*uint8 + BGRA8_SRGB, // 4*uint8 + DXT1, + DXT3, + DXT5, + L8, // 1*uint8 + LA8, // 2*uint8 + R8, // 1*uint8 + R8I, // 1*int8 + R8UI, // 1*uint8 + R16, // 1*uint16 + R16F, // 1*half + R16I, // 1*int16 + R16UI, // 1*uint16 + R32F, // 1*float + R32I, // 1*uint16 + R32UI, // 1*uint32 + RG8, // 2*int8 + RG8I, // 2*int8 + RG8UI, // 2*uint8 + RG16, // 2*uint16 + RG16F, // 2*half + RG16I, // 2*int16 + RG16UI, // 2*uint16 + RG32F, // 2*float + RG32I, // 2*uint16 + RG32UI, // 2*uint32 + RGB5A1, // 3*uint5 + alpha bit + RGB8, // 3*uint8 + RGB8_SRGB, // 3*uint8 + RGB16F, // 3*half + RGB16I, // 4*int16 + RGB16UI, // 4*uint16 + RGB32F, // 3*float + RGB32I, // 4*int32 + RGB32UI, // 4*uint32 + RGBA4, // 4*uint4 + RGBA8, // 4*uint8 + RGBA8_SRGB, // 4*uint8 + RGBA16F, // 4*half + RGBA16I, // 4*int16 + RGBA16UI, // 4*uint16 + RGBA32F, // 4*float + RGBA32I, // 4*int32 + RGBA32UI, // 4*uint32 + Depth16, + Depth16Stencil8, + Depth24, + Depth24Stencil8, + Depth32F, + Depth32FStencil8, + Stencil1, + Stencil4, + Stencil8, + Stencil16, + + Max = Stencil16 }; - enum PixelFlipping - { - PixelFlipping_Horizontally, - PixelFlipping_Vertically, + constexpr std::size_t PixelFormatCount = static_cast(PixelFormat::Max) + 1; - PixelFlipping_Max = PixelFlipping_Vertically + enum class PixelFormatSubType + { + Compressed, // Opaque + Double, // F64 + Float, // F32 + Half, // F16 + Int, // Signed integer + Unsigned, // Unsigned integer + + Max = Unsigned }; - enum PrimitiveMode + enum class PixelFlipping { - PrimitiveMode_LineList, - PrimitiveMode_LineStrip, - PrimitiveMode_PointList, - PrimitiveMode_TriangleList, - PrimitiveMode_TriangleStrip, - PrimitiveMode_TriangleFan, + Horizontally, + Vertically, - PrimitiveMode_Max = PrimitiveMode_TriangleFan + Max = Vertically }; - enum RendererComparison - { - RendererComparison_Always, - RendererComparison_Equal, - RendererComparison_Greater, - RendererComparison_GreaterOrEqual, - RendererComparison_Less, - RendererComparison_LessOrEqual, - RendererComparison_Never, - RendererComparison_NotEqual, + constexpr std::size_t PixelFlippingCount = static_cast(PixelFlipping::Max) + 1; - RendererComparison_Max = RendererComparison_NotEqual + enum class PrimitiveMode + { + LineList, + LineStrip, + PointList, + TriangleList, + TriangleStrip, + TriangleFan, + + Max = TriangleFan }; - enum RendererParameter + enum class RendererComparison { - RendererParameter_Blend, - RendererParameter_ColorWrite, - RendererParameter_DepthBuffer, - RendererParameter_DepthWrite, - RendererParameter_FaceCulling, - RendererParameter_ScissorTest, - RendererParameter_StencilTest, + Always, + Equal, + Greater, + GreaterOrEqual, + Less, + LessOrEqual, + Never, + NotEqual, - RendererParameter_Max = RendererParameter_StencilTest + Max = NotEqual }; - enum SamplerFilter + enum class SamplerFilter { - SamplerFilter_Linear, - SamplerFilter_Nearest, + Linear, + Nearest, - SamplerFilter_Max = SamplerFilter_Nearest + Max = Nearest }; - enum SamplerMipmapMode + enum class SamplerMipmapMode { - SamplerMipmapMode_Linear, - SamplerMipmapMode_Nearest, + Linear, + Nearest, - SamplerMipmapMode_Max = SamplerMipmapMode_Nearest + Max = Nearest }; - enum SamplerWrap + enum class SamplerWrap { - SamplerWrap_Clamp, - SamplerWrap_MirroredRepeat, - SamplerWrap_Repeat, + Clamp, + MirroredRepeat, + Repeat, - SamplerWrap_Max = SamplerWrap_Repeat + Max = Repeat }; enum class ShaderStageType @@ -318,6 +341,8 @@ namespace Nz Max = Vertex }; + constexpr std::size_t ShaderStageTypeCount = static_cast(ShaderStageType::Max) + 1; + template<> struct EnumAsFlags { @@ -328,95 +353,95 @@ namespace Nz constexpr ShaderStageTypeFlags ShaderStageType_All = ShaderStageType::Fragment | ShaderStageType::Vertex; - enum StructFieldType + enum class StructFieldType { - StructFieldType_Bool1, - StructFieldType_Bool2, - StructFieldType_Bool3, - StructFieldType_Bool4, - StructFieldType_Float1, - StructFieldType_Float2, - StructFieldType_Float3, - StructFieldType_Float4, - StructFieldType_Double1, - StructFieldType_Double2, - StructFieldType_Double3, - StructFieldType_Double4, - StructFieldType_Int1, - StructFieldType_Int2, - StructFieldType_Int3, - StructFieldType_Int4, - StructFieldType_UInt1, - StructFieldType_UInt2, - StructFieldType_UInt3, - StructFieldType_UInt4, + Bool1, + Bool2, + Bool3, + Bool4, + Float1, + Float2, + Float3, + Float4, + Double1, + Double2, + Double3, + Double4, + Int1, + Int2, + Int3, + Int4, + UInt1, + UInt2, + UInt3, + UInt4, - StructFieldType_Max = StructFieldType_UInt4 + Max = UInt4 }; - enum StructLayout + enum class StructLayout { - StructLayout_Packed, - StructLayout_Std140, + Packed, + Std140, - StructLayout_Max = StructLayout_Std140 + Max = Std140 }; - enum StencilOperation + enum class StencilOperation { - StencilOperation_Decrement, - StencilOperation_DecrementNoClamp, - StencilOperation_Increment, - StencilOperation_IncrementNoClamp, - StencilOperation_Invert, - StencilOperation_Keep, - StencilOperation_Replace, - StencilOperation_Zero, + Decrement, + DecrementNoClamp, + Increment, + IncrementNoClamp, + Invert, + Keep, + Replace, + Zero, - StencilOperation_Max = StencilOperation_Zero + Max = Zero }; - enum TextAlign + enum class TextAlign { - TextAlign_Left, - TextAlign_Middle, - TextAlign_Right, + Left, + Middle, + Right, - TextAlign_Max = TextAlign_Right + Max = Right }; - enum TextStyle + enum class TextStyle { - TextStyle_Bold, - TextStyle_Italic, - TextStyle_StrikeThrough, - TextStyle_Underlined, + Bold, + Italic, + StrikeThrough, + Underlined, - TextStyle_Max = TextStyle_Underlined + Max = Underlined }; template<> struct EnumAsFlags { - static constexpr TextStyle max = TextStyle_Max; + static constexpr TextStyle max = TextStyle::Max; }; using TextStyleFlags = Flags; constexpr TextStyleFlags TextStyle_Regular = 0; - enum VertexComponent + enum class VertexComponent { - VertexComponent_Unused = -1, + Unused = -1, - VertexComponent_Color, - VertexComponent_Normal, - VertexComponent_Position, - VertexComponent_Tangent, - VertexComponent_TexCoord, - VertexComponent_Userdata, + Color, + Normal, + Position, + Tangent, + TexCoord, + Userdata, - VertexComponent_Max = VertexComponent_Userdata + Max = Userdata }; enum class VertexInputRate @@ -425,26 +450,28 @@ namespace Nz Vertex }; - enum VertexLayout + enum class VertexLayout { // Predefined declarations for rendering - VertexLayout_XY, - VertexLayout_XY_Color, - VertexLayout_XY_UV, - VertexLayout_XYZ, - VertexLayout_XYZ_Color, - VertexLayout_XYZ_Color_UV, - VertexLayout_XYZ_Normal, - VertexLayout_XYZ_Normal_UV, - VertexLayout_XYZ_Normal_UV_Tangent, - VertexLayout_XYZ_Normal_UV_Tangent_Skinning, - VertexLayout_XYZ_UV, + XY, + XY_Color, + XY_UV, + XYZ, + XYZ_Color, + XYZ_Color_UV, + XYZ_Normal, + XYZ_Normal_UV, + XYZ_Normal_UV_Tangent, + XYZ_Normal_UV_Tangent_Skinning, + XYZ_UV, // Predefined declarations for instancing - VertexLayout_Matrix4, + Matrix4, - VertexLayout_Max = VertexLayout_Matrix4 + Max = Matrix4 }; + + constexpr std::size_t VertexLayoutCount = static_cast(VertexLayout::Max) + 1; } #endif // NAZARA_ENUMS_UTILITY_HPP diff --git a/include/Nazara/Utility/FieldOffsets.hpp b/include/Nazara/Utility/FieldOffsets.hpp index 266f82cd7..da721e671 100644 --- a/include/Nazara/Utility/FieldOffsets.hpp +++ b/include/Nazara/Utility/FieldOffsets.hpp @@ -27,6 +27,7 @@ namespace Nz std::size_t AddStruct(const FieldOffsets& fieldStruct); std::size_t AddStructArray(const FieldOffsets& fieldStruct, std::size_t arraySize); + inline std::size_t GetAlignedSize() const; inline std::size_t GetLargestFieldAlignement() const; inline std::size_t GetSize() const; @@ -38,8 +39,6 @@ namespace Nz static std::size_t GetSize(StructFieldType fieldType); private: - static inline std::size_t Align(std::size_t source, std::size_t alignment); - std::size_t m_largestFieldAlignment; std::size_t m_offsetRounding; std::size_t m_size; diff --git a/include/Nazara/Utility/FieldOffsets.inl b/include/Nazara/Utility/FieldOffsets.inl index 5ca15e88f..655cb774a 100644 --- a/include/Nazara/Utility/FieldOffsets.inl +++ b/include/Nazara/Utility/FieldOffsets.inl @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include #include @@ -22,6 +23,14 @@ namespace Nz return m_largestFieldAlignment; } + inline std::size_t FieldOffsets::GetAlignedSize() const + { + if (m_layout == StructLayout::Std140) + return Align(m_size, m_largestFieldAlignment); + else + return m_size; + } + inline std::size_t FieldOffsets::GetSize() const { return m_size; @@ -31,43 +40,43 @@ namespace Nz { switch (layout) { - case StructLayout_Packed: + case StructLayout::Packed: return 1; - case StructLayout_Std140: + case StructLayout::Std140: { switch (fieldType) { - case StructFieldType_Bool1: - case StructFieldType_Float1: - case StructFieldType_Int1: - case StructFieldType_UInt1: + case StructFieldType::Bool1: + case StructFieldType::Float1: + case StructFieldType::Int1: + case StructFieldType::UInt1: return 4; - case StructFieldType_Bool2: - case StructFieldType_Float2: - case StructFieldType_Int2: - case StructFieldType_UInt2: + case StructFieldType::Bool2: + case StructFieldType::Float2: + case StructFieldType::Int2: + case StructFieldType::UInt2: return 2 * 4; - case StructFieldType_Bool3: - case StructFieldType_Float3: - case StructFieldType_Int3: - case StructFieldType_UInt3: - case StructFieldType_Bool4: - case StructFieldType_Float4: - case StructFieldType_Int4: - case StructFieldType_UInt4: + case StructFieldType::Bool3: + case StructFieldType::Float3: + case StructFieldType::Int3: + case StructFieldType::UInt3: + case StructFieldType::Bool4: + case StructFieldType::Float4: + case StructFieldType::Int4: + case StructFieldType::UInt4: return 4 * 4; - case StructFieldType_Double1: + case StructFieldType::Double1: return 8; - case StructFieldType_Double2: + case StructFieldType::Double2: return 2 * 8; - case StructFieldType_Double3: - case StructFieldType_Double4: + case StructFieldType::Double3: + case StructFieldType::Double4: return 4 * 8; } } @@ -80,32 +89,32 @@ namespace Nz { switch (fieldType) { - case StructFieldType_Bool1: - case StructFieldType_Double1: - case StructFieldType_Float1: - case StructFieldType_Int1: - case StructFieldType_UInt1: + case StructFieldType::Bool1: + case StructFieldType::Double1: + case StructFieldType::Float1: + case StructFieldType::Int1: + case StructFieldType::UInt1: return 1; - case StructFieldType_Bool2: - case StructFieldType_Double2: - case StructFieldType_Float2: - case StructFieldType_Int2: - case StructFieldType_UInt2: + case StructFieldType::Bool2: + case StructFieldType::Double2: + case StructFieldType::Float2: + case StructFieldType::Int2: + case StructFieldType::UInt2: return 2; - case StructFieldType_Bool3: - case StructFieldType_Double3: - case StructFieldType_Float3: - case StructFieldType_Int3: - case StructFieldType_UInt3: + case StructFieldType::Bool3: + case StructFieldType::Double3: + case StructFieldType::Float3: + case StructFieldType::Int3: + case StructFieldType::UInt3: return 3; - case StructFieldType_Bool4: - case StructFieldType_Double4: - case StructFieldType_Float4: - case StructFieldType_Int4: - case StructFieldType_UInt4: + case StructFieldType::Bool4: + case StructFieldType::Double4: + case StructFieldType::Float4: + case StructFieldType::Int4: + case StructFieldType::UInt4: return 4; } @@ -116,54 +125,45 @@ namespace Nz { switch (fieldType) { - case StructFieldType_Bool1: - case StructFieldType_Float1: - case StructFieldType_Int1: - case StructFieldType_UInt1: + case StructFieldType::Bool1: + case StructFieldType::Float1: + case StructFieldType::Int1: + case StructFieldType::UInt1: return 4; - case StructFieldType_Bool2: - case StructFieldType_Float2: - case StructFieldType_Int2: - case StructFieldType_UInt2: + case StructFieldType::Bool2: + case StructFieldType::Float2: + case StructFieldType::Int2: + case StructFieldType::UInt2: return 2 * 4; - case StructFieldType_Bool3: - case StructFieldType_Float3: - case StructFieldType_Int3: - case StructFieldType_UInt3: + case StructFieldType::Bool3: + case StructFieldType::Float3: + case StructFieldType::Int3: + case StructFieldType::UInt3: return 3 * 4; - case StructFieldType_Bool4: - case StructFieldType_Float4: - case StructFieldType_Int4: - case StructFieldType_UInt4: + case StructFieldType::Bool4: + case StructFieldType::Float4: + case StructFieldType::Int4: + case StructFieldType::UInt4: return 4 * 4; - case StructFieldType_Double1: + case StructFieldType::Double1: return 8; - case StructFieldType_Double2: + case StructFieldType::Double2: return 2 * 8; - case StructFieldType_Double3: + case StructFieldType::Double3: return 3 * 8; - case StructFieldType_Double4: + case StructFieldType::Double4: return 4 * 8; } return 0; } - - inline std::size_t FieldOffsets::Align(std::size_t source, std::size_t alignment) - { - if (source == 0) - return source; - - assert(alignment > 0); - return ((source + alignment - 1) / alignment) * alignment; - } } #include diff --git a/include/Nazara/Utility/Font.hpp b/include/Nazara/Utility/Font.hpp index 534afb016..636a7a456 100644 --- a/include/Nazara/Utility/Font.hpp +++ b/include/Nazara/Utility/Font.hpp @@ -11,7 +11,6 @@ #include #include -#include #include #include #include @@ -32,12 +31,10 @@ namespace Nz struct FontGlyph; - using FontConstRef = ObjectRef; using FontLibrary = ObjectLibrary; using FontLoader = ResourceLoader; - using FontRef = ObjectRef; - class NAZARA_UTILITY_API Font : public RefCounted, public Resource + class NAZARA_UTILITY_API Font : public Resource { friend FontLibrary; friend FontLoader; @@ -85,15 +82,13 @@ namespace Nz Font& operator=(Font&&) = delete; static std::shared_ptr GetDefaultAtlas(); - static const FontRef& GetDefault(); + static const std::shared_ptr& GetDefault(); static unsigned int GetDefaultGlyphBorder(); static unsigned int GetDefaultMinimumStepSize(); - static FontRef OpenFromFile(const std::filesystem::path& filePath, const FontParams& params = FontParams()); - static FontRef OpenFromMemory(const void* data, std::size_t size, const FontParams& params = FontParams()); - static FontRef OpenFromStream(Stream& stream, const FontParams& params = FontParams()); - - template static FontRef New(Args&&... args); + static std::shared_ptr OpenFromFile(const std::filesystem::path& filePath, const FontParams& params = FontParams()); + static std::shared_ptr OpenFromMemory(const void* data, std::size_t size, const FontParams& params = FontParams()); + static std::shared_ptr OpenFromStream(Stream& stream, const FontParams& params = FontParams()); static void SetDefaultAtlas(const std::shared_ptr& atlas); static void SetDefaultGlyphBorder(unsigned int borderSize); @@ -154,9 +149,7 @@ namespace Nz unsigned int m_minimumStepSize; static std::shared_ptr s_defaultAtlas; - static FontRef s_defaultFont; - static FontLibrary::LibraryMap s_library; - static FontLoader::LoaderList s_loaders; + static std::shared_ptr s_defaultFont; static unsigned int s_defaultGlyphBorder; static unsigned int s_defaultMinimumStepSize; }; diff --git a/include/Nazara/Utility/Font.inl b/include/Nazara/Utility/Font.inl index eaa4fb9bb..f82e86d7c 100644 --- a/include/Nazara/Utility/Font.inl +++ b/include/Nazara/Utility/Font.inl @@ -2,19 +2,12 @@ // This file is part of the "Nazara Engine - Utility module" // For conditions of distribution and use, see copyright notice in Config.hpp +#include #include #include namespace Nz { - template - FontRef Font::New(Args&&... args) - { - std::unique_ptr object(new Font(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); - } } #include diff --git a/include/Nazara/Utility/Image.hpp b/include/Nazara/Utility/Image.hpp index 6355dc60f..cfde858ae 100644 --- a/include/Nazara/Utility/Image.hpp +++ b/include/Nazara/Utility/Image.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -27,7 +28,7 @@ namespace Nz struct NAZARA_UTILITY_API ImageParams : ResourceParameters { // Le format dans lequel l'image doit être chargée (Undefined pour le format le plus proche de l'original) - PixelFormat loadFormat = PixelFormat_Undefined; + PixelFormat loadFormat = PixelFormat::Undefined; // Le nombre de niveaux de mipmaps maximum devant être créé UInt8 levelCount = 0; @@ -37,33 +38,26 @@ namespace Nz class Image; - using ImageConstRef = ObjectRef; using ImageLibrary = ObjectLibrary; using ImageLoader = ResourceLoader; using ImageManager = ResourceManager; - using ImageRef = ObjectRef; using ImageSaver = ResourceSaver; class NAZARA_UTILITY_API Image : public AbstractImage, public Resource { - friend ImageLibrary; - friend ImageLoader; - friend ImageManager; - friend ImageSaver; - friend class Utility; - public: struct SharedImage; Image(); Image(ImageType type, PixelFormat format, unsigned int width, unsigned int height, unsigned int depth = 1, UInt8 levelCount = 1); - Image(const Image& image); Image(SharedImage* sharedImage); + Image(const Image& image); + inline Image(Image&& image) noexcept; ~Image(); bool Convert(PixelFormat format); - void Copy(const Image* source, const Boxui& srcBox, const Vector3ui& dstPos); + void Copy(const Image& source, const Boxui& srcBox, const Vector3ui& dstPos); bool Create(ImageType type, PixelFormat format, unsigned int width, unsigned int height, unsigned int depth = 1, UInt8 levelCount = 1); void Destroy(); @@ -112,29 +106,28 @@ namespace Nz bool Update(const UInt8* pixels, const Rectui& rect, unsigned int z = 0, unsigned int srcWidth = 0, unsigned int srcHeight = 0, UInt8 level = 0) override; Image& operator=(const Image& image); + inline Image& operator=(Image&& image) noexcept; static void Copy(UInt8* destination, const UInt8* source, PixelFormat format, unsigned int width, unsigned int height, unsigned int depth = 1, unsigned int dstWidth = 0, unsigned int dstHeight = 0, unsigned int srcWidth = 0, unsigned int srcHeight = 0); static UInt8 GetMaxLevel(unsigned int width, unsigned int height, unsigned int depth = 1); static UInt8 GetMaxLevel(ImageType type, unsigned int width, unsigned int height, unsigned int depth = 1); // Load - static ImageRef LoadFromFile(const std::filesystem::path& filePath, const ImageParams& params = ImageParams()); - static ImageRef LoadFromMemory(const void* data, std::size_t size, const ImageParams& params = ImageParams()); - static ImageRef LoadFromStream(Stream& stream, const ImageParams& params = ImageParams()); + static std::shared_ptr LoadFromFile(const std::filesystem::path& filePath, const ImageParams& params = ImageParams()); + static std::shared_ptr LoadFromMemory(const void* data, std::size_t size, const ImageParams& params = ImageParams()); + static std::shared_ptr LoadFromStream(Stream& stream, const ImageParams& params = ImageParams()); // LoadArray - static ImageRef LoadArrayFromFile(const std::filesystem::path& filePath, const ImageParams& imageParams = ImageParams(), const Vector2ui& atlasSize = Vector2ui(2, 2)); - static ImageRef LoadArrayFromImage(const Image* image, const Vector2ui& atlasSize = Vector2ui(2, 2)); - static ImageRef LoadArrayFromMemory(const void* data, std::size_t size, const ImageParams& imageParams = ImageParams(), const Vector2ui& atlasSize = Vector2ui(2, 2)); - static ImageRef LoadArrayFromStream(Stream& stream, const ImageParams& imageParams = ImageParams(), const Vector2ui& atlasSize = Vector2ui(2, 2)); + static std::shared_ptr LoadArrayFromFile(const std::filesystem::path& filePath, const ImageParams& imageParams = ImageParams(), const Vector2ui& atlasSize = Vector2ui(2, 2)); + static std::shared_ptr LoadArrayFromImage(const Image& image, const Vector2ui& atlasSize = Vector2ui(2, 2)); + static std::shared_ptr LoadArrayFromMemory(const void* data, std::size_t size, const ImageParams& imageParams = ImageParams(), const Vector2ui& atlasSize = Vector2ui(2, 2)); + static std::shared_ptr LoadArrayFromStream(Stream& stream, const ImageParams& imageParams = ImageParams(), const Vector2ui& atlasSize = Vector2ui(2, 2)); // LoadCubemap - static ImageRef LoadCubemapFromFile(const std::filesystem::path& filePath, const ImageParams& imageParams = ImageParams(), const CubemapParams& cubemapParams = CubemapParams()); - static ImageRef LoadCubemapFromImage(const Image* image, const CubemapParams& params = CubemapParams()); - static ImageRef LoadCubemapFromMemory(const void* data, std::size_t size, const ImageParams& imageParams = ImageParams(), const CubemapParams& cubemapParams = CubemapParams()); - static ImageRef LoadCubemapFromStream(Stream& stream, const ImageParams& imageParams = ImageParams(), const CubemapParams& cubemapParams = CubemapParams()); - - template static ImageRef New(Args&&... args); + static std::shared_ptr LoadCubemapFromFile(const std::filesystem::path& filePath, const ImageParams& imageParams = ImageParams(), const CubemapParams& cubemapParams = CubemapParams()); + static std::shared_ptr LoadCubemapFromImage(const Image& image, const CubemapParams& params = CubemapParams()); + static std::shared_ptr LoadCubemapFromMemory(const void* data, std::size_t size, const ImageParams& imageParams = ImageParams(), const CubemapParams& cubemapParams = CubemapParams()); + static std::shared_ptr LoadCubemapFromStream(Stream& stream, const ImageParams& imageParams = ImageParams(), const CubemapParams& cubemapParams = CubemapParams()); struct SharedImage { @@ -163,24 +156,11 @@ namespace Nz static SharedImage emptyImage; - // Signals: - NazaraSignal(OnImageDestroy, const Image* /*image*/); - NazaraSignal(OnImageRelease, const Image* /*image*/); - private: void EnsureOwnership(); void ReleaseImage(); - static bool Initialize(); - static void Uninitialize(); - SharedImage* m_sharedImage; - - static ImageLibrary::LibraryMap s_library; - static ImageLoader::LoaderList s_loaders; - static ImageManager::ManagerMap s_managerMap; - static ImageManager::ManagerParams s_managerParameters; - static ImageSaver::SaverList s_savers; }; } diff --git a/include/Nazara/Utility/Image.inl b/include/Nazara/Utility/Image.inl index 4fd41adf1..058e2180f 100644 --- a/include/Nazara/Utility/Image.inl +++ b/include/Nazara/Utility/Image.inl @@ -2,18 +2,22 @@ // This file is part of the "Nazara Engine - Utility module" // For conditions of distribution and use, see copyright notice in Config.hpp +#include #include #include namespace Nz { - template - ImageRef Image::New(Args&&... args) + inline Image::Image(Image&& image) noexcept : + m_sharedImage(std::exchange(image.m_sharedImage, &emptyImage)) { - std::unique_ptr object(new Image(std::forward(args)...)); - object->SetPersistent(false); + } - return object.release(); + inline Image& Image::operator=(Image&& image) noexcept + { + std::swap(m_sharedImage, image.m_sharedImage); + + return *this; } } diff --git a/include/Nazara/Utility/IndexBuffer.hpp b/include/Nazara/Utility/IndexBuffer.hpp index 3a908788d..10f46f324 100644 --- a/include/Nazara/Utility/IndexBuffer.hpp +++ b/include/Nazara/Utility/IndexBuffer.hpp @@ -8,34 +8,27 @@ #define NAZARA_INDEXBUFFER_HPP #include -#include -#include #include namespace Nz { - class IndexBuffer; - - using IndexBufferConstRef = ObjectRef; - using IndexBufferRef = ObjectRef; - - class NAZARA_UTILITY_API IndexBuffer : public RefCounted + class NAZARA_UTILITY_API IndexBuffer { public: IndexBuffer() = default; - IndexBuffer(bool largeIndices, BufferRef buffer); - IndexBuffer(bool largeIndices, BufferRef buffer, std::size_t offset, std::size_t size); + IndexBuffer(bool largeIndices, std::shared_ptr buffer); + IndexBuffer(bool largeIndices, std::shared_ptr buffer, std::size_t offset, std::size_t size); IndexBuffer(bool largeIndices, std::size_t length, DataStorage storage, BufferUsageFlags usage); - IndexBuffer(const IndexBuffer& indexBuffer); - IndexBuffer(IndexBuffer&&) = delete; - ~IndexBuffer(); + IndexBuffer(const IndexBuffer&) = default; + IndexBuffer(IndexBuffer&&) noexcept = default; + ~IndexBuffer() = default; unsigned int ComputeCacheMissCount() const; bool Fill(const void* data, std::size_t startIndex, std::size_t length); bool FillRaw(const void* data, std::size_t offset, std::size_t size); - inline const BufferRef& GetBuffer() const; + inline const std::shared_ptr& GetBuffer() const; inline std::size_t GetEndOffset() const; inline std::size_t GetIndexCount() const; inline std::size_t GetStride() const; @@ -53,23 +46,18 @@ namespace Nz void Optimize(); void Reset(); - void Reset(bool largeIndices, BufferRef buffer); - void Reset(bool largeIndices, BufferRef buffer, std::size_t offset, std::size_t size); + void Reset(bool largeIndices, std::shared_ptr buffer); + void Reset(bool largeIndices, std::shared_ptr buffer, std::size_t offset, std::size_t size); void Reset(bool largeIndices, std::size_t length, DataStorage storage, BufferUsageFlags usage); void Reset(const IndexBuffer& indexBuffer); void Unmap() const; - IndexBuffer& operator=(const IndexBuffer& indexBuffer); - IndexBuffer& operator=(IndexBuffer&&) = delete; - - template static IndexBufferRef New(Args&&... args); - - // Signals: - NazaraSignal(OnIndexBufferRelease, const IndexBuffer* /*indexBuffer*/); + IndexBuffer& operator=(const IndexBuffer&) = default; + IndexBuffer& operator=(IndexBuffer&&) noexcept = default; private: - BufferRef m_buffer; + std::shared_ptr m_buffer; std::size_t m_endOffset; std::size_t m_indexCount; std::size_t m_startOffset; diff --git a/include/Nazara/Utility/IndexBuffer.inl b/include/Nazara/Utility/IndexBuffer.inl index d9a93f471..a306a77bd 100644 --- a/include/Nazara/Utility/IndexBuffer.inl +++ b/include/Nazara/Utility/IndexBuffer.inl @@ -7,7 +7,7 @@ namespace Nz { - inline const BufferRef& IndexBuffer::GetBuffer() const + inline const std::shared_ptr& IndexBuffer::GetBuffer() const { return m_buffer; } @@ -24,7 +24,7 @@ namespace Nz inline std::size_t IndexBuffer::GetStride() const { - return static_cast((m_largeIndices) ? sizeof(std::size_t) : sizeof(UInt16)); + return static_cast((m_largeIndices) ? sizeof(UInt32) : sizeof(UInt16)); } inline std::size_t IndexBuffer::GetStartOffset() const @@ -39,7 +39,7 @@ namespace Nz inline bool IndexBuffer::IsValid() const { - return m_buffer.IsValid(); + return m_buffer != nullptr; } inline void* IndexBuffer::Map(BufferAccess access, std::size_t startIndex, std::size_t length) @@ -53,15 +53,6 @@ namespace Nz std::size_t stride = GetStride(); return MapRaw(access, startIndex*stride, length*stride); } - - template - IndexBufferRef IndexBuffer::New(Args&&... args) - { - std::unique_ptr object(new IndexBuffer(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); - } } #include diff --git a/include/Nazara/Utility/IndexMapper.hpp b/include/Nazara/Utility/IndexMapper.hpp index f7fbd30f7..be3b1d1f2 100644 --- a/include/Nazara/Utility/IndexMapper.hpp +++ b/include/Nazara/Utility/IndexMapper.hpp @@ -19,10 +19,10 @@ namespace Nz class NAZARA_UTILITY_API IndexMapper { public: - IndexMapper(IndexBuffer* indexBuffer, BufferAccess access = BufferAccess_ReadWrite, std::size_t indexCount = 0); - IndexMapper(SubMesh* subMesh, BufferAccess access = BufferAccess_ReadWrite); - IndexMapper(const IndexBuffer* indexBuffer, BufferAccess access = BufferAccess_ReadOnly, std::size_t indexCount = 0); - IndexMapper(const SubMesh* subMesh, BufferAccess access = BufferAccess_ReadOnly); + IndexMapper(IndexBuffer& indexBuffer, BufferAccess access = BufferAccess::ReadWrite, std::size_t indexCount = 0); + IndexMapper(SubMesh& subMesh, BufferAccess access = BufferAccess::ReadWrite); + IndexMapper(const IndexBuffer& indexBuffer, BufferAccess access = BufferAccess::ReadOnly, std::size_t indexCount = 0); + IndexMapper(const SubMesh& subMesh, BufferAccess access = BufferAccess::ReadOnly); ~IndexMapper() = default; UInt32 Get(std::size_t i) const; diff --git a/include/Nazara/Utility/MaterialData.hpp b/include/Nazara/Utility/MaterialData.hpp index c09a0e213..2096e699f 100644 --- a/include/Nazara/Utility/MaterialData.hpp +++ b/include/Nazara/Utility/MaterialData.hpp @@ -22,6 +22,12 @@ namespace Nz static constexpr const char* BackFaceStencilReference = "MatBackFaceStencilReference"; static constexpr const char* BackFaceStencilZFail = "MatBackFaceStencilZFail"; static constexpr const char* Blending = "MatBlending"; + static constexpr const char* BlendModeAlpha = "MatBlendModeAlpha"; + static constexpr const char* BlendModeColor = "MatBlendModeColor"; + static constexpr const char* BlendDstAlpha = "MatBlendDstAlpha"; + static constexpr const char* BlendDstColor = "MatBlendDstColor"; + static constexpr const char* BlendSrcAlpha = "MatBlendSrcAlpha"; + static constexpr const char* BlendSrcColor = "MatBlendSrcColor"; static constexpr const char* CullingSide = "MatCullingSide"; static constexpr const char* ColorWrite = "MatColorWrite"; static constexpr const char* DepthBuffer = "MatDepthBuffer"; @@ -33,7 +39,6 @@ namespace Nz static constexpr const char* DiffuseFilter = "MatDiffuseFilter"; static constexpr const char* DiffuseTexturePath = "MatDiffuseTexturePath"; static constexpr const char* DiffuseWrap = "MatDiffuseWrap"; - static constexpr const char* DstBlend = "MatDstBlend"; static constexpr const char* EmissiveTexturePath = "MatEmissiveTexturePath"; static constexpr const char* FaceCulling = "MatFaceCulling"; static constexpr const char* FaceFilling = "MatFaceFilling"; @@ -51,7 +56,6 @@ namespace Nz static constexpr const char* SpecularFilter = "MatSpecularFilter"; static constexpr const char* SpecularTexturePath = "MatSpecularTexturePath"; static constexpr const char* SpecularWrap = "MatSpecularWrap"; - static constexpr const char* SrcBlend = "MatSrcBlend"; static constexpr const char* StencilCompare = "MatStencilCompare"; static constexpr const char* StencilFail = "MatStencilFail"; static constexpr const char* StencilMask = "MatStencilMask"; diff --git a/include/Nazara/Utility/Mesh.hpp b/include/Nazara/Utility/Mesh.hpp index 0cc867624..587fd38ee 100644 --- a/include/Nazara/Utility/Mesh.hpp +++ b/include/Nazara/Utility/Mesh.hpp @@ -9,8 +9,6 @@ #include #include -#include -#include #include #include #include @@ -35,7 +33,7 @@ namespace Nz BufferUsageFlags indexBufferFlags = 0; ///< Buffer usage flags used to build the index buffers BufferUsageFlags vertexBufferFlags = 0; ///< Buffer usage flags used to build the vertex buffers Matrix4f matrix = Matrix4f::Identity(); ///< A matrix which will transform every vertex position - DataStorage storage = DataStorage_Hardware; ///< The place where the buffers will be allocated + DataStorage storage = DataStorage::Hardware; ///< The place where the buffers will be allocated Vector2f texCoordOffset = {0.f, 0.f}; ///< Offset to apply on the texture coordinates (not scaled) Vector2f texCoordScale = {1.f, 1.f}; ///< Scale to apply on the texture coordinates bool animated = true; ///< If true, will load an animated version of the model if possible @@ -51,7 +49,7 @@ namespace Nz * If the declaration has a Vector3f Normals component enabled, Normals are generated. * If the declaration has a Vector3f Tangents component enabled, Tangents are generated. */ - VertexDeclaration* vertexDeclaration = VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent); + std::shared_ptr vertexDeclaration = VertexDeclaration::Get(VertexLayout::XYZ_Normal_UV_Tangent); bool IsValid() const; }; @@ -64,33 +62,25 @@ namespace Nz using MeshVertex = VertexStruct_XYZ_Normal_UV_Tangent; using SkeletalMeshVertex = VertexStruct_XYZ_Normal_UV_Tangent_Skinning; - using MeshConstRef = ObjectRef; using MeshLibrary = ObjectLibrary; using MeshLoader = ResourceLoader; using MeshManager = ResourceManager; - using MeshRef = ObjectRef; using MeshSaver = ResourceSaver; struct MeshImpl; - class NAZARA_UTILITY_API Mesh : public RefCounted, public Resource + class NAZARA_UTILITY_API Mesh : public Resource { - friend MeshLibrary; - friend MeshLoader; - friend MeshManager; - friend MeshSaver; - friend class Utility; - public: inline Mesh(); Mesh(const Mesh&) = delete; Mesh(Mesh&&) = delete; - inline ~Mesh(); + ~Mesh() = default; - void AddSubMesh(SubMesh* subMesh); - void AddSubMesh(const std::string& identifier, SubMesh* subMesh); + void AddSubMesh(std::shared_ptr subMesh); + void AddSubMesh(const std::string& identifier, std::shared_ptr subMesh); - SubMesh* BuildSubMesh(const Primitive& primitive, const MeshParams& params = MeshParams()); + std::shared_ptr BuildSubMesh(const Primitive& primitive, const MeshParams& params = MeshParams()); void BuildSubMeshes(const PrimitiveList& list, const MeshParams& params = MeshParams()); bool CreateSkeletal(std::size_t jointCount); @@ -110,10 +100,8 @@ namespace Nz std::size_t GetMaterialCount() const; Skeleton* GetSkeleton(); const Skeleton* GetSkeleton() const; - SubMesh* GetSubMesh(const std::string& identifier); - SubMesh* GetSubMesh(std::size_t index); - const SubMesh* GetSubMesh(const std::string& identifier) const; - const SubMesh* GetSubMesh(std::size_t index) const; + const std::shared_ptr& GetSubMesh(const std::string& identifier) const; + const std::shared_ptr& GetSubMesh(std::size_t index) const; std::size_t GetSubMeshCount() const; std::size_t GetSubMeshIndex(const std::string& identifier) const; std::size_t GetTriangleCount() const; @@ -144,25 +132,22 @@ namespace Nz Mesh& operator=(const Mesh&) = delete; Mesh& operator=(Mesh&&) = delete; - static MeshRef LoadFromFile(const std::filesystem::path& filePath, const MeshParams& params = MeshParams()); - static MeshRef LoadFromMemory(const void* data, std::size_t size, const MeshParams& params = MeshParams()); - static MeshRef LoadFromStream(Stream& stream, const MeshParams& params = MeshParams()); - - template static MeshRef New(Args&&... args); + static std::shared_ptr LoadFromFile(const std::filesystem::path& filePath, const MeshParams& params = MeshParams()); + static std::shared_ptr LoadFromMemory(const void* data, std::size_t size, const MeshParams& params = MeshParams()); + static std::shared_ptr LoadFromStream(Stream& stream, const MeshParams& params = MeshParams()); // Signals: - NazaraSignal(OnMeshDestroy, const Mesh* /*mesh*/); NazaraSignal(OnMeshInvalidateAABB, const Mesh* /*mesh*/); - NazaraSignal(OnMeshRelease, const Mesh* /*mesh*/); private: struct SubMeshData { - SubMeshRef subMesh; + std::shared_ptr subMesh; NazaraSlot(SubMesh, OnSubMeshInvalidateAABB, onSubMeshInvalidated); }; + std::size_t m_jointCount; // Only used by skeletal meshes std::unordered_map m_subMeshMap; std::vector m_materialData; std::vector m_subMeshes; @@ -172,16 +157,6 @@ namespace Nz std::filesystem::path m_animationPath; mutable bool m_aabbUpdated; bool m_isValid; - std::size_t m_jointCount; // Only used by skeletal meshes - - static bool Initialize(); - static void Uninitialize(); - - static MeshLibrary::LibraryMap s_library; - static MeshLoader::LoaderList s_loaders; - static MeshManager::ManagerMap s_managerMap; - static MeshManager::ManagerParams s_managerParameters; - static MeshSaver::SaverList s_savers; }; } diff --git a/include/Nazara/Utility/Mesh.inl b/include/Nazara/Utility/Mesh.inl index 71af75f0d..0681e0850 100644 --- a/include/Nazara/Utility/Mesh.inl +++ b/include/Nazara/Utility/Mesh.inl @@ -14,22 +14,6 @@ namespace Nz m_isValid(false) { } - - Mesh::~Mesh() - { - OnMeshRelease(this); - - Destroy(); - } - - template - MeshRef Mesh::New(Args&&... args) - { - std::unique_ptr object(new Mesh(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); - } } #include diff --git a/include/Nazara/Utility/Node.hpp b/include/Nazara/Utility/Node.hpp index d2faaab1c..0af3b619f 100644 --- a/include/Nazara/Utility/Node.hpp +++ b/include/Nazara/Utility/Node.hpp @@ -41,21 +41,21 @@ namespace Nz virtual Vector3f GetLeft() const; virtual NodeType GetNodeType() const; const Node* GetParent() const; - Vector3f GetPosition(CoordSys coordSys = CoordSys_Local) const; + Vector3f GetPosition(CoordSys coordSys = CoordSys::Local) const; virtual Vector3f GetRight() const; - Quaternionf GetRotation(CoordSys coordSys = CoordSys_Local) const; - Vector3f GetScale(CoordSys coordSys = CoordSys_Local) const; + Quaternionf GetRotation(CoordSys coordSys = CoordSys::Local) const; + Vector3f GetScale(CoordSys coordSys = CoordSys::Local) const; const Matrix4f& GetTransformMatrix() const; virtual Vector3f GetUp() const; bool HasChilds() const; - Node& Interpolate(const Node& nodeA, const Node& nodeB, float interpolation, CoordSys coordSys = CoordSys_Global); + Node& Interpolate(const Node& nodeA, const Node& nodeB, float interpolation, CoordSys coordSys = CoordSys::Global); - Node& Move(const Vector3f& movement, CoordSys coordSys = CoordSys_Local); - Node& Move(float movementX, float movementY, float movementZ = 0.f, CoordSys coordSys = CoordSys_Local); + Node& Move(const Vector3f& movement, CoordSys coordSys = CoordSys::Local); + Node& Move(float movementX, float movementY, float movementZ = 0.f, CoordSys coordSys = CoordSys::Local); - Node& Rotate(const Quaternionf& rotation, CoordSys coordSys = CoordSys_Local); + Node& Rotate(const Quaternionf& rotation, CoordSys coordSys = CoordSys::Local); Node& Scale(const Vector3f& scale); Node& Scale(float scale); @@ -72,13 +72,13 @@ namespace Nz void SetInitialPosition(float translationX, float translationXY, float translationZ = 0.f); void SetParent(const Node* node = nullptr, bool keepDerived = false); void SetParent(const Node& node, bool keepDerived = false); - void SetPosition(const Vector3f& translation, CoordSys coordSys = CoordSys_Local); - void SetPosition(float translationX, float translationY, float translationZ = 0.f, CoordSys coordSys = CoordSys_Local); - void SetRotation(const Quaternionf& quat, CoordSys coordSys = CoordSys_Local); - void SetScale(const Vector2f& scale, CoordSys coordSys = CoordSys_Local); - void SetScale(const Vector3f& scale, CoordSys coordSys = CoordSys_Local); - void SetScale(float scale, CoordSys coordSys = CoordSys_Local); - void SetScale(float scaleX, float scaleY, float scaleZ = 1.f, CoordSys coordSys = CoordSys_Local); + void SetPosition(const Vector3f& translation, CoordSys coordSys = CoordSys::Local); + void SetPosition(float translationX, float translationY, float translationZ = 0.f, CoordSys coordSys = CoordSys::Local); + void SetRotation(const Quaternionf& quat, CoordSys coordSys = CoordSys::Local); + void SetScale(const Vector2f& scale, CoordSys coordSys = CoordSys::Local); + void SetScale(const Vector3f& scale, CoordSys coordSys = CoordSys::Local); + void SetScale(float scale, CoordSys coordSys = CoordSys::Local); + void SetScale(float scaleX, float scaleY, float scaleZ = 1.f, CoordSys coordSys = CoordSys::Local); void SetTransformMatrix(const Matrix4f& matrix); // Local -> global diff --git a/include/Nazara/Utility/PixelFormat.hpp b/include/Nazara/Utility/PixelFormat.hpp index 52b51da28..f12be11fd 100644 --- a/include/Nazara/Utility/PixelFormat.hpp +++ b/include/Nazara/Utility/PixelFormat.hpp @@ -11,8 +11,8 @@ #include #include #include +#include #include -#include ///TODO: Permettre la conversion automatique entre les formats via des renseignements de bits et de type pour chaque format. /// Ce serait plus lent que la conversion spécialisée (qui ne disparaîtra donc pas) mais ça permettrait au moteur de faire la conversion @@ -87,9 +87,9 @@ namespace Nz static bool Initialize(); static void Uninitialize(); - static PixelFormatDescription s_pixelFormatInfos[PixelFormat_Max + 1]; - static ConvertFunction s_convertFunctions[PixelFormat_Max+1][PixelFormat_Max+1]; - static std::map s_flipFunctions[PixelFlipping_Max+1]; + static std::array, PixelFormatCount> s_convertFunctions; + static std::array, PixelFormatCount> s_flipFunctions; + static std::array s_pixelFormatInfos; }; } diff --git a/include/Nazara/Utility/PixelFormat.inl b/include/Nazara/Utility/PixelFormat.inl index 6f0170607..7f62d15a0 100644 --- a/include/Nazara/Utility/PixelFormat.inl +++ b/include/Nazara/Utility/PixelFormat.inl @@ -2,7 +2,9 @@ // This file is part of the "Nazara Engine - Utility module" // For conditions of distribution and use, see copyright notice in Config.hpp +#include #include +#include #include #include #include @@ -10,7 +12,7 @@ namespace Nz { inline PixelFormatDescription::PixelFormatDescription() : - content(PixelFormatContent_Undefined), + content(PixelFormatContent::Undefined), bitsPerPixel(0) { } @@ -74,10 +76,10 @@ namespace Nz inline bool PixelFormatDescription::IsCompressed() const { - return redType == PixelFormatSubType_Compressed || - greenType == PixelFormatSubType_Compressed || - blueType == PixelFormatSubType_Compressed || - alphaType == PixelFormatSubType_Compressed; + return redType == PixelFormatSubType::Compressed || + greenType == PixelFormatSubType::Compressed || + blueType == PixelFormatSubType::Compressed || + alphaType == PixelFormatSubType::Compressed; } inline bool PixelFormatDescription::IsValid() const @@ -101,7 +103,7 @@ namespace Nz if (!IsValid()) return false; - if (content <= PixelFormatContent_Undefined || content > PixelFormatContent_Max) + if (content <= PixelFormatContent::Undefined || content > PixelFormatContent::Max) return false; std::array*, 4> masks = { {&redMask, &greenMask, &blueMask, &alphaMask} }; @@ -121,13 +123,13 @@ namespace Nz switch (types[i]) { - case PixelFormatSubType_Half: + case PixelFormatSubType::Half: if (usedBits != 16) return false; break; - case PixelFormatSubType_Float: + case PixelFormatSubType::Float: if (usedBits != 32) return false; @@ -149,10 +151,10 @@ namespace Nz { switch (format) { - case PixelFormat_DXT1: - case PixelFormat_DXT3: - case PixelFormat_DXT5: - return (((width + 3) / 4) * ((height + 3) / 4) * ((format == PixelFormat_DXT1) ? 8 : 16)) * depth; + case PixelFormat::DXT1: + case PixelFormat::DXT3: + case PixelFormat::DXT5: + return (((width + 3) / 4) * ((height + 3) / 4) * ((format == PixelFormat::DXT1) ? 8 : 16)) * depth; default: NazaraError("Unsupported format"); @@ -185,31 +187,18 @@ namespace Nz } #endif - ConvertFunction func = s_convertFunctions[srcFormat][dstFormat]; - if (!func) - { - NazaraError("Pixel format conversion from " + GetName(srcFormat) + " to " + GetName(dstFormat) + " is not supported"); - return false; - } - - if (!func(reinterpret_cast(src), reinterpret_cast(src) + GetBytesPerPixel(srcFormat), reinterpret_cast(dst))) - { - NazaraError("Pixel format conversion from " + GetName(srcFormat) + " to " + GetName(dstFormat) + " failed"); - return false; - } - - return true; + return Convert(srcFormat, dstFormat, src, static_cast(src) + GetBytesPerPixel(srcFormat), dst); } inline bool PixelFormatInfo::Convert(PixelFormat srcFormat, PixelFormat dstFormat, const void* start, const void* end, void* dst) { if (srcFormat == dstFormat) { - std::memcpy(dst, start, reinterpret_cast(end)-reinterpret_cast(start)); + std::memcpy(dst, start, reinterpret_cast(end) - reinterpret_cast(start)); return true; } - ConvertFunction func = s_convertFunctions[srcFormat][dstFormat]; + ConvertFunction func = s_convertFunctions[UnderlyingCast(srcFormat)][UnderlyingCast(dstFormat)]; if (!func) { NazaraError("Pixel format conversion from " + GetName(srcFormat) + " to " + GetName(dstFormat) + " is not supported"); @@ -227,7 +216,7 @@ namespace Nz inline UInt8 PixelFormatInfo::GetBitsPerPixel(PixelFormat format) { - return s_pixelFormatInfos[format].bitsPerPixel; + return s_pixelFormatInfos[UnderlyingCast(format)].bitsPerPixel; } inline UInt8 PixelFormatInfo::GetBytesPerPixel(PixelFormat format) @@ -237,27 +226,27 @@ namespace Nz inline PixelFormatContent PixelFormatInfo::GetContent(PixelFormat format) { - return s_pixelFormatInfos[format].content; + return s_pixelFormatInfos[UnderlyingCast(format)].content; } inline const PixelFormatDescription& PixelFormatInfo::GetInfo(PixelFormat format) { - return s_pixelFormatInfos[format]; + return s_pixelFormatInfos[UnderlyingCast(format)]; } inline const std::string& PixelFormatInfo::GetName(PixelFormat format) { - return s_pixelFormatInfos[format].name; + return s_pixelFormatInfos[UnderlyingCast(format)].name; } inline bool PixelFormatInfo::HasAlpha(PixelFormat format) { - return s_pixelFormatInfos[format].alphaMask.TestAny(); + return s_pixelFormatInfos[UnderlyingCast(format)].alphaMask.TestAny(); } inline bool PixelFormatInfo::IsCompressed(PixelFormat format) { - return s_pixelFormatInfos[format].IsCompressed(); + return s_pixelFormatInfos[UnderlyingCast(format)].IsCompressed(); } inline bool PixelFormatInfo::IsConversionSupported(PixelFormat srcFormat, PixelFormat dstFormat) @@ -265,22 +254,22 @@ namespace Nz if (srcFormat == dstFormat) return true; - return s_convertFunctions[srcFormat][dstFormat] != nullptr; + return s_convertFunctions[UnderlyingCast(srcFormat)][UnderlyingCast(dstFormat)] != nullptr; } inline bool PixelFormatInfo::IsValid(PixelFormat format) { - return format != PixelFormat_Undefined; + return format != PixelFormat::Undefined; } inline void PixelFormatInfo::SetConvertFunction(PixelFormat srcFormat, PixelFormat dstFormat, ConvertFunction func) { - s_convertFunctions[srcFormat][dstFormat] = func; + s_convertFunctions[UnderlyingCast(srcFormat)][UnderlyingCast(dstFormat)] = func; } inline void PixelFormatInfo::SetFlipFunction(PixelFlipping flipping, PixelFormat format, FlipFunction func) { - s_flipFunctions[flipping][format] = func; + s_flipFunctions[UnderlyingCast(flipping)][UnderlyingCast(format)] = func; } } diff --git a/include/Nazara/Utility/RichTextDrawer.hpp b/include/Nazara/Utility/RichTextDrawer.hpp index 44cb55695..f3a3dbefd 100644 --- a/include/Nazara/Utility/RichTextDrawer.hpp +++ b/include/Nazara/Utility/RichTextDrawer.hpp @@ -37,7 +37,7 @@ namespace Nz inline const Color& GetBlockColor(std::size_t index) const; inline std::size_t GetBlockCount() const; inline std::size_t GetBlockFirstGlyphIndex(std::size_t index) const; - inline const FontRef& GetBlockFont(std::size_t index) const; + inline const std::shared_ptr& GetBlockFont(std::size_t index) const; inline float GetBlockLineHeight(std::size_t index) const; inline float GetBlockLineSpacingOffset(std::size_t index) const; inline const Color& GetBlockOutlineColor(std::size_t index) const; @@ -50,12 +50,12 @@ namespace Nz inline unsigned int GetDefaultCharacterSize() const; inline float GetDefaultCharacterSpacingOffset() const; inline const Color& GetDefaultColor() const; - inline const FontRef& GetDefaultFont() const; + inline const std::shared_ptr& GetDefaultFont() const; inline float GetDefaultLineSpacingOffset() const; inline const Color& GetDefaultOutlineColor() const; inline float GetDefaultOutlineThickness() const; inline TextStyleFlags GetDefaultStyle() const; - Font* GetFont(std::size_t index) const override; + const std::shared_ptr& GetFont(std::size_t index) const override; std::size_t GetFontCount() const override; const Glyph& GetGlyph(std::size_t index) const override; std::size_t GetGlyphCount() const override; @@ -72,7 +72,7 @@ namespace Nz inline void SetBlockCharacterSize(std::size_t index, unsigned int characterSize); inline void SetBlockCharacterSpacingOffset(std::size_t index, float offset); inline void SetBlockColor(std::size_t index, const Color& color); - inline void SetBlockFont(std::size_t index, FontRef font); + inline void SetBlockFont(std::size_t index, std::shared_ptr font); inline void SetBlockLineSpacingOffset(std::size_t index, float offset); inline void SetBlockOutlineColor(std::size_t index, const Color& color); inline void SetBlockOutlineThickness(std::size_t index, float thickness); @@ -82,7 +82,7 @@ namespace Nz inline void SetDefaultCharacterSize(unsigned int characterSize); inline void SetDefaultCharacterSpacingOffset(float offset); inline void SetDefaultColor(const Color& color); - inline void SetDefaultFont(const FontRef& font); + inline void SetDefaultFont(const std::shared_ptr& font); inline void SetDefaultLineSpacingOffset(float offset); inline void SetDefaultOutlineColor(const Color& color); inline void SetDefaultOutlineThickness(float thickness); @@ -98,16 +98,16 @@ namespace Nz private: struct Block; - inline void AppendNewLine(const Font* font, unsigned int characterSize, float lineSpacingOffset) const; - void AppendNewLine(const Font* font, unsigned int characterSize, float lineSpacingOffset, std::size_t glyphIndex, float glyphPosition) const; + inline void AppendNewLine(const Font& font, unsigned int characterSize, float lineSpacingOffset) const; + void AppendNewLine(const Font& font, unsigned int characterSize, float lineSpacingOffset, std::size_t glyphIndex, float glyphPosition) const; inline void ClearGlyphs() const; inline void ConnectFontSlots(); inline void DisconnectFontSlots(); - bool GenerateGlyph(Glyph& glyph, char32_t character, float outlineThickness, bool lineWrap, const Font* font, const Color& color, TextStyleFlags style, float lineSpacingOffset, unsigned int characterSize, int renderOrder, int* advance) const; - void GenerateGlyphs(const Font* font, const Color& color, TextStyleFlags style, unsigned int characterSize, const Color& outlineColor, float characterSpacingOffset, float lineSpacingOffset, float outlineThickness, const std::string& text) const; + bool GenerateGlyph(Glyph& glyph, char32_t character, float outlineThickness, bool lineWrap, const Font& font, const Color& color, TextStyleFlags style, float lineSpacingOffset, unsigned int characterSize, int renderOrder, int* advance) const; + void GenerateGlyphs(const Font& font, const Color& color, TextStyleFlags style, unsigned int characterSize, const Color& outlineColor, float characterSpacingOffset, float lineSpacingOffset, float outlineThickness, const std::string& text) const; inline float GetLineHeight(const Block& block) const; inline float GetLineHeight(float lineSpacingOffset, const Font::SizeInfo& sizeInfo) const; - inline std::size_t HandleFontAddition(const FontRef& font); + inline std::size_t HandleFontAddition(const std::shared_ptr& font); inline void InvalidateGlyphs(); inline void ReleaseFont(std::size_t fontIndex); inline bool ShouldLineWrap(float size) const; @@ -136,7 +136,7 @@ namespace Nz struct FontData { - FontRef font; + std::shared_ptr font; std::size_t useCount = 0; NazaraSlot(Font, OnFontAtlasChanged, atlasChangedSlot); @@ -148,9 +148,9 @@ namespace Nz Color m_defaultColor; Color m_defaultOutlineColor; TextStyleFlags m_defaultStyle; - FontRef m_defaultFont; + std::shared_ptr m_defaultFont; mutable std::size_t m_lastSeparatorGlyph; - std::unordered_map m_fontIndexes; + std::unordered_map, std::size_t> m_fontIndexes; std::vector m_blocks; std::vector m_fonts; mutable std::vector m_glyphs; @@ -179,7 +179,7 @@ namespace Nz inline unsigned int GetCharacterSize() const; inline Color GetColor() const; inline std::size_t GetFirstGlyphIndex() const; - inline const FontRef& GetFont() const; + inline const std::shared_ptr& GetFont() const; inline float GetLineSpacingOffset() const; inline Color GetOutlineColor() const; inline float GetOutlineThickness() const; @@ -189,7 +189,7 @@ namespace Nz inline void SetCharacterSpacingOffset(float offset); inline void SetCharacterSize(unsigned int size); inline void SetColor(Color color); - inline void SetFont(FontRef font); + inline void SetFont(std::shared_ptr font); inline void SetLineSpacingOffset(float offset); inline void SetOutlineColor(Color color); inline void SetOutlineThickness(float thickness); diff --git a/include/Nazara/Utility/RichTextDrawer.inl b/include/Nazara/Utility/RichTextDrawer.inl index 977565287..622af5717 100644 --- a/include/Nazara/Utility/RichTextDrawer.inl +++ b/include/Nazara/Utility/RichTextDrawer.inl @@ -80,7 +80,7 @@ namespace Nz return m_blocks[index].glyphIndex; } - inline const FontRef& RichTextDrawer::GetBlockFont(std::size_t index) const + inline const std::shared_ptr& RichTextDrawer::GetBlockFont(std::size_t index) const { NazaraAssert(index < m_blocks.size(), "Invalid block index"); std::size_t fontIndex = m_blocks[index].fontIndex; @@ -139,7 +139,7 @@ namespace Nz return m_defaultColor; } - inline const FontRef& RichTextDrawer::GetDefaultFont() const + inline const std::shared_ptr& RichTextDrawer::GetDefaultFont() const { return m_defaultFont; } @@ -164,7 +164,7 @@ namespace Nz return m_defaultStyle; } - inline void RichTextDrawer::AppendNewLine(const Font* font, unsigned int characterSize, float lineSpacingOffset) const + inline void RichTextDrawer::AppendNewLine(const Font& font, unsigned int characterSize, float lineSpacingOffset) const { AppendNewLine(font, characterSize, lineSpacingOffset, InvalidGlyph, 0); } @@ -214,7 +214,7 @@ namespace Nz return float(sizeInfo.lineHeight) + lineSpacingOffset; } - inline std::size_t RichTextDrawer::HandleFontAddition(const FontRef& font) + inline std::size_t RichTextDrawer::HandleFontAddition(const std::shared_ptr& font) { auto it = m_fontIndexes.find(font); if (it == m_fontIndexes.end()) @@ -292,7 +292,7 @@ namespace Nz InvalidateGlyphs(); } - inline void RichTextDrawer::SetBlockFont(std::size_t index, FontRef font) + inline void RichTextDrawer::SetBlockFont(std::size_t index, std::shared_ptr font) { NazaraAssert(index < m_blocks.size(), "Invalid block index"); std::size_t fontIndex = HandleFontAddition(font); @@ -375,7 +375,7 @@ namespace Nz m_defaultColor = color; } - inline void RichTextDrawer::SetDefaultFont(const FontRef& font) + inline void RichTextDrawer::SetDefaultFont(const std::shared_ptr& font) { m_defaultFont = font; } @@ -457,7 +457,7 @@ namespace Nz * * \see GetCharacterSize, GetColor, GetStyle, GetText, SetFont */ - inline const FontRef& RichTextDrawer::BlockRef::GetFont() const + inline const std::shared_ptr& RichTextDrawer::BlockRef::GetFont() const { return m_drawer.GetBlockFont(m_blockIndex); } @@ -567,7 +567,7 @@ namespace Nz * * \see GetCharacterSize, SetCharacterSize, SetColor, SetStyle, SetText */ - inline void RichTextDrawer::BlockRef::SetFont(FontRef font) + inline void RichTextDrawer::BlockRef::SetFont(std::shared_ptr font) { m_drawer.SetBlockFont(m_blockIndex, std::move(font)); } diff --git a/include/Nazara/Utility/SimpleTextDrawer.hpp b/include/Nazara/Utility/SimpleTextDrawer.hpp index d1d1027dc..b0a0fd92b 100644 --- a/include/Nazara/Utility/SimpleTextDrawer.hpp +++ b/include/Nazara/Utility/SimpleTextDrawer.hpp @@ -31,8 +31,8 @@ namespace Nz inline float GetCharacterSpacingOffset() const; inline unsigned int GetCharacterSize() const; inline const Color& GetColor() const; - inline Font* GetFont() const; - Font* GetFont(std::size_t index) const override; + inline const std::shared_ptr& GetFont() const; + const std::shared_ptr& GetFont(std::size_t index) const override; std::size_t GetFontCount() const override; const Glyph& GetGlyph(std::size_t index) const override; std::size_t GetGlyphCount() const override; @@ -49,7 +49,7 @@ namespace Nz inline void SetCharacterSpacingOffset(float offset); inline void SetCharacterSize(unsigned int characterSize); inline void SetColor(const Color& color); - inline void SetFont(Font* font); + inline void SetFont(std::shared_ptr font); inline void SetLineSpacingOffset(float offset); inline void SetMaxLineWidth(float lineWidth) override; inline void SetOutlineColor(const Color& color); @@ -62,8 +62,8 @@ namespace Nz static inline SimpleTextDrawer Draw(const std::string& str, unsigned int characterSize, TextStyleFlags style = TextStyle_Regular, const Color& color = Color::White); static inline SimpleTextDrawer Draw(const std::string& str, unsigned int characterSize, TextStyleFlags style, const Color& color, float outlineThickness, const Color& outlineColor); - static inline SimpleTextDrawer Draw(Font* font, const std::string& str, unsigned int characterSize, TextStyleFlags style = TextStyle_Regular, const Color& color = Color::White); - static inline SimpleTextDrawer Draw(Font* font, const std::string& str, unsigned int characterSize, TextStyleFlags style, const Color& color, float outlineThickness, const Color& outlineColor); + static inline SimpleTextDrawer Draw(const std::shared_ptr& font, const std::string& str, unsigned int characterSize, TextStyleFlags style = TextStyle_Regular, const Color& color = Color::White); + static inline SimpleTextDrawer Draw(const std::shared_ptr& font, const std::string& str, unsigned int characterSize, TextStyleFlags style, const Color& color, float outlineThickness, const Color& outlineColor); private: inline void AppendNewLine() const; @@ -104,7 +104,7 @@ namespace Nz std::string m_text; Color m_color; Color m_outlineColor; - FontRef m_font; + std::shared_ptr m_font; mutable Rectf m_bounds; TextStyleFlags m_style; mutable UInt32 m_previousCharacter; diff --git a/include/Nazara/Utility/SimpleTextDrawer.inl b/include/Nazara/Utility/SimpleTextDrawer.inl index 0bc38edda..24836d42a 100644 --- a/include/Nazara/Utility/SimpleTextDrawer.inl +++ b/include/Nazara/Utility/SimpleTextDrawer.inl @@ -65,7 +65,7 @@ namespace Nz return m_color; } - inline Font* SimpleTextDrawer::GetFont() const + inline const std::shared_ptr& SimpleTextDrawer::GetFont() const { return m_font; } @@ -131,11 +131,11 @@ namespace Nz } } - inline void SimpleTextDrawer::SetFont(Font* font) + inline void SimpleTextDrawer::SetFont(std::shared_ptr font) { if (m_font != font) { - m_font = font; + m_font = std::move(font); if (m_font) ConnectFontSlots(); @@ -281,7 +281,7 @@ namespace Nz return drawer; } - inline SimpleTextDrawer SimpleTextDrawer::Draw(Font* font, const std::string& str, unsigned int characterSize, TextStyleFlags style, const Color& color) + inline SimpleTextDrawer SimpleTextDrawer::Draw(const std::shared_ptr& font, const std::string& str, unsigned int characterSize, TextStyleFlags style, const Color& color) { SimpleTextDrawer drawer; drawer.SetCharacterSize(characterSize); @@ -293,7 +293,7 @@ namespace Nz return drawer; } - inline SimpleTextDrawer SimpleTextDrawer::Draw(Font* font, const std::string& str, unsigned int characterSize, TextStyleFlags style, const Color& color, float outlineThickness, const Color& outlineColor) + inline SimpleTextDrawer SimpleTextDrawer::Draw(const std::shared_ptr& font, const std::string& str, unsigned int characterSize, TextStyleFlags style, const Color& color, float outlineThickness, const Color& outlineColor) { SimpleTextDrawer drawer; drawer.SetCharacterSize(characterSize); diff --git a/include/Nazara/Utility/SkeletalMesh.hpp b/include/Nazara/Utility/SkeletalMesh.hpp index 486403cda..a5c43d60c 100644 --- a/include/Nazara/Utility/SkeletalMesh.hpp +++ b/include/Nazara/Utility/SkeletalMesh.hpp @@ -8,56 +8,34 @@ #define NAZARA_SKELETALMESH_HPP #include -#include -#include #include #include #include namespace Nz { - class SkeletalMesh; - - using SkeletalMeshConstRef = ObjectRef; - using SkeletalMeshRef = ObjectRef; - class NAZARA_UTILITY_API SkeletalMesh final : public SubMesh { public: - SkeletalMesh(VertexBuffer* vertexBuffer, const IndexBuffer* indexBuffer); - - NAZARA_DEPRECATED("SkeletalMesh constructor taking a mesh is deprecated, submeshes no longer require to be part of a single mesh") - SkeletalMesh(const Mesh* parent); - - ~SkeletalMesh(); - - NAZARA_DEPRECATED("SkeletalMesh create/destroy functions are deprecated, please use constructor") - bool Create(VertexBuffer* vertexBuffer); - void Destroy(); + SkeletalMesh(std::shared_ptr vertexBuffer, std::shared_ptr indexBuffer); + ~SkeletalMesh() = default; const Boxf& GetAABB() const override; AnimationType GetAnimationType() const final; - const IndexBuffer* GetIndexBuffer() const override; - VertexBuffer* GetVertexBuffer(); - const VertexBuffer* GetVertexBuffer() const; + const std::shared_ptr& GetIndexBuffer() const override; + const std::shared_ptr& GetVertexBuffer() const; std::size_t GetVertexCount() const override; bool IsAnimated() const final; bool IsValid() const; void SetAABB(const Boxf& aabb); - void SetIndexBuffer(const IndexBuffer* indexBuffer); - - template static SkeletalMeshRef New(Args&&... args); - - // Signals: - NazaraSignal(OnSkeletalMeshDestroy, const SkeletalMesh* /*skeletalMesh*/); - NazaraSignal(OnSkeletalMeshRelease, const SkeletalMesh* /*skeletalMesh*/); + void SetIndexBuffer(std::shared_ptr indexBuffer); private: Boxf m_aabb; - IndexBufferConstRef m_indexBuffer; - VertexBufferRef m_vertexBuffer; + std::shared_ptr m_indexBuffer; + std::shared_ptr m_vertexBuffer; }; } diff --git a/include/Nazara/Utility/SkeletalMesh.inl b/include/Nazara/Utility/SkeletalMesh.inl index d6b071062..c508ab9a1 100644 --- a/include/Nazara/Utility/SkeletalMesh.inl +++ b/include/Nazara/Utility/SkeletalMesh.inl @@ -2,19 +2,12 @@ // This file is part of the "Nazara Engine - Utility module" // For conditions of distribution and use, see copyright notice in Config.hpp +#include #include #include namespace Nz { - template - SkeletalMeshRef SkeletalMesh::New(Args&&... args) - { - std::unique_ptr object(new SkeletalMesh(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); - } } #include diff --git a/include/Nazara/Utility/Skeleton.hpp b/include/Nazara/Utility/Skeleton.hpp index 535fc9f7d..27fecbbba 100644 --- a/include/Nazara/Utility/Skeleton.hpp +++ b/include/Nazara/Utility/Skeleton.hpp @@ -9,8 +9,6 @@ #include #include -#include -#include #include #include #include @@ -21,21 +19,18 @@ namespace Nz class Joint; class Skeleton; - using SkeletonConstRef = ObjectRef; using SkeletonLibrary = ObjectLibrary; - using SkeletonRef = ObjectRef; struct SkeletonImpl; - class NAZARA_UTILITY_API Skeleton : public RefCounted + class NAZARA_UTILITY_API Skeleton { friend Joint; - friend SkeletonLibrary; - friend class Utility; public: - Skeleton() = default; + Skeleton(); Skeleton(const Skeleton& skeleton); + Skeleton(Skeleton&&) noexcept; ~Skeleton(); bool Create(std::size_t jointCount); @@ -49,33 +44,25 @@ namespace Nz Joint* GetJoints(); const Joint* GetJoints() const; std::size_t GetJointCount() const; - int GetJointIndex(const std::string& jointName) const; + std::size_t GetJointIndex(const std::string& jointName) const; void Interpolate(const Skeleton& skeletonA, const Skeleton& skeletonB, float interpolation); - void Interpolate(const Skeleton& skeletonA, const Skeleton& skeletonB, float interpolation, std::size_t* indices, std::size_t indiceCount); + void Interpolate(const Skeleton& skeletonA, const Skeleton& skeletonB, float interpolation, const std::size_t* indices, std::size_t indiceCount); bool IsValid() const; Skeleton& operator=(const Skeleton& skeleton); - - template static SkeletonRef New(Args&&... args); + Skeleton& operator=(Skeleton&&) noexcept; // Signals: - NazaraSignal(OnSkeletonDestroy, const Skeleton* /*skeleton*/); NazaraSignal(OnSkeletonJointsInvalidated, const Skeleton* /*skeleton*/); - NazaraSignal(OnSkeletonRelease, const Skeleton* /*skeleton*/); private: void InvalidateJoints(); void InvalidateJointMap(); void UpdateJointMap() const; - static bool Initialize(); - static void Uninitialize(); - - SkeletonImpl* m_impl = nullptr; - - static SkeletonLibrary::LibraryMap s_library; + std::unique_ptr m_impl; }; } diff --git a/include/Nazara/Utility/Skeleton.inl b/include/Nazara/Utility/Skeleton.inl index 033cba926..997159e19 100644 --- a/include/Nazara/Utility/Skeleton.inl +++ b/include/Nazara/Utility/Skeleton.inl @@ -7,14 +7,6 @@ namespace Nz { - template - SkeletonRef Skeleton::New(Args&&... args) - { - std::unique_ptr object(new Skeleton(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); - } } #include diff --git a/include/Nazara/Utility/StaticMesh.hpp b/include/Nazara/Utility/StaticMesh.hpp index 64887e254..4044521f1 100644 --- a/include/Nazara/Utility/StaticMesh.hpp +++ b/include/Nazara/Utility/StaticMesh.hpp @@ -8,57 +8,36 @@ #define NAZARA_STATICMESH_HPP #include -#include #include namespace Nz { - class StaticMesh; - - using StaticMeshConstRef = ObjectRef; - using StaticMeshRef = ObjectRef; - class NAZARA_UTILITY_API StaticMesh final : public SubMesh { public: - StaticMesh(VertexBuffer* vertexBuffer, const IndexBuffer* indexBuffer); - - NAZARA_DEPRECATED("StaticMesh constructor taking a mesh is deprecated, submeshes no longer require to be part of a single mesh") - StaticMesh(const Mesh* parent); - - ~StaticMesh(); + StaticMesh(std::shared_ptr vertexBuffer, std::shared_ptr indexBuffer); + ~StaticMesh() = default; void Center(); - NAZARA_DEPRECATED("StaticMesh create/destroy functions are deprecated, please use constructor") - bool Create(VertexBuffer* vertexBuffer); - void Destroy(); - bool GenerateAABB(); const Boxf& GetAABB() const override; AnimationType GetAnimationType() const final; - const IndexBuffer* GetIndexBuffer() const override; - VertexBuffer* GetVertexBuffer(); - const VertexBuffer* GetVertexBuffer() const; + const std::shared_ptr& GetIndexBuffer() const override; + const std::shared_ptr& GetVertexBuffer() const; std::size_t GetVertexCount() const override; bool IsAnimated() const final; bool IsValid() const; void SetAABB(const Boxf& aabb); - void SetIndexBuffer(const IndexBuffer* indexBuffer); - - template static StaticMeshRef New(Args&&... args); - - // Signals: - NazaraSignal(OnStaticMeshDestroy, const StaticMesh* /*staticMesh*/); - NazaraSignal(OnStaticMeshRelease, const StaticMesh* /*staticMesh*/); + void SetIndexBuffer(std::shared_ptr indexBuffer); private: Boxf m_aabb; - IndexBufferConstRef m_indexBuffer; - VertexBufferRef m_vertexBuffer; + std::shared_ptr m_indexBuffer; + std::shared_ptr m_vertexBuffer; }; } diff --git a/include/Nazara/Utility/StaticMesh.inl b/include/Nazara/Utility/StaticMesh.inl index d25367dcb..997159e19 100644 --- a/include/Nazara/Utility/StaticMesh.inl +++ b/include/Nazara/Utility/StaticMesh.inl @@ -7,14 +7,6 @@ namespace Nz { - template - StaticMeshRef StaticMesh::New(Args&&... args) - { - std::unique_ptr object(new StaticMesh(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); - } } #include diff --git a/include/Nazara/Utility/SubMesh.hpp b/include/Nazara/Utility/SubMesh.hpp index 8feb14f15..b1d4e709b 100644 --- a/include/Nazara/Utility/SubMesh.hpp +++ b/include/Nazara/Utility/SubMesh.hpp @@ -8,8 +8,7 @@ #define NAZARA_SUBMESH_HPP #include -#include -#include +#include #include #include #include @@ -18,21 +17,13 @@ namespace Nz { class Mesh; - class SubMesh; - using SubMeshConstRef = ObjectRef; - using SubMeshRef = ObjectRef; - - class NAZARA_UTILITY_API SubMesh : public RefCounted + class NAZARA_UTILITY_API SubMesh { friend Mesh; public: SubMesh(); - - NAZARA_DEPRECATED("Submesh constructor taking a mesh is deprecated, submeshes no longer require to be part of a single mesh") - SubMesh(const Mesh* parent); - SubMesh(const SubMesh&) = delete; SubMesh(SubMesh&&) = delete; virtual ~SubMesh(); @@ -43,7 +34,7 @@ namespace Nz virtual const Boxf& GetAABB() const = 0; virtual AnimationType GetAnimationType() const = 0; - virtual const IndexBuffer* GetIndexBuffer() const = 0; + virtual const std::shared_ptr& GetIndexBuffer() const = 0; std::size_t GetMaterialIndex() const; PrimitiveMode GetPrimitiveMode() const; std::size_t GetTriangleCount() const; @@ -59,7 +50,6 @@ namespace Nz // Signals: NazaraSignal(OnSubMeshInvalidateAABB, const SubMesh* /*subMesh*/); - NazaraSignal(OnSubMeshRelease, const SubMesh* /*subMesh*/); protected: PrimitiveMode m_primitiveMode; diff --git a/include/Nazara/Utility/TriangleIterator.hpp b/include/Nazara/Utility/TriangleIterator.hpp index b33b1b386..43f310264 100644 --- a/include/Nazara/Utility/TriangleIterator.hpp +++ b/include/Nazara/Utility/TriangleIterator.hpp @@ -18,8 +18,8 @@ namespace Nz class NAZARA_UTILITY_API TriangleIterator { public: - TriangleIterator(PrimitiveMode primitiveMode, const IndexBuffer* indexBuffer); - TriangleIterator(const SubMesh* subMesh); + TriangleIterator(PrimitiveMode primitiveMode, const IndexBuffer& indexBuffer); + TriangleIterator(const SubMesh& subMesh); ~TriangleIterator() = default; bool Advance(); diff --git a/include/Nazara/Utility/UniformBuffer.hpp b/include/Nazara/Utility/UniformBuffer.hpp index cf16bc118..faaa2e482 100644 --- a/include/Nazara/Utility/UniformBuffer.hpp +++ b/include/Nazara/Utility/UniformBuffer.hpp @@ -8,31 +8,24 @@ #define NAZARA_UNIFORMBUFFER_HPP #include -#include -#include #include namespace Nz { - class UniformBuffer; - - using UniformBufferConstRef = ObjectRef; - using UniformBufferRef = ObjectRef; - - class NAZARA_UTILITY_API UniformBuffer : public RefCounted + class NAZARA_UTILITY_API UniformBuffer { public: UniformBuffer() = default; - UniformBuffer(BufferRef buffer); - UniformBuffer(BufferRef buffer, UInt32 offset, UInt32 size); + UniformBuffer(std::shared_ptr buffer); + UniformBuffer(std::shared_ptr buffer, UInt32 offset, UInt32 size); UniformBuffer(UInt32 length, DataStorage storage, BufferUsageFlags usage); - UniformBuffer(const UniformBuffer& uniformBuffer); - UniformBuffer(UniformBuffer&&) = delete; - ~UniformBuffer(); + UniformBuffer(const UniformBuffer&) = default; + UniformBuffer(UniformBuffer&&) noexcept = default; + ~UniformBuffer() = default; bool Fill(const void* data, UInt32 offset, UInt32 size); - inline const BufferRef& GetBuffer() const; + inline const std::shared_ptr& GetBuffer() const; inline UInt32 GetEndOffset() const; inline UInt32 GetStartOffset() const; @@ -42,23 +35,18 @@ namespace Nz void* Map(BufferAccess access, UInt32 offset = 0, UInt32 size = 0) const; void Reset(); - void Reset(BufferRef buffer); - void Reset(BufferRef buffer, UInt32 offset, UInt32 size); + void Reset(std::shared_ptr buffer); + void Reset(std::shared_ptr buffer, UInt32 offset, UInt32 size); void Reset(UInt32 size, DataStorage storage, BufferUsageFlags usage); void Reset(const UniformBuffer& uniformBuffer); void Unmap() const; - UniformBuffer& operator=(const UniformBuffer& uniformBuffer); - UniformBuffer& operator=(UniformBuffer&&) = delete; - - template static UniformBufferRef New(Args&&... args); - - // Signals: - NazaraSignal(OnUniformBufferRelease, const UniformBuffer* /*UniformBuffer*/); + UniformBuffer& operator=(const UniformBuffer&) = default; + UniformBuffer& operator=(UniformBuffer&&) noexcept = default; private: - BufferRef m_buffer; + std::shared_ptr m_buffer; UInt32 m_endOffset; UInt32 m_startOffset; }; diff --git a/include/Nazara/Utility/UniformBuffer.inl b/include/Nazara/Utility/UniformBuffer.inl index 958f0131a..e8f912507 100644 --- a/include/Nazara/Utility/UniformBuffer.inl +++ b/include/Nazara/Utility/UniformBuffer.inl @@ -8,7 +8,7 @@ namespace Nz { - inline const BufferRef& UniformBuffer::GetBuffer() const + inline const std::shared_ptr& UniformBuffer::GetBuffer() const { return m_buffer; } @@ -25,16 +25,7 @@ namespace Nz inline bool UniformBuffer::IsValid() const { - return m_buffer.IsValid(); - } - - template - UniformBufferRef UniformBuffer::New(Args&&... args) - { - std::unique_ptr object(new UniformBuffer(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); + return m_buffer != nullptr; } } diff --git a/include/Nazara/Utility/Utility.hpp b/include/Nazara/Utility/Utility.hpp index 9c2ebb2b4..049a23e5a 100644 --- a/include/Nazara/Utility/Utility.hpp +++ b/include/Nazara/Utility/Utility.hpp @@ -9,7 +9,11 @@ #include #include +#include #include +#include +#include +#include namespace Nz { @@ -23,9 +27,34 @@ namespace Nz struct Config {}; Utility(Config /*config*/); + Utility(const Utility&) = delete; + Utility(Utility&&) = delete; ~Utility(); + AnimationLoader& GetAnimationLoader(); + const AnimationLoader& GetAnimationLoader() const; + FontLoader& GetFontLoader(); + const FontLoader& GetFontLoader() const; + ImageLoader& GetImageLoader(); + const ImageLoader& GetImageLoader() const; + ImageSaver& GetImageSaver(); + const ImageSaver& GetImageSaver() const; + MeshLoader& GetMeshLoader(); + const MeshLoader& GetMeshLoader() const; + MeshSaver& GetMeshSaver(); + const MeshSaver& GetMeshSaver() const; + + Utility& operator=(const Utility&) = delete; + Utility& operator=(Utility&&) = delete; + private: + AnimationLoader m_animationLoader; + FontLoader m_fontLoader; + ImageLoader m_imageLoader; + ImageSaver m_imageSaver; + MeshLoader m_meshLoader; + MeshSaver m_meshSaver; + static Utility* s_instance; }; } diff --git a/include/Nazara/Utility/VertexBuffer.hpp b/include/Nazara/Utility/VertexBuffer.hpp index 82c83399d..237e0bc6b 100644 --- a/include/Nazara/Utility/VertexBuffer.hpp +++ b/include/Nazara/Utility/VertexBuffer.hpp @@ -8,39 +8,31 @@ #define NAZARA_VERTEXBUFFER_HPP #include -#include -#include -#include #include #include namespace Nz { - class VertexBuffer; - - using VertexBufferConstRef = ObjectRef; - using VertexBufferRef = ObjectRef; - - class NAZARA_UTILITY_API VertexBuffer : public RefCounted + class NAZARA_UTILITY_API VertexBuffer { public: VertexBuffer() = default; - VertexBuffer(VertexDeclarationConstRef vertexDeclaration, BufferRef buffer); - VertexBuffer(VertexDeclarationConstRef vertexDeclaration, BufferRef buffer, std::size_t offset, std::size_t size); - VertexBuffer(VertexDeclarationConstRef vertexDeclaration, std::size_t length, DataStorage storage, BufferUsageFlags usage); - VertexBuffer(const VertexBuffer& vertexBuffer); - VertexBuffer(VertexBuffer&&) = delete; - ~VertexBuffer(); + VertexBuffer(std::shared_ptr vertexDeclaration, std::shared_ptr buffer); + VertexBuffer(std::shared_ptr vertexDeclaration, std::shared_ptr buffer, std::size_t offset, std::size_t size); + VertexBuffer(std::shared_ptr vertexDeclaration, std::size_t length, DataStorage storage, BufferUsageFlags usage); + VertexBuffer(const VertexBuffer&) = default; + VertexBuffer(VertexBuffer&&) noexcept = default; + ~VertexBuffer() = default; bool Fill(const void* data, std::size_t startVertex, std::size_t length); bool FillRaw(const void* data, std::size_t offset, std::size_t size); - inline const BufferRef& GetBuffer() const; + inline const std::shared_ptr& GetBuffer() const; inline std::size_t GetEndOffset() const; inline std::size_t GetStartOffset() const; inline std::size_t GetStride() const; inline std::size_t GetVertexCount() const; - inline const VertexDeclarationConstRef& GetVertexDeclaration() const; + inline const std::shared_ptr& GetVertexDeclaration() const; inline bool IsValid() const; @@ -50,29 +42,24 @@ namespace Nz void* MapRaw(BufferAccess access, std::size_t offset = 0, std::size_t size = 0) const; void Reset(); - void Reset(VertexDeclarationConstRef vertexDeclaration, BufferRef buffer); - void Reset(VertexDeclarationConstRef vertexDeclaration, BufferRef buffer, std::size_t offset, std::size_t size); - void Reset(VertexDeclarationConstRef vertexDeclaration, std::size_t length, DataStorage storage, BufferUsageFlags usage); + void Reset(std::shared_ptr vertexDeclaration, std::shared_ptr buffer); + void Reset(std::shared_ptr vertexDeclaration, std::shared_ptr buffer, std::size_t offset, std::size_t size); + void Reset(std::shared_ptr vertexDeclaration, std::size_t length, DataStorage storage, BufferUsageFlags usage); void Reset(const VertexBuffer& vertexBuffer); - void SetVertexDeclaration(VertexDeclarationConstRef vertexDeclaration); + void SetVertexDeclaration(std::shared_ptr vertexDeclaration); void Unmap() const; - VertexBuffer& operator=(const VertexBuffer& vertexBuffer); - VertexBuffer& operator=(VertexBuffer&&) = delete; - - template static VertexBufferRef New(Args&&... args); - - // Signals: - NazaraSignal(OnVertexBufferRelease, const VertexBuffer* /*vertexBuffer*/); + VertexBuffer& operator=(const VertexBuffer&) = default; + VertexBuffer& operator=(VertexBuffer&&) noexcept = default; private: - BufferRef m_buffer; + std::shared_ptr m_buffer; + std::shared_ptr m_vertexDeclaration; std::size_t m_endOffset; std::size_t m_startOffset; std::size_t m_vertexCount; - VertexDeclarationConstRef m_vertexDeclaration; }; } diff --git a/include/Nazara/Utility/VertexBuffer.inl b/include/Nazara/Utility/VertexBuffer.inl index 6cf8e8c19..f3f3c6fde 100644 --- a/include/Nazara/Utility/VertexBuffer.inl +++ b/include/Nazara/Utility/VertexBuffer.inl @@ -2,12 +2,13 @@ // This file is part of the "Nazara Engine - Utility module" // For conditions of distribution and use, see copyright notice in Config.hpp +#include #include #include namespace Nz { - inline const BufferRef& VertexBuffer::GetBuffer() const + inline const std::shared_ptr& VertexBuffer::GetBuffer() const { return m_buffer; } @@ -32,23 +33,14 @@ namespace Nz return m_vertexCount; } - inline const VertexDeclarationConstRef& VertexBuffer::GetVertexDeclaration() const + inline const std::shared_ptr& VertexBuffer::GetVertexDeclaration() const { return m_vertexDeclaration; } inline bool VertexBuffer::IsValid() const { - return m_buffer.IsValid() && m_vertexDeclaration.IsValid(); - } - - template - VertexBufferRef VertexBuffer::New(Args&&... args) - { - std::unique_ptr object(new VertexBuffer(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); + return m_buffer && m_vertexDeclaration; } } diff --git a/include/Nazara/Utility/VertexDeclaration.hpp b/include/Nazara/Utility/VertexDeclaration.hpp index 6fc49cdd0..4a9827d8b 100644 --- a/include/Nazara/Utility/VertexDeclaration.hpp +++ b/include/Nazara/Utility/VertexDeclaration.hpp @@ -9,22 +9,19 @@ #include #include -#include -#include #include #include #include #include +#include namespace Nz { class VertexDeclaration; - using VertexDeclarationConstRef = ObjectRef; using VertexDeclarationLibrary = ObjectLibrary; - using VertexDeclarationRef = ObjectRef; - class NAZARA_UTILITY_API VertexDeclaration : public RefCounted + class NAZARA_UTILITY_API VertexDeclaration { friend VertexDeclarationLibrary; friend class Utility; @@ -54,9 +51,8 @@ namespace Nz VertexDeclaration& operator=(const VertexDeclaration&) = delete; VertexDeclaration& operator=(VertexDeclaration&&) = delete; - static inline const VertexDeclarationRef& Get(VertexLayout layout); + static inline const std::shared_ptr& Get(VertexLayout layout); static bool IsTypeSupported(ComponentType type); - template static VertexDeclarationRef New(Args&&... args); struct Component { @@ -81,8 +77,7 @@ namespace Nz std::size_t m_stride; VertexInputRate m_inputRate; - static std::array s_declarations; - static VertexDeclarationLibrary::LibraryMap s_library; + static std::array, VertexLayoutCount> s_declarations; }; } diff --git a/include/Nazara/Utility/VertexDeclaration.inl b/include/Nazara/Utility/VertexDeclaration.inl index df4e9b5a1..b126c562b 100644 --- a/include/Nazara/Utility/VertexDeclaration.inl +++ b/include/Nazara/Utility/VertexDeclaration.inl @@ -12,7 +12,7 @@ namespace Nz { inline auto VertexDeclaration::FindComponent(VertexComponent vertexComponent, std::size_t componentIndex) const -> const Component* { - assert(componentIndex == 0 || vertexComponent == VertexComponent_Userdata); + assert(componentIndex == 0 || vertexComponent == VertexComponent::Userdata); for (const Component& component : m_components) { @@ -56,7 +56,7 @@ namespace Nz template auto VertexDeclaration::GetComponentByType(VertexComponent vertexComponent, std::size_t componentIndex) const -> const Component* { - NazaraAssert(componentIndex == 0 || vertexComponent == VertexComponent_Userdata, "Only userdata vertex component can have component indexes"); + NazaraAssert(componentIndex == 0 || vertexComponent == VertexComponent::Userdata, "Only userdata vertex component can have component indexes"); if (const Component* component = FindComponent(vertexComponent, componentIndex)) { if (GetComponentTypeOf() == component->type) @@ -72,20 +72,11 @@ namespace Nz return GetComponentByType(vertexComponent, componentIndex) != nullptr; } - inline const VertexDeclarationRef& VertexDeclaration::Get(VertexLayout layout) + inline const std::shared_ptr& VertexDeclaration::Get(VertexLayout layout) { - NazaraAssert(layout <= VertexLayout_Max, "Vertex layout out of enum"); + NazaraAssert(layout <= VertexLayout::Max, "Vertex layout out of enum"); - return s_declarations[layout]; - } - - template - VertexDeclarationRef VertexDeclaration::New(Args&&... args) - { - std::unique_ptr object = std::make_unique(std::forward(args)...); - object->SetPersistent(false); - - return object.release(); + return s_declarations[UnderlyingCast(layout)]; } } diff --git a/include/Nazara/Utility/VertexMapper.hpp b/include/Nazara/Utility/VertexMapper.hpp index 39a210b00..c758e057d 100644 --- a/include/Nazara/Utility/VertexMapper.hpp +++ b/include/Nazara/Utility/VertexMapper.hpp @@ -20,10 +20,10 @@ namespace Nz class NAZARA_UTILITY_API VertexMapper { public: - VertexMapper(SubMesh* subMesh, BufferAccess access = BufferAccess_ReadWrite); - VertexMapper(VertexBuffer* vertexBuffer, BufferAccess access = BufferAccess_ReadWrite); - VertexMapper(const SubMesh* subMesh, BufferAccess access = BufferAccess_ReadOnly); - VertexMapper(const VertexBuffer* vertexBuffer, BufferAccess access = BufferAccess_ReadOnly); + VertexMapper(SubMesh& subMesh, BufferAccess access = BufferAccess::ReadWrite); + VertexMapper(VertexBuffer& vertexBuffer, BufferAccess access = BufferAccess::ReadWrite); + VertexMapper(const SubMesh& subMesh, BufferAccess access = BufferAccess::ReadOnly); + VertexMapper(const VertexBuffer& vertexBuffer, BufferAccess access = BufferAccess::ReadOnly); ~VertexMapper(); template SparsePtr GetComponentPtr(VertexComponent component, std::size_t componentIndex = 0); diff --git a/include/Nazara/Utility/VertexMapper.inl b/include/Nazara/Utility/VertexMapper.inl index ddb1015c2..fb704915f 100644 --- a/include/Nazara/Utility/VertexMapper.inl +++ b/include/Nazara/Utility/VertexMapper.inl @@ -13,7 +13,7 @@ namespace Nz SparsePtr VertexMapper::GetComponentPtr(VertexComponent component, std::size_t componentIndex) { // On récupère la déclaration depuis le buffer - const VertexDeclaration* declaration = m_mapper.GetBuffer()->GetVertexDeclaration(); + const std::shared_ptr& declaration = m_mapper.GetBuffer()->GetVertexDeclaration(); if (const auto* componentData = declaration->GetComponentByType(component, componentIndex)) return SparsePtr(static_cast(m_mapper.GetPointer()) + componentData->offset, declaration->GetStride()); diff --git a/include/Nazara/VulkanRenderer.hpp b/include/Nazara/VulkanRenderer.hpp index 7b52637fc..633e24ee4 100644 --- a/include/Nazara/VulkanRenderer.hpp +++ b/include/Nazara/VulkanRenderer.hpp @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/Nazara/VulkanRenderer/Utils.hpp b/include/Nazara/VulkanRenderer/Utils.hpp index c1267da83..77f553d30 100644 --- a/include/Nazara/VulkanRenderer/Utils.hpp +++ b/include/Nazara/VulkanRenderer/Utils.hpp @@ -11,14 +11,25 @@ #include #include #include +#include #include namespace Nz { + inline std::optional FromVulkan(VkFormat format); + + inline VkAttachmentLoadOp ToVulkan(AttachmentLoadOp loadOp); + inline VkAttachmentStoreOp ToVulkan(AttachmentStoreOp storeOp); inline VkBufferUsageFlags ToVulkan(BufferType bufferType); inline VkFormat ToVulkan(ComponentType componentType); inline VkCullModeFlagBits ToVulkan(FaceSide faceSide); inline VkPolygonMode ToVulkan(FaceFilling faceFilling); + inline VkFrontFace ToVulkan(FrontFace frontFace); + inline VkAccessFlagBits ToVulkan(MemoryAccess memoryAccess); + inline VkAccessFlags ToVulkan(MemoryAccessFlags memoryAccessFlags); + inline VkPipelineStageFlagBits ToVulkan(PipelineStage pipelineStage); + inline VkPipelineStageFlags ToVulkan(PipelineStageFlags pipelineStages); + inline VkFormat ToVulkan(PixelFormat pixelFormat); inline VkPrimitiveTopology ToVulkan(PrimitiveMode primitiveMode); inline VkCompareOp ToVulkan(RendererComparison comparison); inline VkFilter ToVulkan(SamplerFilter samplerFilter); @@ -28,6 +39,9 @@ namespace Nz inline VkShaderStageFlagBits ToVulkan(ShaderStageType stageType); inline VkShaderStageFlags ToVulkan(ShaderStageTypeFlags stageType); inline VkStencilOp ToVulkan(StencilOperation stencilOp); + inline VkImageLayout ToVulkan(TextureLayout textureLayout); + inline VkImageUsageFlagBits ToVulkan(TextureUsage textureLayout); + inline VkImageUsageFlags ToVulkan(TextureUsageFlags textureLayout); inline VkVertexInputRate ToVulkan(VertexInputRate inputRate); NAZARA_VULKANRENDERER_API std::string TranslateVulkanError(VkResult code); diff --git a/include/Nazara/VulkanRenderer/Utils.inl b/include/Nazara/VulkanRenderer/Utils.inl index 242e7c6e0..ddd91133e 100644 --- a/include/Nazara/VulkanRenderer/Utils.inl +++ b/include/Nazara/VulkanRenderer/Utils.inl @@ -10,16 +10,99 @@ namespace Nz { + inline std::optional FromVulkan(VkFormat format) + { + switch (format) + { + case VK_FORMAT_B8G8R8A8_UNORM: return PixelFormat::BGRA8; + case VK_FORMAT_B8G8R8A8_SRGB: return PixelFormat::BGRA8_SRGB; + case VK_FORMAT_D16_UNORM: return PixelFormat::Depth16; + case VK_FORMAT_D16_UNORM_S8_UINT: return PixelFormat::Depth16Stencil8; + case VK_FORMAT_D24_UNORM_S8_UINT: return PixelFormat::Depth24Stencil8; + case VK_FORMAT_D32_SFLOAT: return PixelFormat::Depth32F; + case VK_FORMAT_D32_SFLOAT_S8_UINT: return PixelFormat::Depth32FStencil8; + case VK_FORMAT_R8G8B8A8_UNORM: return PixelFormat::RGBA8; + case VK_FORMAT_R8G8B8A8_SRGB: return PixelFormat::RGBA8_SRGB; + default: break; + } + + return std::nullopt; + } + + inline VkAttachmentLoadOp ToVulkan(AttachmentLoadOp loadOp) + { + switch (loadOp) + { + case AttachmentLoadOp::Clear: return VK_ATTACHMENT_LOAD_OP_CLEAR; + case AttachmentLoadOp::Discard: return VK_ATTACHMENT_LOAD_OP_DONT_CARE; + case AttachmentLoadOp::Load: return VK_ATTACHMENT_LOAD_OP_LOAD; + } + + NazaraError("Unhandled AttachmentLoadOp 0x" + NumberToString(UnderlyingCast(loadOp), 16)); + return {}; + } + + inline VkAttachmentStoreOp ToVulkan(AttachmentStoreOp storeOp) + { + switch (storeOp) + { + case AttachmentStoreOp::Discard: return VK_ATTACHMENT_STORE_OP_DONT_CARE; + case AttachmentStoreOp::Store: return VK_ATTACHMENT_STORE_OP_STORE; + } + + NazaraError("Unhandled AttachmentStoreOp 0x" + NumberToString(UnderlyingCast(storeOp), 16)); + return {}; + } + + inline VkBlendOp ToVulkan(BlendEquation blendEquation) + { + switch (blendEquation) + { + case BlendEquation::Add: return VK_BLEND_OP_ADD; + case BlendEquation::Max: return VK_BLEND_OP_MAX; + case BlendEquation::Min: return VK_BLEND_OP_MIN; + case BlendEquation::ReverseSubtract: return VK_BLEND_OP_REVERSE_SUBTRACT; + case BlendEquation::Subtract: return VK_BLEND_OP_SUBTRACT; + } + + NazaraError("Unhandled BlendEquation 0x" + NumberToString(UnderlyingCast(blendEquation), 16)); + return {}; + } + + inline VkBlendFactor ToVulkan(BlendFunc blendFunc) + { + switch (blendFunc) + { + case BlendFunc::ConstantAlpha: return VK_BLEND_FACTOR_CONSTANT_ALPHA; + case BlendFunc::ConstantColor: return VK_BLEND_FACTOR_CONSTANT_COLOR; + case BlendFunc::DstAlpha: return VK_BLEND_FACTOR_DST_ALPHA; + case BlendFunc::DstColor: return VK_BLEND_FACTOR_DST_COLOR; + case BlendFunc::InvConstantAlpha: return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA; + case BlendFunc::InvConstantColor: return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR; + case BlendFunc::InvDstAlpha: return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA; + case BlendFunc::InvDstColor: return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR; + case BlendFunc::InvSrcAlpha: return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + case BlendFunc::InvSrcColor: return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR; + case BlendFunc::SrcAlpha: return VK_BLEND_FACTOR_SRC_ALPHA; + case BlendFunc::SrcColor: return VK_BLEND_FACTOR_SRC_COLOR; + case BlendFunc::One: return VK_BLEND_FACTOR_ONE; + case BlendFunc::Zero: return VK_BLEND_FACTOR_ZERO; + } + + NazaraError("Unhandled BlendFunc 0x" + NumberToString(UnderlyingCast(blendFunc), 16)); + return {}; + } + inline VkBufferUsageFlags ToVulkan(BufferType bufferType) { switch (bufferType) { - case BufferType_Index: return VK_BUFFER_USAGE_INDEX_BUFFER_BIT; - case BufferType_Vertex: return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; - case BufferType_Uniform: return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + case BufferType::Index: return VK_BUFFER_USAGE_INDEX_BUFFER_BIT; + case BufferType::Vertex: return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + case BufferType::Uniform: return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; } - NazaraError("Unhandled BufferType 0x" + NumberToString(bufferType, 16)); + NazaraError("Unhandled BufferType 0x" + NumberToString(UnderlyingCast(bufferType), 16)); return 0; } @@ -27,23 +110,23 @@ namespace Nz { switch (componentType) { - case ComponentType_Color: return VK_FORMAT_R8G8B8A8_UINT; - case ComponentType_Double1: return VK_FORMAT_R64_SFLOAT; - case ComponentType_Double2: return VK_FORMAT_R64G64_SFLOAT; - case ComponentType_Double3: return VK_FORMAT_R64G64B64_SFLOAT; - case ComponentType_Double4: return VK_FORMAT_R64G64B64A64_SFLOAT; - case ComponentType_Float1: return VK_FORMAT_R32_SFLOAT; - case ComponentType_Float2: return VK_FORMAT_R32G32_SFLOAT; - case ComponentType_Float3: return VK_FORMAT_R32G32B32_SFLOAT; - case ComponentType_Float4: return VK_FORMAT_R32G32B32A32_SFLOAT; - case ComponentType_Int1: return VK_FORMAT_R32_SINT; - case ComponentType_Int2: return VK_FORMAT_R32G32_SINT; - case ComponentType_Int3: return VK_FORMAT_R32G32B32_SINT; - case ComponentType_Int4: return VK_FORMAT_R32G32B32A32_SINT; - case ComponentType_Quaternion: return VK_FORMAT_R32G32B32A32_SFLOAT; + case ComponentType::Color: return VK_FORMAT_R8G8B8A8_UINT; + case ComponentType::Double1: return VK_FORMAT_R64_SFLOAT; + case ComponentType::Double2: return VK_FORMAT_R64G64_SFLOAT; + case ComponentType::Double3: return VK_FORMAT_R64G64B64_SFLOAT; + case ComponentType::Double4: return VK_FORMAT_R64G64B64A64_SFLOAT; + case ComponentType::Float1: return VK_FORMAT_R32_SFLOAT; + case ComponentType::Float2: return VK_FORMAT_R32G32_SFLOAT; + case ComponentType::Float3: return VK_FORMAT_R32G32B32_SFLOAT; + case ComponentType::Float4: return VK_FORMAT_R32G32B32A32_SFLOAT; + case ComponentType::Int1: return VK_FORMAT_R32_SINT; + case ComponentType::Int2: return VK_FORMAT_R32G32_SINT; + case ComponentType::Int3: return VK_FORMAT_R32G32B32_SINT; + case ComponentType::Int4: return VK_FORMAT_R32G32B32A32_SINT; + case ComponentType::Quaternion: return VK_FORMAT_R32G32B32A32_SFLOAT; } - NazaraError("Unhandled ComponentType 0x" + NumberToString(componentType, 16)); + NazaraError("Unhandled ComponentType 0x" + NumberToString(UnderlyingCast(componentType), 16)); return VK_FORMAT_UNDEFINED; } @@ -51,13 +134,13 @@ namespace Nz { switch (faceSide) { - case FaceSide_None: return VK_CULL_MODE_NONE; - case FaceSide_Back: return VK_CULL_MODE_BACK_BIT; - case FaceSide_Front: return VK_CULL_MODE_FRONT_BIT; - case FaceSide_FrontAndBack: return VK_CULL_MODE_FRONT_AND_BACK; + case FaceSide::None: return VK_CULL_MODE_NONE; + case FaceSide::Back: return VK_CULL_MODE_BACK_BIT; + case FaceSide::Front: return VK_CULL_MODE_FRONT_BIT; + case FaceSide::FrontAndBack: return VK_CULL_MODE_FRONT_AND_BACK; } - NazaraError("Unhandled FaceSide 0x" + NumberToString(faceSide, 16)); + NazaraError("Unhandled FaceSide 0x" + NumberToString(UnderlyingCast(faceSide), 16)); return VK_CULL_MODE_BACK_BIT; } @@ -65,28 +148,137 @@ namespace Nz { switch (faceFilling) { - case FaceFilling_Fill: return VK_POLYGON_MODE_FILL; - case FaceFilling_Line: return VK_POLYGON_MODE_LINE; - case FaceFilling_Point: return VK_POLYGON_MODE_POINT; + case FaceFilling::Fill: return VK_POLYGON_MODE_FILL; + case FaceFilling::Line: return VK_POLYGON_MODE_LINE; + case FaceFilling::Point: return VK_POLYGON_MODE_POINT; } - NazaraError("Unhandled FaceFilling 0x" + NumberToString(faceFilling, 16)); + NazaraError("Unhandled FaceFilling 0x" + NumberToString(UnderlyingCast(faceFilling), 16)); return VK_POLYGON_MODE_FILL; } + inline VkFrontFace ToVulkan(FrontFace frontFace) + { + switch (frontFace) + { + case FrontFace::Clockwise: return VK_FRONT_FACE_CLOCKWISE; + case FrontFace::CounterClockwise: return VK_FRONT_FACE_COUNTER_CLOCKWISE; + } + + NazaraError("Unhandled FrontFace 0x" + NumberToString(UnderlyingCast(frontFace), 16)); + return {}; + } + + inline VkAccessFlagBits ToVulkan(MemoryAccess memoryAccess) + { + switch (memoryAccess) + { + case MemoryAccess::ColorRead: return VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; + case MemoryAccess::ColorWrite: return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + case MemoryAccess::DepthStencilRead: return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; + case MemoryAccess::DepthStencilWrite: return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + case MemoryAccess::IndexBufferRead: return VK_ACCESS_INDEX_READ_BIT; + case MemoryAccess::IndirectCommandRead: return VK_ACCESS_INDIRECT_COMMAND_READ_BIT; + case MemoryAccess::HostRead: return VK_ACCESS_HOST_READ_BIT; + case MemoryAccess::HostWrite: return VK_ACCESS_HOST_WRITE_BIT; + case MemoryAccess::MemoryRead: return VK_ACCESS_MEMORY_READ_BIT; + case MemoryAccess::MemoryWrite: return VK_ACCESS_MEMORY_WRITE_BIT; + case MemoryAccess::ShaderRead: return VK_ACCESS_SHADER_READ_BIT; + case MemoryAccess::ShaderWrite: return VK_ACCESS_SHADER_WRITE_BIT; + case MemoryAccess::TransferRead: return VK_ACCESS_TRANSFER_READ_BIT; + case MemoryAccess::TransferWrite: return VK_ACCESS_TRANSFER_WRITE_BIT; + case MemoryAccess::UniformBufferRead: return VK_ACCESS_UNIFORM_READ_BIT; + case MemoryAccess::VertexBufferRead: return VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; + } + + NazaraError("Unhandled MemoryAccess 0x" + NumberToString(UnderlyingCast(memoryAccess), 16)); + return {}; + } + + inline VkAccessFlags ToVulkan(MemoryAccessFlags memoryAccessFlags) + { + VkShaderStageFlags accessBits = 0; + for (int i = 0; i <= UnderlyingCast(MemoryAccess::Max); ++i) + { + MemoryAccess memoryAccess = static_cast(i); + if (memoryAccessFlags.Test(memoryAccess)) + accessBits |= ToVulkan(memoryAccess); + } + + return accessBits; + } + + inline VkPipelineStageFlagBits ToVulkan(PipelineStage pipelineStage) + { + switch (pipelineStage) + { + case PipelineStage::TopOfPipe: return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + case PipelineStage::ColorOutput: return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + case PipelineStage::DrawIndirect: return VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; + case PipelineStage::FragmentShader: return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + case PipelineStage::FragmentTestsEarly: return VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + case PipelineStage::FragmentTestsLate: return VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + case PipelineStage::GeometryShader: return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT; + case PipelineStage::TessellationControlShader: return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT; + case PipelineStage::TessellationEvaluationShader: return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT; + case PipelineStage::Transfer: return VK_PIPELINE_STAGE_TRANSFER_BIT; + case PipelineStage::TransformFeedback: return VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT; + case PipelineStage::VertexInput: return VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; + case PipelineStage::VertexShader: return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT; + case PipelineStage::BottomOfPipe: return VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + } + + NazaraError("Unhandled PipelineStage 0x" + NumberToString(UnderlyingCast(pipelineStage), 16)); + return {}; + } + + inline VkPipelineStageFlags ToVulkan(PipelineStageFlags pipelineStages) + { + VkShaderStageFlags pipelineStageBits = 0; + for (int i = 0; i <= UnderlyingCast(PipelineStage::Max); ++i) + { + PipelineStage pipelineStage = static_cast(i); + if (pipelineStages.Test(pipelineStage)) + pipelineStageBits |= ToVulkan(pipelineStage); + } + + return pipelineStageBits; + } + + inline VkFormat ToVulkan(PixelFormat pixelFormat) + { + switch (pixelFormat) + { + case PixelFormat::BGRA8: return VK_FORMAT_B8G8R8A8_UNORM; + case PixelFormat::BGRA8_SRGB: return VK_FORMAT_B8G8R8A8_SRGB; + case PixelFormat::Depth16: return VK_FORMAT_D16_UNORM; + case PixelFormat::Depth16Stencil8: return VK_FORMAT_D16_UNORM_S8_UINT; + case PixelFormat::Depth24Stencil8: return VK_FORMAT_D24_UNORM_S8_UINT; + case PixelFormat::Depth32F: return VK_FORMAT_D32_SFLOAT; + case PixelFormat::Depth32FStencil8: return VK_FORMAT_D32_SFLOAT_S8_UINT; + case PixelFormat::RGBA8: return VK_FORMAT_R8G8B8A8_UNORM; + case PixelFormat::RGBA8_SRGB: return VK_FORMAT_R8G8B8A8_SRGB; + case PixelFormat::RGBA32F: return VK_FORMAT_R32G32B32A32_SFLOAT; + default: break; + } + + NazaraError("Unhandled PixelFormat 0x" + NumberToString(UnderlyingCast(pixelFormat), 16)); + return {}; + } + inline VkPrimitiveTopology ToVulkan(PrimitiveMode primitiveMode) { switch (primitiveMode) { - case PrimitiveMode_LineList: return VK_PRIMITIVE_TOPOLOGY_LINE_LIST; - case PrimitiveMode_LineStrip: return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; - case PrimitiveMode_PointList: return VK_PRIMITIVE_TOPOLOGY_POINT_LIST; - case PrimitiveMode_TriangleList: return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - case PrimitiveMode_TriangleStrip: return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; - case PrimitiveMode_TriangleFan: return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN; + case PrimitiveMode::LineList: return VK_PRIMITIVE_TOPOLOGY_LINE_LIST; + case PrimitiveMode::LineStrip: return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; + case PrimitiveMode::PointList: return VK_PRIMITIVE_TOPOLOGY_POINT_LIST; + case PrimitiveMode::TriangleList: return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + case PrimitiveMode::TriangleStrip: return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + case PrimitiveMode::TriangleFan: return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN; } - NazaraError("Unhandled FaceFilling 0x" + NumberToString(primitiveMode, 16)); + NazaraError("Unhandled FaceFilling 0x" + NumberToString(UnderlyingCast(primitiveMode), 16)); return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; } @@ -94,17 +286,17 @@ namespace Nz { switch (comparison) { - case RendererComparison_Never: return VK_COMPARE_OP_NEVER; - case RendererComparison_Less: return VK_COMPARE_OP_LESS; - case RendererComparison_Equal: return VK_COMPARE_OP_EQUAL; - case RendererComparison_LessOrEqual: return VK_COMPARE_OP_LESS_OR_EQUAL; - case RendererComparison_Greater: return VK_COMPARE_OP_GREATER; - case RendererComparison_NotEqual: return VK_COMPARE_OP_NOT_EQUAL; - case RendererComparison_GreaterOrEqual: return VK_COMPARE_OP_GREATER_OR_EQUAL; - case RendererComparison_Always: return VK_COMPARE_OP_ALWAYS; + case RendererComparison::Never: return VK_COMPARE_OP_NEVER; + case RendererComparison::Less: return VK_COMPARE_OP_LESS; + case RendererComparison::Equal: return VK_COMPARE_OP_EQUAL; + case RendererComparison::LessOrEqual: return VK_COMPARE_OP_LESS_OR_EQUAL; + case RendererComparison::Greater: return VK_COMPARE_OP_GREATER; + case RendererComparison::NotEqual: return VK_COMPARE_OP_NOT_EQUAL; + case RendererComparison::GreaterOrEqual: return VK_COMPARE_OP_GREATER_OR_EQUAL; + case RendererComparison::Always: return VK_COMPARE_OP_ALWAYS; } - NazaraError("Unhandled RendererComparison 0x" + NumberToString(comparison, 16)); + NazaraError("Unhandled RendererComparison 0x" + NumberToString(UnderlyingCast(comparison), 16)); return VK_COMPARE_OP_NEVER; } @@ -112,8 +304,8 @@ namespace Nz { switch (samplerFilter) { - case SamplerFilter_Linear: return VK_FILTER_LINEAR; - case SamplerFilter_Nearest: return VK_FILTER_NEAREST; + case SamplerFilter::Linear: return VK_FILTER_LINEAR; + case SamplerFilter::Nearest: return VK_FILTER_NEAREST; } NazaraError("Unhandled SamplerFilter 0x" + NumberToString(UnderlyingCast(samplerFilter), 16)); @@ -124,8 +316,8 @@ namespace Nz { switch (samplerMipmap) { - case SamplerMipmapMode_Linear: return VK_SAMPLER_MIPMAP_MODE_LINEAR; - case SamplerMipmapMode_Nearest: return VK_SAMPLER_MIPMAP_MODE_NEAREST; + case SamplerMipmapMode::Linear: return VK_SAMPLER_MIPMAP_MODE_LINEAR; + case SamplerMipmapMode::Nearest: return VK_SAMPLER_MIPMAP_MODE_NEAREST; } NazaraError("Unhandled SamplerMipmapMode 0x" + NumberToString(UnderlyingCast(samplerMipmap), 16)); @@ -136,9 +328,9 @@ namespace Nz { switch (samplerWrap) { - case SamplerWrap_Clamp: return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - case SamplerWrap_MirroredRepeat: return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; - case SamplerWrap_Repeat: return VK_SAMPLER_ADDRESS_MODE_REPEAT; + case SamplerWrap::Clamp: return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + case SamplerWrap::MirroredRepeat: return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; + case SamplerWrap::Repeat: return VK_SAMPLER_ADDRESS_MODE_REPEAT; } NazaraError("Unhandled SamplerWrap 0x" + NumberToString(UnderlyingCast(samplerWrap), 16)); @@ -172,14 +364,12 @@ namespace Nz inline VkShaderStageFlags ToVulkan(ShaderStageTypeFlags stageType) { VkShaderStageFlags shaderStageBits = 0; - - if (stageType.Test(ShaderStageType::Fragment)) - shaderStageBits |= VK_SHADER_STAGE_FRAGMENT_BIT; - - if (stageType.Test(ShaderStageType::Vertex)) - shaderStageBits |= VK_SHADER_STAGE_VERTEX_BIT; - - static_assert(UnderlyingCast(ShaderStageType::Max) + 1 == 2); + for (int i = 0; i <= UnderlyingCast(ShaderStageType::Max); ++i) + { + ShaderStageType shaderStage = static_cast(i); + if (stageType.Test(shaderStage)) + shaderStageBits |= ToVulkan(shaderStage); + } return shaderStageBits; } @@ -188,18 +378,65 @@ namespace Nz { switch (stencilOp) { - case StencilOperation_Decrement: return VK_STENCIL_OP_DECREMENT_AND_CLAMP; - case StencilOperation_DecrementNoClamp: return VK_STENCIL_OP_DECREMENT_AND_WRAP; - case StencilOperation_Increment: return VK_STENCIL_OP_INCREMENT_AND_CLAMP; - case StencilOperation_IncrementNoClamp: return VK_STENCIL_OP_INCREMENT_AND_WRAP; - case StencilOperation_Invert: return VK_STENCIL_OP_INVERT; - case StencilOperation_Keep: return VK_STENCIL_OP_KEEP; - case StencilOperation_Replace: return VK_STENCIL_OP_REPLACE; - case StencilOperation_Zero: return VK_STENCIL_OP_ZERO; + case StencilOperation::Decrement: return VK_STENCIL_OP_DECREMENT_AND_CLAMP; + case StencilOperation::DecrementNoClamp: return VK_STENCIL_OP_DECREMENT_AND_WRAP; + case StencilOperation::Increment: return VK_STENCIL_OP_INCREMENT_AND_CLAMP; + case StencilOperation::IncrementNoClamp: return VK_STENCIL_OP_INCREMENT_AND_WRAP; + case StencilOperation::Invert: return VK_STENCIL_OP_INVERT; + case StencilOperation::Keep: return VK_STENCIL_OP_KEEP; + case StencilOperation::Replace: return VK_STENCIL_OP_REPLACE; + case StencilOperation::Zero: return VK_STENCIL_OP_ZERO; } - NazaraError("Unhandled RendererComparison 0x" + NumberToString(stencilOp, 16)); - return VK_STENCIL_OP_KEEP; + NazaraError("Unhandled StencilOperation 0x" + NumberToString(UnderlyingCast(stencilOp), 16)); + return {}; + } + + inline VkImageLayout ToVulkan(TextureLayout textureLayout) + { + switch (textureLayout) + { + case TextureLayout::ColorInput: return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + case TextureLayout::ColorOutput: return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + case TextureLayout::DepthStencilReadOnly: return VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + case TextureLayout::DepthStencilReadWrite: return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + case TextureLayout::Present: return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + case TextureLayout::TransferSource: return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + case TextureLayout::TransferDestination: return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + case TextureLayout::Undefined: return VK_IMAGE_LAYOUT_UNDEFINED; + } + + NazaraError("Unhandled TextureLayout 0x" + NumberToString(UnderlyingCast(textureLayout), 16)); + return {}; + } + + inline VkImageUsageFlagBits ToVulkan(TextureUsage textureLayout) + { + switch (textureLayout) + { + case TextureUsage::ColorAttachment: return VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + case TextureUsage::DepthStencilAttachment: return VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + case TextureUsage::InputAttachment: return VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; + case TextureUsage::ShaderSampling: return VK_IMAGE_USAGE_SAMPLED_BIT; + case TextureUsage::TransferSource: return VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + case TextureUsage::TransferDestination: return VK_IMAGE_USAGE_TRANSFER_DST_BIT; + } + + NazaraError("Unhandled TextureUsage 0x" + NumberToString(UnderlyingCast(textureLayout), 16)); + return {}; + } + + inline VkImageUsageFlags ToVulkan(TextureUsageFlags textureLayout) + { + VkImageUsageFlags imageUsageBits = 0; + for (int i = 0; i <= UnderlyingCast(TextureUsage::Max); ++i) + { + TextureUsage textureUsage = static_cast(i); + if (textureLayout.Test(textureUsage)) + imageUsageBits |= ToVulkan(textureUsage); + } + + return imageUsageBits; } inline VkVertexInputRate ToVulkan(VertexInputRate inputRate) @@ -211,7 +448,7 @@ namespace Nz } NazaraError("Unhandled VertexInputRate 0x" + NumberToString(UnderlyingCast(inputRate), 16)); - return VK_VERTEX_INPUT_RATE_VERTEX; + return {}; } } diff --git a/include/Nazara/VulkanRenderer/VkRenderWindow.hpp b/include/Nazara/VulkanRenderer/VkRenderWindow.hpp index c14fc640d..98d8a238a 100644 --- a/include/Nazara/VulkanRenderer/VkRenderWindow.hpp +++ b/include/Nazara/VulkanRenderer/VkRenderWindow.hpp @@ -55,8 +55,6 @@ namespace Nz inline const VulkanRenderPass& GetRenderPass() const override; inline const Vk::Swapchain& GetSwapchain() const; - inline std::shared_ptr GetRenderDevice() override; - void Present(UInt32 imageIndex, VkSemaphore waitSemaphore = VK_NULL_HANDLE); VkRenderWindow& operator=(const VkRenderWindow&) = delete; @@ -74,7 +72,7 @@ namespace Nz std::shared_ptr m_device; std::size_t m_currentFrame; std::vector m_inflightFences; - std::vector m_concurrentImageData; + std::vector> m_concurrentImageData; Vk::DeviceMemory m_depthBufferMemory; Vk::Image m_depthBuffer; Vk::ImageView m_depthBufferView; diff --git a/include/Nazara/VulkanRenderer/VkRenderWindow.inl b/include/Nazara/VulkanRenderer/VkRenderWindow.inl index 5daff2463..e108bc8ac 100644 --- a/include/Nazara/VulkanRenderer/VkRenderWindow.inl +++ b/include/Nazara/VulkanRenderer/VkRenderWindow.inl @@ -36,11 +36,6 @@ namespace Nz { return m_swapchain; } - - inline std::shared_ptr VkRenderWindow::GetRenderDevice() - { - return m_device; - } } #include diff --git a/include/Nazara/VulkanRenderer/Vulkan.hpp b/include/Nazara/VulkanRenderer/Vulkan.hpp index 12db5feb9..44368576e 100644 --- a/include/Nazara/VulkanRenderer/Vulkan.hpp +++ b/include/Nazara/VulkanRenderer/Vulkan.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,8 @@ namespace Nz Vulkan() = delete; ~Vulkan() = delete; + static RenderDeviceInfo BuildRenderDeviceInfo(const Vk::PhysicalDevice& physDevice); + static std::shared_ptr CreateDevice(const Vk::PhysicalDevice& deviceInfo); static std::shared_ptr CreateDevice(const Vk::PhysicalDevice& deviceInfo, const Vk::Surface& surface, UInt32* graphicsFamilyIndex, UInt32* presentableFamilyIndex, UInt32* transferFamilyIndex); static std::shared_ptr CreateDevice(const Vk::PhysicalDevice& deviceInfo, const QueueFamily* queueFamilies, std::size_t queueFamilyCount); @@ -43,7 +46,7 @@ namespace Nz static const std::vector& GetPhysicalDevices(); static const Vk::PhysicalDevice& GetPhysicalDeviceInfo(VkPhysicalDevice physDevice); - + static bool Initialize(UInt32 targetApiVersion, const ParameterList& parameters); static bool IsInitialized(); diff --git a/include/Nazara/VulkanRenderer/VulkanCommandBuffer.inl b/include/Nazara/VulkanRenderer/VulkanCommandBuffer.inl index 27e99bce8..16397ccc3 100644 --- a/include/Nazara/VulkanRenderer/VulkanCommandBuffer.inl +++ b/include/Nazara/VulkanRenderer/VulkanCommandBuffer.inl @@ -33,6 +33,10 @@ namespace Nz inline Vk::CommandBuffer& VulkanCommandBuffer::GetCommandBuffer(std::size_t imageIndex) { + if (m_commandBuffers.size() == 1) + return m_commandBuffers.front(); + + assert(imageIndex < m_commandBuffers.size()); return m_commandBuffers[imageIndex].Get(); } diff --git a/include/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.hpp b/include/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.hpp index 7fd23ee13..a3c8173a2 100644 --- a/include/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.hpp +++ b/include/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.hpp @@ -25,7 +25,7 @@ namespace Nz ~VulkanCommandBufferBuilder() = default; void BeginDebugRegion(const std::string_view& regionName, const Nz::Color& color) override; - void BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect, std::initializer_list clearValues) override; + void BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect, const ClearValues* clearValues, std::size_t clearValueCount) override; void BindIndexBuffer(AbstractBuffer* indexBuffer, UInt64 offset = 0) override; void BindPipeline(const RenderPipeline& pipeline) override; @@ -44,18 +44,23 @@ namespace Nz inline Vk::CommandBuffer& GetCommandBuffer(); inline std::size_t GetMaxFramebufferCount() const; + void NextSubpass() override; + void PreTransferBarrier() override; void PostTransferBarrier() override; void SetScissor(Nz::Recti scissorRegion) override; void SetViewport(Nz::Recti viewportRegion) override; + void TextureBarrier(PipelineStageFlags srcStageMask, PipelineStageFlags dstStageMask, MemoryAccessFlags srcAccessMask, MemoryAccessFlags dstAccessMask, TextureLayout oldLayout, TextureLayout newLayout, const Texture& texture) override; + VulkanCommandBufferBuilder& operator=(const VulkanCommandBufferBuilder&) = delete; VulkanCommandBufferBuilder& operator=(VulkanCommandBufferBuilder&&) = delete; private: Vk::CommandBuffer& m_commandBuffer; const VulkanRenderPass* m_currentRenderPass; + std::size_t m_currentSubpassIndex; std::size_t m_framebufferCount; std::size_t m_imageIndex; }; diff --git a/include/Nazara/VulkanRenderer/VulkanDevice.hpp b/include/Nazara/VulkanRenderer/VulkanDevice.hpp index b7d8e095c..882720ca1 100644 --- a/include/Nazara/VulkanRenderer/VulkanDevice.hpp +++ b/include/Nazara/VulkanRenderer/VulkanDevice.hpp @@ -18,21 +18,31 @@ namespace Nz class NAZARA_VULKANRENDERER_API VulkanDevice : public RenderDevice, public Vk::Device { public: - using Device::Device; + inline VulkanDevice(Vk::Instance& instance, RenderDeviceInfo renderDeviceInfo); VulkanDevice(const VulkanDevice&) = delete; VulkanDevice(VulkanDevice&&) = delete; ///TODO? ~VulkanDevice(); + const RenderDeviceInfo& GetDeviceInfo() const override; + std::shared_ptr InstantiateBuffer(BufferType type) override; std::shared_ptr InstantiateCommandPool(QueueType queueType) override; + std::shared_ptr InstantiateFramebuffer(unsigned int width, unsigned int height, const std::shared_ptr& renderPass, const std::vector>& attachments) override; + std::shared_ptr InstantiateRenderPass(std::vector attachments, std::vector subpassDescriptions, std::vector subpassDependencies) override; std::shared_ptr InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) override; std::shared_ptr InstantiateRenderPipelineLayout(RenderPipelineLayoutInfo pipelineLayoutInfo) override; - std::shared_ptr InstantiateShaderStage(ShaderStageType type, ShaderLanguage lang, const void* source, std::size_t sourceSize) override; + std::shared_ptr InstantiateShaderModule(ShaderStageTypeFlags stages, ShaderAst::StatementPtr& shaderAst, const ShaderWriter::States& states) override; + std::shared_ptr InstantiateShaderModule(ShaderStageTypeFlags stages, ShaderLanguage lang, const void* source, std::size_t sourceSize, const ShaderWriter::States& states) override; std::shared_ptr InstantiateTexture(const TextureInfo& params) override; std::shared_ptr InstantiateTextureSampler(const TextureSamplerInfo& params) override; + bool IsTextureFormatSupported(PixelFormat format, TextureUsage usage) const override; + VulkanDevice& operator=(const VulkanDevice&) = delete; VulkanDevice& operator=(VulkanDevice&&) = delete; ///TODO? + + private: + RenderDeviceInfo m_renderDeviceInfo; }; } diff --git a/include/Nazara/VulkanRenderer/VulkanDevice.inl b/include/Nazara/VulkanRenderer/VulkanDevice.inl index dd44f8b19..6c5f8a58b 100644 --- a/include/Nazara/VulkanRenderer/VulkanDevice.inl +++ b/include/Nazara/VulkanRenderer/VulkanDevice.inl @@ -7,6 +7,11 @@ namespace Nz { + inline VulkanDevice::VulkanDevice(Vk::Instance& instance, RenderDeviceInfo renderDeviceInfo) : + Device(instance), + m_renderDeviceInfo(std::move(renderDeviceInfo)) + { + } } #include diff --git a/include/Nazara/VulkanRenderer/VulkanRenderImage.hpp b/include/Nazara/VulkanRenderer/VulkanRenderImage.hpp index f7033b799..ecbd3c7c9 100644 --- a/include/Nazara/VulkanRenderer/VulkanRenderImage.hpp +++ b/include/Nazara/VulkanRenderer/VulkanRenderImage.hpp @@ -36,13 +36,13 @@ namespace Nz inline Vk::Semaphore& GetRenderFinishedSemaphore(); VulkanUploadPool& GetUploadPool() override; - void SubmitCommandBuffer(CommandBuffer* commandBuffer, QueueTypeFlags queueTypeFlags) override; - void SubmitCommandBuffer(VkCommandBuffer commandBuffer, QueueTypeFlags queueTypeFlags); - void Present() override; inline void Reset(UInt32 imageIndex); + void SubmitCommandBuffer(CommandBuffer* commandBuffer, QueueTypeFlags queueTypeFlags) override; + void SubmitCommandBuffer(VkCommandBuffer commandBuffer, QueueTypeFlags queueTypeFlags); + VulkanRenderImage& operator=(const VulkanRenderImage&) = delete; VulkanRenderImage& operator=(VulkanRenderImage&&) = delete; diff --git a/include/Nazara/VulkanRenderer/VulkanRenderImage.inl b/include/Nazara/VulkanRenderer/VulkanRenderImage.inl index 521233611..d1feba2a9 100644 --- a/include/Nazara/VulkanRenderer/VulkanRenderImage.inl +++ b/include/Nazara/VulkanRenderer/VulkanRenderImage.inl @@ -7,7 +7,7 @@ namespace Nz { - inline Vk::Fence& Nz::VulkanRenderImage::GetInFlightFence() + inline Vk::Fence& VulkanRenderImage::GetInFlightFence() { return m_inFlightFence; } @@ -29,6 +29,8 @@ namespace Nz inline void VulkanRenderImage::Reset(UInt32 imageIndex) { + FlushReleaseQueue(); + m_graphicalCommandsBuffers.clear(); m_currentCommandBuffer = 0; m_imageIndex = imageIndex; diff --git a/include/Nazara/VulkanRenderer/VulkanRenderPass.hpp b/include/Nazara/VulkanRenderer/VulkanRenderPass.hpp index 87bc54fa9..7b66c1bcb 100644 --- a/include/Nazara/VulkanRenderer/VulkanRenderPass.hpp +++ b/include/Nazara/VulkanRenderer/VulkanRenderPass.hpp @@ -18,12 +18,11 @@ namespace Nz class NAZARA_VULKANRENDERER_API VulkanRenderPass final : public RenderPass { public: - inline VulkanRenderPass(Vk::RenderPass renderPass, std::initializer_list formats); //< FIXME + VulkanRenderPass(Vk::Device& device, std::vector attachments, std::vector subpassDescriptions, std::vector subpassDependencies); VulkanRenderPass(const VulkanRenderPass&) = delete; VulkanRenderPass(VulkanRenderPass&&) noexcept = default; ~VulkanRenderPass() = default; - inline PixelFormat GetAttachmentFormat(std::size_t attachmentIndex) const; inline Vk::RenderPass& GetRenderPass(); inline const Vk::RenderPass& GetRenderPass() const; @@ -31,7 +30,6 @@ namespace Nz VulkanRenderPass& operator=(VulkanRenderPass&&) noexcept = default; private: - std::vector m_formats; Vk::RenderPass m_renderPass; }; } diff --git a/include/Nazara/VulkanRenderer/VulkanRenderPass.inl b/include/Nazara/VulkanRenderer/VulkanRenderPass.inl index d21e1a67c..ce153800d 100644 --- a/include/Nazara/VulkanRenderer/VulkanRenderPass.inl +++ b/include/Nazara/VulkanRenderer/VulkanRenderPass.inl @@ -7,17 +7,6 @@ namespace Nz { - inline VulkanRenderPass::VulkanRenderPass(Vk::RenderPass renderPass, std::initializer_list formats) : - m_formats(std::begin(formats), std::end(formats)), - m_renderPass(std::move(renderPass)) - { - } - - inline PixelFormat VulkanRenderPass::GetAttachmentFormat(std::size_t attachmentIndex) const - { - return m_formats[attachmentIndex]; - } - inline Vk::RenderPass& VulkanRenderPass::GetRenderPass() { return m_renderPass; diff --git a/include/Nazara/VulkanRenderer/VulkanRenderPipeline.hpp b/include/Nazara/VulkanRenderer/VulkanRenderPipeline.hpp index 8165d56f0..aa0d44a98 100644 --- a/include/Nazara/VulkanRenderer/VulkanRenderPipeline.hpp +++ b/include/Nazara/VulkanRenderer/VulkanRenderPipeline.hpp @@ -8,12 +8,13 @@ #define NAZARA_VULKANRENDERER_VULKANRENDERPIPELINE_HPP #include +#include #include #include #include +#include #include #include -#include #include namespace Nz @@ -26,7 +27,9 @@ namespace Nz VulkanRenderPipeline(Vk::Device& device, RenderPipelineInfo pipelineInfo); ~VulkanRenderPipeline() = default; - VkPipeline Get(const Vk::RenderPass& renderPass) const; + VkPipeline Get(const VulkanRenderPass& renderPass, std::size_t subpassIndex) const; + + inline const RenderPipelineInfo& GetPipelineInfo() const override; static std::vector BuildColorBlendAttachmentStateList(const RenderPipelineInfo& pipelineInfo); static VkPipelineColorBlendStateCreateInfo BuildColorBlendInfo(const RenderPipelineInfo& pipelineInfo, const std::vector& attachmentState); @@ -69,9 +72,16 @@ namespace Nz }; private: - mutable std::unordered_map m_pipelines; + void UpdateCreateInfo(std::size_t colorBufferCount) const; + + struct PipelineHasher + { + inline std::size_t operator()(const std::pair& renderPass) const; + }; + + mutable std::unordered_map, Vk::Pipeline, PipelineHasher> m_pipelines; MovablePtr m_device; - CreateInfo m_pipelineCreateInfo; + mutable CreateInfo m_pipelineCreateInfo; RenderPipelineInfo m_pipelineInfo; }; } diff --git a/include/Nazara/VulkanRenderer/VulkanRenderPipeline.inl b/include/Nazara/VulkanRenderer/VulkanRenderPipeline.inl index 00c03d4d2..177d4a5d3 100644 --- a/include/Nazara/VulkanRenderer/VulkanRenderPipeline.inl +++ b/include/Nazara/VulkanRenderer/VulkanRenderPipeline.inl @@ -7,6 +7,19 @@ namespace Nz { + inline std::size_t VulkanRenderPipeline::PipelineHasher::operator()(const std::pair& renderPass) const + { + std::size_t seed = 0; + HashCombine(seed, renderPass.first); + HashCombine(seed, renderPass.second); + + return seed; + } + + inline const RenderPipelineInfo& VulkanRenderPipeline::GetPipelineInfo() const + { + return m_pipelineInfo; + } } #include diff --git a/include/Nazara/VulkanRenderer/VulkanRenderPipelineLayout.hpp b/include/Nazara/VulkanRenderer/VulkanRenderPipelineLayout.hpp index 17e1a8800..a62c3f681 100644 --- a/include/Nazara/VulkanRenderer/VulkanRenderPipelineLayout.hpp +++ b/include/Nazara/VulkanRenderer/VulkanRenderPipelineLayout.hpp @@ -53,7 +53,7 @@ namespace Nz using BindingStorage = std::aligned_storage_t; Bitset freeBindings; - Vk::DescriptorPool descriptorPool; + std::unique_ptr descriptorPool; std::unique_ptr storage; }; diff --git a/include/Nazara/VulkanRenderer/VulkanRenderer.hpp b/include/Nazara/VulkanRenderer/VulkanRenderer.hpp index d52086dce..bd772716b 100644 --- a/include/Nazara/VulkanRenderer/VulkanRenderer.hpp +++ b/include/Nazara/VulkanRenderer/VulkanRenderer.hpp @@ -33,7 +33,7 @@ namespace Nz RenderAPI QueryAPI() const override; std::string QueryAPIString() const override; UInt32 QueryAPIVersion() const override; - std::vector QueryRenderDevices() const override; + const std::vector& QueryRenderDevices() const override; bool Prepare(const ParameterList& parameters) override; @@ -41,7 +41,7 @@ namespace Nz private: std::list m_devices; - std::vector m_physDevices; + std::vector m_deviceInfos; ParameterList m_initializationParameters; Vk::Instance m_instance; }; diff --git a/include/Nazara/VulkanRenderer/VulkanShaderBinding.hpp b/include/Nazara/VulkanRenderer/VulkanShaderBinding.hpp index ee97ec66f..8d38b92dd 100644 --- a/include/Nazara/VulkanRenderer/VulkanShaderBinding.hpp +++ b/include/Nazara/VulkanRenderer/VulkanShaderBinding.hpp @@ -28,7 +28,7 @@ namespace Nz inline std::size_t GetPoolIndex() const; inline const VulkanRenderPipelineLayout& GetOwner() const; - void Update(std::initializer_list bindings) override; + void Update(const Binding* bindings, std::size_t bindingCount) override; VulkanShaderBinding& operator=(const VulkanShaderBinding&) = delete; VulkanShaderBinding& operator=(VulkanShaderBinding&&) = delete; diff --git a/include/Nazara/VulkanRenderer/VulkanShaderModule.hpp b/include/Nazara/VulkanRenderer/VulkanShaderModule.hpp new file mode 100644 index 000000000..c3bc405f0 --- /dev/null +++ b/include/Nazara/VulkanRenderer/VulkanShaderModule.hpp @@ -0,0 +1,53 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Vulkan Renderer" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_VULKANRENDERER_VULKANSHADERSTAGE_HPP +#define NAZARA_VULKANRENDERER_VULKANSHADERSTAGE_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_VULKANRENDERER_API VulkanShaderModule : public ShaderModule + { + public: + struct Stage; + + VulkanShaderModule() = default; + VulkanShaderModule(const VulkanShaderModule&) = delete; + VulkanShaderModule(VulkanShaderModule&&) = delete; + ~VulkanShaderModule() = default; + + bool Create(Vk::Device& device, ShaderStageTypeFlags shaderStages, ShaderAst::StatementPtr& shaderAst, const ShaderWriter::States& states); + bool Create(Vk::Device& device, ShaderStageTypeFlags shaderStages, ShaderLanguage lang, const void* source, std::size_t sourceSize, const ShaderWriter::States& states); + + inline const Vk::ShaderModule& GetHandle() const; + inline const std::vector& GetStages() const; + + VulkanShaderModule& operator=(const VulkanShaderModule&) = delete; + VulkanShaderModule& operator=(VulkanShaderModule&&) = delete; + + struct Stage + { + ShaderStageType stage; + std::string name; + }; + + private: + Vk::ShaderModule m_shaderModule; + std::vector m_stages; + }; +} + +#include + +#endif // NAZARA_VULKANRENDERER_VULKANSHADERSTAGE_HPP diff --git a/include/Nazara/VulkanRenderer/VulkanShaderStage.inl b/include/Nazara/VulkanRenderer/VulkanShaderModule.inl similarity index 59% rename from include/Nazara/VulkanRenderer/VulkanShaderStage.inl rename to include/Nazara/VulkanRenderer/VulkanShaderModule.inl index 04aae8d74..8c3bded08 100644 --- a/include/Nazara/VulkanRenderer/VulkanShaderStage.inl +++ b/include/Nazara/VulkanRenderer/VulkanShaderModule.inl @@ -2,19 +2,19 @@ // This file is part of the "Nazara Engine - Vulkan Renderer" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include namespace Nz { - inline const Vk::ShaderModule& VulkanShaderStage::GetHandle() const + inline const Vk::ShaderModule& VulkanShaderModule::GetHandle() const { return m_shaderModule; } - inline ShaderStageType VulkanShaderStage::GetStageType() const + inline auto VulkanShaderModule::GetStages() const -> const std::vector& { - return m_stage; + return m_stages; } } diff --git a/include/Nazara/VulkanRenderer/VulkanShaderStage.hpp b/include/Nazara/VulkanRenderer/VulkanShaderStage.hpp deleted file mode 100644 index 50644f102..000000000 --- a/include/Nazara/VulkanRenderer/VulkanShaderStage.hpp +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Vulkan Renderer" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_VULKANRENDERER_VULKANSHADERSTAGE_HPP -#define NAZARA_VULKANRENDERER_VULKANSHADERSTAGE_HPP - -#include -#include -#include -#include -#include - -namespace Nz -{ - class NAZARA_VULKANRENDERER_API VulkanShaderStage : public ShaderStageImpl - { - public: - VulkanShaderStage() = default; - VulkanShaderStage(const VulkanShaderStage&) = delete; - VulkanShaderStage(VulkanShaderStage&&) = delete; - ~VulkanShaderStage() = default; - - bool Create(Vk::Device& device, ShaderStageType type, ShaderLanguage lang, const void* source, std::size_t sourceSize); - - inline const Vk::ShaderModule& GetHandle() const; - inline ShaderStageType GetStageType() const; - - VulkanShaderStage& operator=(const VulkanShaderStage&) = delete; - VulkanShaderStage& operator=(VulkanShaderStage&&) = delete; - - private: - Vk::ShaderModule m_shaderModule; - ShaderStageType m_stage; - }; -} - -#include - -#endif // NAZARA_VULKANRENDERER_VULKANSHADERSTAGE_HPP diff --git a/include/Nazara/VulkanRenderer/VulkanSingleFramebuffer.hpp b/include/Nazara/VulkanRenderer/VulkanSingleFramebuffer.hpp index 688bf99ba..0edc5d1e3 100644 --- a/include/Nazara/VulkanRenderer/VulkanSingleFramebuffer.hpp +++ b/include/Nazara/VulkanRenderer/VulkanSingleFramebuffer.hpp @@ -8,13 +8,17 @@ #define NAZARA_VULKANRENDERER_VULKANSINGLEFRAMEBUFFER_HPP #include +#include namespace Nz { + class RenderPass; + class Texture; + class NAZARA_VULKANRENDERER_API VulkanSingleFramebuffer final : public VulkanFramebuffer { public: - inline VulkanSingleFramebuffer(Vk::Framebuffer renderPass); + VulkanSingleFramebuffer(Vk::Device& device, unsigned int width, unsigned int height, const std::shared_ptr& renderPass, const std::vector>& attachments); VulkanSingleFramebuffer(const VulkanSingleFramebuffer&) = delete; VulkanSingleFramebuffer(VulkanSingleFramebuffer&&) = delete; ~VulkanSingleFramebuffer() = default; diff --git a/include/Nazara/VulkanRenderer/VulkanSingleFramebuffer.inl b/include/Nazara/VulkanRenderer/VulkanSingleFramebuffer.inl index 19f5e35c1..b9553b998 100644 --- a/include/Nazara/VulkanRenderer/VulkanSingleFramebuffer.inl +++ b/include/Nazara/VulkanRenderer/VulkanSingleFramebuffer.inl @@ -7,12 +7,6 @@ namespace Nz { - inline VulkanSingleFramebuffer::VulkanSingleFramebuffer(Vk::Framebuffer framebuffer) : - VulkanFramebuffer(Type::Single), - m_framebuffer(std::move(framebuffer)) - { - } - inline Vk::Framebuffer& VulkanSingleFramebuffer::GetFramebuffer() { return m_framebuffer; diff --git a/include/Nazara/VulkanRenderer/VulkanUploadPool.hpp b/include/Nazara/VulkanRenderer/VulkanUploadPool.hpp index fc8c9daf5..52ed8175c 100644 --- a/include/Nazara/VulkanRenderer/VulkanUploadPool.hpp +++ b/include/Nazara/VulkanRenderer/VulkanUploadPool.hpp @@ -40,17 +40,23 @@ namespace Nz VulkanUploadPool& operator=(VulkanUploadPool&&) = delete; private: + static constexpr std::size_t AllocationPerBlock = 2048; + + using AllocationBlock = std::array; + struct Block { Vk::DeviceMemory blockMemory; Vk::Buffer buffer; - UInt64 freeOffset; + UInt64 freeOffset = 0; + UInt64 size; }; UInt64 m_blockSize; Vk::Device& m_device; + std::size_t m_nextAllocationIndex; + std::vector> m_allocationBlocks; std::vector m_blocks; - std::vector m_allocations; }; } diff --git a/include/Nazara/VulkanRenderer/VulkanUploadPool.inl b/include/Nazara/VulkanRenderer/VulkanUploadPool.inl index 0245b5513..6aa3d88aa 100644 --- a/include/Nazara/VulkanRenderer/VulkanUploadPool.inl +++ b/include/Nazara/VulkanRenderer/VulkanUploadPool.inl @@ -9,7 +9,8 @@ namespace Nz { inline VulkanUploadPool::VulkanUploadPool(Vk::Device& device, UInt64 blockSize) : m_blockSize(blockSize), - m_device(device) + m_device(device), + m_nextAllocationIndex(0) { } } diff --git a/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.hpp b/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.hpp index 9310c5034..7f3397641 100644 --- a/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.hpp +++ b/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.hpp @@ -57,6 +57,7 @@ namespace Nz inline void CopyBuffer(VkBuffer source, VkBuffer target, UInt64 size, UInt64 sourceOffset = 0, UInt64 targetOffset = 0); inline void CopyBufferToImage(VkBuffer source, VkImage target, VkImageLayout targetLayout, UInt32 width, UInt32 height, UInt32 depth = 1); + inline void CopyBufferToImage(VkBuffer source, VkImage target, VkImageLayout targetLayout, const VkImageSubresourceLayers& subresourceLayers, UInt32 width, UInt32 height, UInt32 depth = 1); inline void Draw(UInt32 vertexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, UInt32 firstInstance = 0); inline void DrawIndexed(UInt32 indexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, Int32 vertexOffset = 0, UInt32 firstInstance = 0); @@ -70,11 +71,15 @@ namespace Nz inline CommandPool& GetPool(); + inline void ImageBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageLayout oldLayout, VkImageLayout newLayout, VkImage image, VkImageAspectFlags aspectFlags); + inline void InsertDebugLabel(const char* label); inline void InsertDebugLabel(const char* label, Nz::Color color); inline void MemoryBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask); + inline void NextSubpass(VkSubpassContents contents = VK_SUBPASS_CONTENTS_INLINE); + inline void PipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, const VkImageMemoryBarrier& imageMemoryBarrier); inline void PipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, const VkMemoryBarrier& memoryBarrier); inline void PipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, UInt32 memoryBarrierCount, const VkMemoryBarrier* memoryBarriers, UInt32 bufferMemoryBarrierCount, const VkBufferMemoryBarrier* bufferMemoryBarriers, UInt32 imageMemoryBarrierCount, const VkImageMemoryBarrier* imageMemoryBarriers); diff --git a/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.inl b/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.inl index 2e33e57b2..8a91cb685 100644 --- a/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.inl +++ b/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.inl @@ -225,17 +225,24 @@ namespace Nz } inline void CommandBuffer::CopyBufferToImage(VkBuffer source, VkImage target, VkImageLayout targetLayout, UInt32 width, UInt32 height, UInt32 depth) + { + VkImageSubresourceLayers subresourceLayers = { + VK_IMAGE_ASPECT_COLOR_BIT, //< aspectMask + 0, + 0, + 1 + }; + + return CopyBufferToImage(source, target, targetLayout, subresourceLayers, width, height, depth); + } + + inline void CommandBuffer::CopyBufferToImage(VkBuffer source, VkImage target, VkImageLayout targetLayout, const VkImageSubresourceLayers& subresourceLayers, UInt32 width, UInt32 height, UInt32 depth) { VkBufferImageCopy region = { 0, 0, 0, - { // imageSubresource - VK_IMAGE_ASPECT_COLOR_BIT, //< aspectMask - 0, - 0, - 1 - }, + subresourceLayers, { // imageOffset 0, 0, 0 }, @@ -295,6 +302,28 @@ namespace Nz return *m_pool; } + inline void CommandBuffer::ImageBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageLayout oldLayout, VkImageLayout newLayout, VkImage image, VkImageAspectFlags aspectFlags) + { + VkImageMemoryBarrier imageBarrier = { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + nullptr, + srcAccessMask, + dstAccessMask, + oldLayout, + newLayout, + VK_QUEUE_FAMILY_IGNORED, + VK_QUEUE_FAMILY_IGNORED, + image, + { + aspectFlags, + 0, 1, + 0, 1 + } + }; + + return PipelineBarrier(srcStageMask, dstStageMask, dependencyFlags, imageBarrier); + } + inline void CommandBuffer::InsertDebugLabel(const char* label) { return InsertDebugLabel(label, Nz::Color(0, 0, 0, 0)); @@ -333,6 +362,11 @@ namespace Nz return PipelineBarrier(srcStageMask, dstStageMask, 0U, memoryBarrier); } + inline void CommandBuffer::NextSubpass(VkSubpassContents contents) + { + return m_pool->GetDevice()->vkCmdNextSubpass(m_handle, contents); + } + inline void CommandBuffer::PipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, const VkImageMemoryBarrier& imageMemoryBarrier) { return PipelineBarrier(srcStageMask, dstStageMask, dependencyFlags, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); diff --git a/include/Nazara/VulkanRenderer/Wrapper/DescriptorSet.inl b/include/Nazara/VulkanRenderer/Wrapper/DescriptorSet.inl index d6712c1b4..a601a3b02 100644 --- a/include/Nazara/VulkanRenderer/Wrapper/DescriptorSet.inl +++ b/include/Nazara/VulkanRenderer/Wrapper/DescriptorSet.inl @@ -145,9 +145,8 @@ namespace Nz inline DescriptorSet& DescriptorSet::operator=(DescriptorSet&& descriptorSet) noexcept { - m_pool = descriptorSet.m_pool; - std::swap(m_handle, descriptorSet.m_handle); + std::swap(m_pool, descriptorSet.m_pool); return *this; } diff --git a/include/Nazara/VulkanRenderer/Wrapper/Instance.hpp b/include/Nazara/VulkanRenderer/Wrapper/Instance.hpp index 3ab30645e..ed3e9d5ac 100644 --- a/include/Nazara/VulkanRenderer/Wrapper/Instance.hpp +++ b/include/Nazara/VulkanRenderer/Wrapper/Instance.hpp @@ -59,20 +59,20 @@ namespace Nz inline bool Create(const std::string& appName, UInt32 appVersion, const std::string& engineName, UInt32 engineVersion, UInt32 apiVersion, const std::vector& layers, const std::vector& extensions, const VkAllocationCallbacks* allocator = nullptr); inline void Destroy(); - bool EnumeratePhysicalDevices(std::vector* physicalDevices); + bool EnumeratePhysicalDevices(std::vector* physicalDevices) const; - inline PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* name); + inline PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* name) const; inline UInt32 GetApiVersion() const; inline VkResult GetLastErrorCode() const; - bool GetPhysicalDeviceExtensions(VkPhysicalDevice device, std::vector* extensionProperties); - inline VkPhysicalDeviceFeatures GetPhysicalDeviceFeatures(VkPhysicalDevice device); - inline VkFormatProperties GetPhysicalDeviceFormatProperties(VkPhysicalDevice device, VkFormat format); - inline bool GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* imageFormatProperties); - inline VkPhysicalDeviceMemoryProperties GetPhysicalDeviceMemoryProperties(VkPhysicalDevice device); - inline VkPhysicalDeviceProperties GetPhysicalDeviceProperties(VkPhysicalDevice device); - bool GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice device, std::vector* queueFamilyProperties); + bool GetPhysicalDeviceExtensions(VkPhysicalDevice device, std::vector* extensionProperties) const; + inline VkPhysicalDeviceFeatures GetPhysicalDeviceFeatures(VkPhysicalDevice device) const; + inline VkFormatProperties GetPhysicalDeviceFormatProperties(VkPhysicalDevice device, VkFormat format) const; + inline bool GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* imageFormatProperties) const; + inline VkPhysicalDeviceMemoryProperties GetPhysicalDeviceMemoryProperties(VkPhysicalDevice device) const; + inline VkPhysicalDeviceProperties GetPhysicalDeviceProperties(VkPhysicalDevice device) const; + bool GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice device, std::vector* queueFamilyProperties) const; void InstallDebugMessageCallback(); @@ -95,7 +95,7 @@ namespace Nz void DestroyInstance(); void ResetPointers(); - inline PFN_vkVoidFunction GetProcAddr(const char* name); + inline PFN_vkVoidFunction GetProcAddr(const char* name) const; struct InternalData; @@ -104,7 +104,7 @@ namespace Nz std::unordered_set m_loadedLayers; VkAllocationCallbacks m_allocator; VkInstance m_instance; - VkResult m_lastErrorCode; + mutable VkResult m_lastErrorCode; UInt32 m_apiVersion; }; } diff --git a/include/Nazara/VulkanRenderer/Wrapper/Instance.inl b/include/Nazara/VulkanRenderer/Wrapper/Instance.inl index e66261801..84658f9af 100644 --- a/include/Nazara/VulkanRenderer/Wrapper/Instance.inl +++ b/include/Nazara/VulkanRenderer/Wrapper/Instance.inl @@ -49,7 +49,7 @@ namespace Nz } } - inline PFN_vkVoidFunction Instance::GetDeviceProcAddr(VkDevice device, const char* name) + inline PFN_vkVoidFunction Instance::GetDeviceProcAddr(VkDevice device, const char* name) const { PFN_vkVoidFunction func = vkGetDeviceProcAddr(device, name); if (!func) @@ -88,7 +88,7 @@ namespace Nz return m_instance; } - inline VkPhysicalDeviceFeatures Instance::GetPhysicalDeviceFeatures(VkPhysicalDevice device) + inline VkPhysicalDeviceFeatures Instance::GetPhysicalDeviceFeatures(VkPhysicalDevice device) const { VkPhysicalDeviceFeatures features; vkGetPhysicalDeviceFeatures(device, &features); @@ -96,7 +96,7 @@ namespace Nz return features; } - inline VkFormatProperties Instance::GetPhysicalDeviceFormatProperties(VkPhysicalDevice device, VkFormat format) + inline VkFormatProperties Instance::GetPhysicalDeviceFormatProperties(VkPhysicalDevice device, VkFormat format) const { VkFormatProperties formatProperties; vkGetPhysicalDeviceFormatProperties(device, format, &formatProperties); @@ -104,7 +104,7 @@ namespace Nz return formatProperties; } - inline bool Instance::GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* imageFormatProperties) + inline bool Instance::GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* imageFormatProperties) const { m_lastErrorCode = vkGetPhysicalDeviceImageFormatProperties(physicalDevice, format, type, tiling, usage, flags, imageFormatProperties); if (m_lastErrorCode != VkResult::VK_SUCCESS) @@ -116,7 +116,7 @@ namespace Nz return true; } - inline VkPhysicalDeviceMemoryProperties Instance::GetPhysicalDeviceMemoryProperties(VkPhysicalDevice device) + inline VkPhysicalDeviceMemoryProperties Instance::GetPhysicalDeviceMemoryProperties(VkPhysicalDevice device) const { VkPhysicalDeviceMemoryProperties memoryProperties; vkGetPhysicalDeviceMemoryProperties(device, &memoryProperties); @@ -124,7 +124,7 @@ namespace Nz return memoryProperties; } - inline VkPhysicalDeviceProperties Instance::GetPhysicalDeviceProperties(VkPhysicalDevice device) + inline VkPhysicalDeviceProperties Instance::GetPhysicalDeviceProperties(VkPhysicalDevice device) const { VkPhysicalDeviceProperties properties; vkGetPhysicalDeviceProperties(device, &properties); @@ -132,7 +132,7 @@ namespace Nz return properties; } - inline PFN_vkVoidFunction Instance::GetProcAddr(const char* name) + inline PFN_vkVoidFunction Instance::GetProcAddr(const char* name) const { PFN_vkVoidFunction func = Loader::GetInstanceProcAddr(m_instance, name); if (!func) diff --git a/include/Nazara/VulkanRenderer/Wrapper/PhysicalDevice.hpp b/include/Nazara/VulkanRenderer/Wrapper/PhysicalDevice.hpp index 5e027252f..4b81e27fa 100644 --- a/include/Nazara/VulkanRenderer/Wrapper/PhysicalDevice.hpp +++ b/include/Nazara/VulkanRenderer/Wrapper/PhysicalDevice.hpp @@ -11,20 +11,17 @@ #include #include -namespace Nz +namespace Nz::Vk { - namespace Vk + struct PhysicalDevice { - struct PhysicalDevice - { - VkPhysicalDevice physDevice; - VkPhysicalDeviceFeatures features; - VkPhysicalDeviceMemoryProperties memoryProperties; - VkPhysicalDeviceProperties properties; - std::unordered_set extensions; - std::vector queueFamilies; - }; - } + VkPhysicalDevice physDevice; + VkPhysicalDeviceFeatures features; + VkPhysicalDeviceMemoryProperties memoryProperties; + VkPhysicalDeviceProperties properties; + std::unordered_set extensions; + std::vector queueFamilies; + }; } #endif // NAZARA_VULKANRENDERER_VKPHYSICALDEVICE_HPP diff --git a/include/NazaraSDK/Application.hpp b/include/NazaraSDK/Application.hpp index 2bd467137..e185892ad 100644 --- a/include/NazaraSDK/Application.hpp +++ b/include/NazaraSDK/Application.hpp @@ -15,11 +15,6 @@ #include #include -#ifndef NDK_SERVER -#include -#include -#endif - namespace Ndk { class NDK_API Application @@ -31,9 +26,6 @@ namespace Ndk Application(Application&&) = delete; inline ~Application(); - #ifndef NDK_SERVER - template T& AddWindow(Args&&... args); - #endif template World& AddWorld(Args&&... args); inline const std::set& GetOptions() const; @@ -44,17 +36,8 @@ namespace Ndk inline bool HasOption(const std::string& option) const; inline bool HasParameter(const std::string& key, std::string* value) const; - #ifndef NDK_SERVER - inline bool IsConsoleEnabled() const; - inline bool IsFPSCounterEnabled() const; - #endif - bool Run(); - #ifndef NDK_SERVER - inline void MakeExitOnLastWindowClosed(bool exitOnClosedWindows); - #endif - inline void Quit(); Application& operator=(const Application&) = delete; @@ -62,26 +45,16 @@ namespace Ndk inline static Application* Instance(); + protected: + void ClearWorlds(); + void ParseCommandline(int argc, char* argv[]); + private: - #ifndef NDK_SERVER - struct WindowInfo - { - inline WindowInfo(std::unique_ptr&& window); - - std::unique_ptr window; - }; - - std::vector m_windows; - #endif - std::map m_parameters; std::set m_options; std::list m_worlds; Nz::Clock m_updateClock; - #ifndef NDK_SERVER - bool m_exitOnClosedWindows; - #endif bool m_shouldQuit; float m_updateTime; diff --git a/include/NazaraSDK/Application.inl b/include/NazaraSDK/Application.inl index d6b58a257..4016a9777 100644 --- a/include/NazaraSDK/Application.inl +++ b/include/NazaraSDK/Application.inl @@ -15,9 +15,6 @@ namespace Ndk * \remark Only one Application instance can exist at a time */ inline Application::Application() : - #ifndef NDK_SERVER - m_exitOnClosedWindows(true), - #endif m_shouldQuit(false), m_updateTime(0.f) { @@ -33,33 +30,11 @@ namespace Ndk inline Application::~Application() { m_worlds.clear(); - #ifndef NDK_SERVER - m_windows.clear(); - #endif // Automatic free of modules s_application = nullptr; } - /*! - * \brief Adds a window to the application - * \return A reference to the newly created windows - * - * \param args Arguments used to create the window - */ - #ifndef NDK_SERVER - template - T& Application::AddWindow(Args&&... args) - { - static_assert(std::is_base_of::value, "Type must inherit Window"); - - m_windows.emplace_back(std::make_unique(std::forward(args)...)); - WindowInfo& info = m_windows.back(); - - return static_cast(*info.window.get()); //< Warning: ugly - } - #endif - /*! * \brief Adds a world to the application * \return A reference to the newly created world @@ -147,18 +122,6 @@ namespace Ndk return true; } - /*! - * \brief Makes the application exit when there's no more open window - * - * \param exitOnClosedWindows Should exit be called when no more window is open - */ - #ifndef NDK_SERVER - inline void Application::MakeExitOnLastWindowClosed(bool exitOnClosedWindows) - { - m_exitOnClosedWindows = exitOnClosedWindows; - } - #endif - /*! * \brief Quits the application */ @@ -177,11 +140,4 @@ namespace Ndk { return s_application; } - - #ifndef NDK_SERVER - inline Application::WindowInfo::WindowInfo(std::unique_ptr&& windowPtr) : - window(std::move(windowPtr)) - { - } - #endif } diff --git a/include/NazaraSDK/ClientApplication.hpp b/include/NazaraSDK/ClientApplication.hpp new file mode 100644 index 000000000..54875af27 --- /dev/null +++ b/include/NazaraSDK/ClientApplication.hpp @@ -0,0 +1,69 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Development Kit" +// For conditions of distribution and use, see copyright notice in Prerequisites.hpp + +#pragma once + +#ifndef NDK_CLIENTAPPLICATION_HPP +#define NDK_CLIENTAPPLICATION_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Ndk +{ + class NDK_CLIENT_API ClientApplication : public Application + { + public: + struct ConsoleOverlay; + struct FPSCounterOverlay; + + inline ClientApplication(); + ClientApplication(int argc, char* argv[]); + ClientApplication(const ClientApplication&) = delete; + ClientApplication(ClientApplication&&) = delete; + inline ~ClientApplication(); + + template T& AddWindow(Args&&... args); + + bool Run(); + + inline void MakeExitOnLastWindowClosed(bool exitOnClosedWindows); + + ClientApplication& operator=(const ClientApplication&) = delete; + ClientApplication& operator=(ClientApplication&&) = delete; + + inline static ClientApplication* Instance(); + + private: + enum OverlayFlags + { + OverlayFlags_Console = 0x1, + OverlayFlags_FPSCounter = 0x2 + }; + + struct WindowInfo + { + inline WindowInfo(std::unique_ptr&& window); + + std::unique_ptr window; + }; + + std::vector m_windows; + Nz::UInt32 m_overlayFlags; + bool m_exitOnClosedWindows; + + static ClientApplication* s_clientApplication; + }; +} + +#include + +#endif // NDK_CLIENTAPPLICATION_HPP diff --git a/include/NazaraSDK/ClientApplication.inl b/include/NazaraSDK/ClientApplication.inl new file mode 100644 index 000000000..d4f10a245 --- /dev/null +++ b/include/NazaraSDK/ClientApplication.inl @@ -0,0 +1,79 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Development Kit" +// For conditions of distribution and use, see copyright notice in Prerequisites.hpp + +#include +#include +#include + +namespace Ndk +{ + /*! + * \brief Constructs an Application object without passing command-line arguments + * + * This calls Sdk::Initialize() + * + * \remark Only one Application instance can exist at a time + */ + inline ClientApplication::ClientApplication() : + m_overlayFlags(0U), + m_exitOnClosedWindows(true) + { + NazaraAssert(s_clientApplication == nullptr, "You can create only one application instance per program"); + s_clientApplication = this; + } + + /*! + * \brief Destructs the application object + * + * This destroy all worlds and windows and then calls Sdk::Uninitialize + */ + inline ClientApplication::~ClientApplication() + { + ClearWorlds(); + m_windows.clear(); + + s_clientApplication = nullptr; + } + + /*! + * \brief Adds a window to the application + * \return A reference to the newly created windows + * + * \param args Arguments used to create the window + */ + template + T& ClientApplication::AddWindow(Args&&... args) + { + static_assert(std::is_base_of::value, "Type must inherit Window"); + + m_windows.emplace_back(std::make_unique(std::forward(args)...)); + WindowInfo& info = m_windows.back(); + + return static_cast(*info.window.get()); //< Warning: ugly + } + + /*! + * \brief Makes the application exit when there's no more open window + * + * \param exitOnClosedWindows Should exit be called when no more window is open + */ + inline void ClientApplication::MakeExitOnLastWindowClosed(bool exitOnClosedWindows) + { + m_exitOnClosedWindows = exitOnClosedWindows; + } + + /*! + * \brief Gets the singleton instance of the application + * \return Singleton application + */ + inline ClientApplication* ClientApplication::Instance() + { + return s_clientApplication; + } + + inline ClientApplication::WindowInfo::WindowInfo(std::unique_ptr&& windowPtr) : + window(std::move(windowPtr)) + { + } +} diff --git a/include/NazaraSDK/ClientPrerequisites.hpp b/include/NazaraSDK/ClientPrerequisites.hpp new file mode 100644 index 000000000..b90c37761 --- /dev/null +++ b/include/NazaraSDK/ClientPrerequisites.hpp @@ -0,0 +1,46 @@ +/* + Nazara Development Kit ("NDK"), also called Nazara Engine - SDK ("Software Development Kit") + + Copyright (C) 2015 Jérôme "Lynix" Leclercq (Lynix680@gmail.com) + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +#ifndef NDK_CLIENT_PREREQUISITES_HPP +#define NDK_CLIENT_PREREQUISITES_HPP + +/*! +* \defgroup NDK (NazaraSDK) Nazara Development Kit +* A library grouping every modules of Nazara into multiple higher-level features suchs as scene management (handled by an ECS), application, lua binding, etc. +*/ + +#include + +// Importation/Exportation of the API +#if defined(NAZARA_STATIC) + #define NDK_CLIENT_API +#else + #ifdef NDK_CLIENT_BUILD + #define NDK_CLIENT_API NAZARA_EXPORT + #else + #define NDK_CLIENT_API NAZARA_IMPORT + #endif +#endif + +#endif // NDK_CLIENT_PREREQUISITES_HPP diff --git a/include/NazaraSDK/ClientSdk.hpp b/include/NazaraSDK/ClientSdk.hpp new file mode 100644 index 000000000..bc8a5b07a --- /dev/null +++ b/include/NazaraSDK/ClientSdk.hpp @@ -0,0 +1,36 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Development Kit" +// For conditions of distribution and use, see copyright notice in Prerequisites.hpp + +#pragma once + +#ifndef NDK_CLIENTSDK_HPP +#define NDK_CLIENTSDK_HPP + +#include +#include +#include +#include + +namespace Ndk +{ + class NDK_CLIENT_API ClientSdk : public Nz::ModuleBase + { + friend ModuleBase; + + public: + using Dependencies = Nz::TypeList; + + struct Config {}; + + ClientSdk(Config /*config*/); + ~ClientSdk(); + + private: + static ClientSdk* s_instance; + }; +} + +#include + +#endif // NDK_CLIENTSDK_HPP diff --git a/include/NazaraSDK/ClientSdk.inl b/include/NazaraSDK/ClientSdk.inl new file mode 100644 index 000000000..5db72c705 --- /dev/null +++ b/include/NazaraSDK/ClientSdk.inl @@ -0,0 +1,7 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Development Kit" +// For conditions of distribution and use, see copyright notice in Prerequisites.hpp + +namespace Ndk +{ +} diff --git a/include/NazaraSDK/Components/CollisionComponent2D.hpp b/include/NazaraSDK/Components/CollisionComponent2D.hpp index d10dec8af..69753a3e9 100644 --- a/include/NazaraSDK/Components/CollisionComponent2D.hpp +++ b/include/NazaraSDK/Components/CollisionComponent2D.hpp @@ -25,20 +25,20 @@ namespace Ndk friend class PhysicsSystem2D; public: - CollisionComponent2D(Nz::Collider2DRef geom = Nz::Collider2DRef()); + CollisionComponent2D(std::shared_ptr geom = std::shared_ptr()); CollisionComponent2D(const CollisionComponent2D& collision); ~CollisionComponent2D() = default; Nz::Rectf GetAABB() const; - const Nz::Collider2DRef& GetGeom() const; + const std::shared_ptr& GetGeom() const; const Nz::Vector2f& GetGeomOffset() const; void Recenter(const Nz::Vector2f& origin); - void SetGeom(Nz::Collider2DRef geom, bool recomputeMoment = true, bool recomputeMassCenter = true); + void SetGeom(std::shared_ptr geom, bool recomputeMoment = true, bool recomputeMassCenter = true); void SetGeomOffset(const Nz::Vector2f& geomOffset); - CollisionComponent2D& operator=(Nz::Collider2DRef geom); + CollisionComponent2D& operator=(std::shared_ptr geom); CollisionComponent2D& operator=(CollisionComponent2D&& collision) = delete; static ComponentIndex componentIndex; @@ -56,7 +56,7 @@ namespace Ndk void OnDetached() override; std::unique_ptr m_staticBody; - Nz::Collider2DRef m_geom; + std::shared_ptr m_geom; bool m_bodyUpdated; }; } diff --git a/include/NazaraSDK/Components/CollisionComponent2D.inl b/include/NazaraSDK/Components/CollisionComponent2D.inl index 35df6467c..6be748111 100644 --- a/include/NazaraSDK/Components/CollisionComponent2D.inl +++ b/include/NazaraSDK/Components/CollisionComponent2D.inl @@ -10,7 +10,7 @@ namespace Ndk * \param geom Reference to a geometry symbolizing the entity */ - inline CollisionComponent2D::CollisionComponent2D(Nz::Collider2DRef geom) : + inline CollisionComponent2D::CollisionComponent2D(std::shared_ptr geom) : m_geom(std::move(geom)), m_bodyUpdated(false) { @@ -33,7 +33,7 @@ namespace Ndk * \return A constant reference to the physics geometry */ - inline const Nz::Collider2DRef& CollisionComponent2D::GetGeom() const + inline const std::shared_ptr& CollisionComponent2D::GetGeom() const { return m_geom; } @@ -45,7 +45,7 @@ namespace Ndk * \param geom Reference to a geometry symbolizing the entity */ - inline CollisionComponent2D& CollisionComponent2D::operator=(Nz::Collider2DRef geom) + inline CollisionComponent2D& CollisionComponent2D::operator=(std::shared_ptr geom) { SetGeom(geom); diff --git a/include/NazaraSDK/Components/CollisionComponent3D.hpp b/include/NazaraSDK/Components/CollisionComponent3D.hpp index 7994232a8..083c4ef1c 100644 --- a/include/NazaraSDK/Components/CollisionComponent3D.hpp +++ b/include/NazaraSDK/Components/CollisionComponent3D.hpp @@ -23,15 +23,15 @@ namespace Ndk friend class PhysicsSystem3D; public: - CollisionComponent3D(Nz::Collider3DRef geom = Nz::Collider3DRef()); + CollisionComponent3D(std::shared_ptr geom = std::shared_ptr()); CollisionComponent3D(const CollisionComponent3D& collision); ~CollisionComponent3D() = default; - const Nz::Collider3DRef& GetGeom() const; + const std::shared_ptr& GetGeom() const; - void SetGeom(Nz::Collider3DRef geom); + void SetGeom(std::shared_ptr geom); - CollisionComponent3D& operator=(Nz::Collider3DRef geom); + CollisionComponent3D& operator=(std::shared_ptr geom); CollisionComponent3D& operator=(CollisionComponent3D&& collision) = delete; static ComponentIndex componentIndex; @@ -48,7 +48,7 @@ namespace Ndk void OnEntityEnabled() override; std::unique_ptr m_staticBody; - Nz::Collider3DRef m_geom; + std::shared_ptr m_geom; bool m_bodyUpdated; }; } diff --git a/include/NazaraSDK/Components/CollisionComponent3D.inl b/include/NazaraSDK/Components/CollisionComponent3D.inl index fc31fe0b5..a2a8ede7f 100644 --- a/include/NazaraSDK/Components/CollisionComponent3D.inl +++ b/include/NazaraSDK/Components/CollisionComponent3D.inl @@ -10,7 +10,7 @@ namespace Ndk * \param geom Reference to a geometry symbolizing the entity */ - inline CollisionComponent3D::CollisionComponent3D(Nz::Collider3DRef geom) : + inline CollisionComponent3D::CollisionComponent3D(std::shared_ptr geom) : m_geom(std::move(geom)), m_bodyUpdated(false) { @@ -33,7 +33,7 @@ namespace Ndk * \return A constant reference to the physics geometry */ - inline const Nz::Collider3DRef& CollisionComponent3D::GetGeom() const + inline const std::shared_ptr& CollisionComponent3D::GetGeom() const { return m_geom; } @@ -45,7 +45,7 @@ namespace Ndk * \param geom Reference to a geometry symbolizing the entity */ - inline CollisionComponent3D& CollisionComponent3D::operator=(Nz::Collider3DRef geom) + inline CollisionComponent3D& CollisionComponent3D::operator=(std::shared_ptr geom) { SetGeom(geom); diff --git a/include/NazaraSDK/Components/ListenerComponent.hpp b/include/NazaraSDK/Components/ListenerComponent.hpp index cea5a8d84..c8936bc81 100644 --- a/include/NazaraSDK/Components/ListenerComponent.hpp +++ b/include/NazaraSDK/Components/ListenerComponent.hpp @@ -4,10 +4,10 @@ #pragma once -#ifndef NDK_SERVER #ifndef NDK_COMPONENTS_LISTENERCOMPONENT_HPP #define NDK_COMPONENTS_LISTENERCOMPONENT_HPP +#include #include namespace Ndk @@ -16,7 +16,7 @@ namespace Ndk using ListenerComponentHandle = Nz::ObjectHandle; - class NDK_API ListenerComponent : public Component + class NDK_CLIENT_API ListenerComponent : public Component { public: inline ListenerComponent(); @@ -35,4 +35,3 @@ namespace Ndk #include #endif // NDK_COMPONENTS_LISTENERCOMPONENT_HPP -#endif // NDK_SERVER \ No newline at end of file diff --git a/include/NazaraSDK/Components/PhysicsComponent2D.hpp b/include/NazaraSDK/Components/PhysicsComponent2D.hpp index 89aeb8dfd..3f2851eeb 100644 --- a/include/NazaraSDK/Components/PhysicsComponent2D.hpp +++ b/include/NazaraSDK/Components/PhysicsComponent2D.hpp @@ -30,10 +30,10 @@ namespace Ndk PhysicsComponent2D(const PhysicsComponent2D& physics); ~PhysicsComponent2D() = default; - inline void AddForce(const Nz::Vector2f& force, Nz::CoordSys coordSys = Nz::CoordSys_Global); - inline void AddForce(const Nz::Vector2f& force, const Nz::Vector2f& point, Nz::CoordSys coordSys = Nz::CoordSys_Global); - inline void AddImpulse(const Nz::Vector2f& impulse, Nz::CoordSys coordSys = Nz::CoordSys_Global); - inline void AddImpulse(const Nz::Vector2f& impulse, const Nz::Vector2f& point, Nz::CoordSys coordSys = Nz::CoordSys_Global); + inline void AddForce(const Nz::Vector2f& force, Nz::CoordSys coordSys = Nz::CoordSys::Global); + inline void AddForce(const Nz::Vector2f& force, const Nz::Vector2f& point, Nz::CoordSys coordSys = Nz::CoordSys::Global); + inline void AddImpulse(const Nz::Vector2f& impulse, Nz::CoordSys coordSys = Nz::CoordSys::Global); + inline void AddImpulse(const Nz::Vector2f& impulse, const Nz::Vector2f& point, Nz::CoordSys coordSys = Nz::CoordSys::Global); inline void AddTorque(const Nz::RadianAnglef& torque); inline bool ClosestPointQuery(const Nz::Vector2f& position, Nz::Vector2f* closestPoint, float* closestDistance) const; @@ -47,11 +47,11 @@ namespace Ndk inline float GetAngularDamping() const; inline Nz::RadianAnglef GetAngularVelocity() const; NAZARA_DEPRECATED("Name error, please use GetMassCenter") - inline Nz::Vector2f GetCenterOfGravity(Nz::CoordSys coordSys = Nz::CoordSys_Local) const; + inline Nz::Vector2f GetCenterOfGravity(Nz::CoordSys coordSys = Nz::CoordSys::Local) const; inline float GetElasticity(std::size_t shapeIndex = 0) const; inline float GetFriction(std::size_t shapeIndex = 0) const; inline float GetMass() const; - inline Nz::Vector2f GetMassCenter(Nz::CoordSys coordSys = Nz::CoordSys_Local) const; + inline Nz::Vector2f GetMassCenter(Nz::CoordSys coordSys = Nz::CoordSys::Local) const; inline float GetMomentOfInertia() const; inline Nz::Vector2f GetPosition() const; inline Nz::RadianAnglef GetRotation() const; @@ -73,7 +73,7 @@ namespace Ndk inline void SetFriction(float friction); inline void SetFriction(std::size_t shapeIndex, float friction); inline void SetMass(float mass, bool recomputeMoment = true); - inline void SetMassCenter(const Nz::Vector2f& center, Nz::CoordSys coordSys = Nz::CoordSys_Local); + inline void SetMassCenter(const Nz::Vector2f& center, Nz::CoordSys coordSys = Nz::CoordSys::Local); inline void SetMomentOfInertia(float moment); inline void SetPosition(const Nz::Vector2f& position); inline void SetRotation(const Nz::RadianAnglef& rotation); diff --git a/include/NazaraSDK/Components/PhysicsComponent3D.hpp b/include/NazaraSDK/Components/PhysicsComponent3D.hpp index 16a242e81..be3ca4aae 100644 --- a/include/NazaraSDK/Components/PhysicsComponent3D.hpp +++ b/include/NazaraSDK/Components/PhysicsComponent3D.hpp @@ -27,9 +27,9 @@ namespace Ndk PhysicsComponent3D(const PhysicsComponent3D& physics); ~PhysicsComponent3D() = default; - inline void AddForce(const Nz::Vector3f& force, Nz::CoordSys coordSys = Nz::CoordSys_Global); - inline void AddForce(const Nz::Vector3f& force, const Nz::Vector3f& point, Nz::CoordSys coordSys = Nz::CoordSys_Global); - inline void AddTorque(const Nz::Vector3f& torque, Nz::CoordSys coordSys = Nz::CoordSys_Global); + inline void AddForce(const Nz::Vector3f& force, Nz::CoordSys coordSys = Nz::CoordSys::Global); + inline void AddForce(const Nz::Vector3f& force, const Nz::Vector3f& point, Nz::CoordSys coordSys = Nz::CoordSys::Global); + inline void AddTorque(const Nz::Vector3f& torque, Nz::CoordSys coordSys = Nz::CoordSys::Global); inline void EnableAutoSleep(bool autoSleep); inline void EnableNodeSynchronization(bool nodeSynchronization); @@ -41,7 +41,7 @@ namespace Ndk inline float GetLinearDamping() const; inline Nz::Vector3f GetLinearVelocity() const; inline float GetMass() const; - inline Nz::Vector3f GetMassCenter(Nz::CoordSys coordSys = Nz::CoordSys_Local) const; + inline Nz::Vector3f GetMassCenter(Nz::CoordSys coordSys = Nz::CoordSys::Local) const; inline const Nz::Matrix4f& GetMatrix() const; inline Nz::Vector3f GetPosition() const; inline Nz::Quaternionf GetRotation() const; diff --git a/include/NazaraSDK/Components/PhysicsComponent3D.inl b/include/NazaraSDK/Components/PhysicsComponent3D.inl index 9937f354c..6925d5608 100644 --- a/include/NazaraSDK/Components/PhysicsComponent3D.inl +++ b/include/NazaraSDK/Components/PhysicsComponent3D.inl @@ -480,7 +480,7 @@ namespace Ndk m_pendingStates.gravityFactor = rigidBody.GetGravityFactor(); m_pendingStates.linearDamping = rigidBody.GetLinearDamping(); m_pendingStates.mass = rigidBody.GetMass(); - m_pendingStates.massCenter = rigidBody.GetMassCenter(Nz::CoordSys_Local); + m_pendingStates.massCenter = rigidBody.GetMassCenter(Nz::CoordSys::Local); m_pendingStates.valid = true; } diff --git a/include/NazaraSDK/Components/VelocityComponent.hpp b/include/NazaraSDK/Components/VelocityComponent.hpp index a82ecdf5c..5a0f5bd2f 100644 --- a/include/NazaraSDK/Components/VelocityComponent.hpp +++ b/include/NazaraSDK/Components/VelocityComponent.hpp @@ -19,7 +19,7 @@ namespace Ndk class NDK_API VelocityComponent : public Component { public: - VelocityComponent(const Nz::Vector3f& velocity = Nz::Vector3f::Zero(), Nz::CoordSys coordSystem = Nz::CoordSys_Global); + VelocityComponent(const Nz::Vector3f& velocity = Nz::Vector3f::Zero(), Nz::CoordSys coordSystem = Nz::CoordSys::Global); ~VelocityComponent() = default; Nz::Vector3f linearVelocity; diff --git a/include/NazaraSDK/EntityList.hpp b/include/NazaraSDK/EntityList.hpp index ae9a5e63d..ce613fcf4 100644 --- a/include/NazaraSDK/EntityList.hpp +++ b/include/NazaraSDK/EntityList.hpp @@ -16,6 +16,7 @@ namespace Ndk class NDK_API EntityList { friend Entity; + friend World; public: class iterator; @@ -23,16 +24,16 @@ namespace Ndk using size_type = std::size_t; inline EntityList(); - inline EntityList(const EntityList& entityList); - inline EntityList(EntityList&& entityList) noexcept; - inline ~EntityList(); + EntityList(const EntityList& entityList); + EntityList(EntityList&& entityList) noexcept; + ~EntityList(); - inline void Clear(); + void Clear(); inline bool Has(const Entity* entity) const; inline bool Has(EntityId entity) const; - inline void Insert(Entity* entity); + void Insert(Entity* entity); inline void Remove(Entity* entity); inline void Reserve(std::size_t entityCount); @@ -50,6 +51,7 @@ namespace Ndk inline std::size_t FindNext(std::size_t currentId) const; inline World* GetWorld() const; inline void NotifyEntityDestruction(const Entity* entity); + inline void SetWorld(World* world); Nz::Bitset m_entityBits; World* m_world; diff --git a/include/NazaraSDK/EntityList.inl b/include/NazaraSDK/EntityList.inl index 48876faf8..128f12a24 100644 --- a/include/NazaraSDK/EntityList.inl +++ b/include/NazaraSDK/EntityList.inl @@ -2,6 +2,7 @@ // This file is part of the "Nazara Development Kit" // For conditions of distribution and use, see copyright notice in Prerequisites.hpp +#include #include #include @@ -21,52 +22,6 @@ namespace Ndk { } - /*! - * \brief Construct a new entity list by copying another one - */ - inline EntityList::EntityList(const EntityList& entityList) : - m_entityBits(entityList.m_entityBits), - m_world(entityList.m_world) - { - for (const Ndk::EntityHandle& entity : *this) - entity->RegisterEntityList(this); - } - - /*! - * \brief Construct a new entity list by moving a list into this one - */ - inline EntityList::EntityList(EntityList&& entityList) noexcept : - m_entityBits(std::move(entityList.m_entityBits)), - m_world(entityList.m_world) - { - for (const Ndk::EntityHandle& entity : *this) - { - entity->UnregisterEntityList(&entityList); - entity->RegisterEntityList(this); - } - } - - inline EntityList::~EntityList() - { - for (const Ndk::EntityHandle& entity : *this) - entity->UnregisterEntityList(this); - } - - - /*! - * \brief Clears the set from every entities - * - * \remark This resets the implicit world member, allowing you to insert entities from a different world than previously - */ - inline void EntityList::Clear() - { - for (const Ndk::EntityHandle& entity : *this) - entity->UnregisterEntityList(this); - - m_entityBits.Clear(); - m_world = nullptr; - } - /*! * \brief Checks whether or not the EntityList contains the entity * \return true If it is the case @@ -93,29 +48,6 @@ namespace Ndk return m_entityBits.UnboundedTest(entity); } - /*! - * \brief Inserts the entity into the set - * - * Marks an entity as present in this entity list, it must belongs to the same world as others entities contained in this list. - * - * \param entity Valid pointer to an entity - * - * \remark If entity is already contained, no action is performed - * \remark If any entity has been inserted since construction (or last Clear call), the entity must belong to the same world as the previously inserted entities - */ - inline void EntityList::Insert(Entity* entity) - { - NazaraAssert(entity, "Invalid entity"); - - if (!Has(entity)) - { - entity->RegisterEntityList(this); - - m_entityBits.UnboundedSet(entity->GetId(), true); - m_world = entity->GetWorld(); - } - } - /*! * \brief Removes the entity from the set * @@ -167,40 +99,6 @@ namespace Ndk return m_entityBits.Count(); } - inline EntityList& EntityList::operator=(const EntityList& entityList) - { - for (const Ndk::EntityHandle& entity : *this) - entity->UnregisterEntityList(this); - - m_entityBits = entityList.m_entityBits; - m_world = entityList.m_world; - - for (const Ndk::EntityHandle& entity : *this) - entity->RegisterEntityList(this); - - return *this; - } - - inline EntityList& EntityList::operator=(EntityList&& entityList) noexcept - { - if (this == &entityList) - return *this; - - for (const Ndk::EntityHandle& entity : *this) - entity->UnregisterEntityList(this); - - m_entityBits = std::move(entityList.m_entityBits); - m_world = entityList.m_world; - - for (const Ndk::EntityHandle& entity : *this) - { - entity->UnregisterEntityList(&entityList); - entity->RegisterEntityList(this); - } - - return *this; - } - inline std::size_t EntityList::FindNext(std::size_t currentId) const { return m_entityBits.FindNext(currentId); @@ -218,6 +116,11 @@ namespace Ndk m_entityBits.Reset(entity->GetId()); } + inline void EntityList::SetWorld(World* world) + { + m_world = world; + } + inline EntityList::iterator::iterator(const EntityList* list, std::size_t nextId) : m_nextEntityId(nextId), diff --git a/include/NazaraSDK/Sdk.hpp b/include/NazaraSDK/Sdk.hpp index 4d86229d1..3be008c22 100644 --- a/include/NazaraSDK/Sdk.hpp +++ b/include/NazaraSDK/Sdk.hpp @@ -17,11 +17,6 @@ #include #include -#ifndef NDK_SERVER -#include -#include -#endif - namespace Ndk { class NDK_API Sdk : public Nz::ModuleBase @@ -29,13 +24,7 @@ namespace Ndk friend ModuleBase; public: - using CommonDependencies = Nz::TypeList; -#ifdef NDK_SERVER - using Dependencies = CommonDependencies; -#else - using ClientDependencies = Nz::TypeList; - using Dependencies = Nz::TypeListConcat; -#endif + using Dependencies = Nz::TypeList; struct Config {}; diff --git a/include/NazaraSDK/Systems/ListenerSystem.hpp b/include/NazaraSDK/Systems/ListenerSystem.hpp index 3c9317e0d..b7d98cc4e 100644 --- a/include/NazaraSDK/Systems/ListenerSystem.hpp +++ b/include/NazaraSDK/Systems/ListenerSystem.hpp @@ -4,15 +4,15 @@ #pragma once -#ifndef NDK_SERVER #ifndef NDK_SYSTEMS_LISTENERSYSTEM_HPP #define NDK_SYSTEMS_LISTENERSYSTEM_HPP -#include + #include + #include namespace Ndk { - class NDK_API ListenerSystem : public System + class NDK_CLIENT_API ListenerSystem : public System { public: ListenerSystem(); @@ -28,4 +28,3 @@ namespace Ndk #include #endif // NDK_SYSTEMS_LISTENERSYSTEM_HPP -#endif // NDK_SERVER diff --git a/include/NazaraSDK/World.hpp b/include/NazaraSDK/World.hpp index b8765d379..346cb665d 100644 --- a/include/NazaraSDK/World.hpp +++ b/include/NazaraSDK/World.hpp @@ -26,18 +26,17 @@ namespace Ndk { friend BaseSystem; friend Entity; + friend EntityList; public: using EntityVector = std::vector; struct ProfilerData; - inline World(bool addDefaultSystems = true); + inline World(); World(const World&) = delete; inline World(World&& world) noexcept; ~World() noexcept; - void AddDefaultSystems(); - inline BaseSystem& AddSystem(std::unique_ptr&& system); template SystemType& AddSystem(Args&&... args); @@ -97,7 +96,9 @@ namespace Ndk inline void Invalidate(); inline void Invalidate(EntityId id); inline void InvalidateSystemOrder(); + inline void RegisterEntityList(EntityList* list); void ReorderSystems(); + inline void UnregisterEntityList(EntityList* list); struct DoubleBitset { @@ -123,6 +124,7 @@ namespace Ndk std::vector m_orderedSystems; std::vector m_entities; std::vector m_entityBlocks; + std::vector m_referencedByLists; std::vector> m_waitingEntities; EntityList m_aliveEntities; ProfilerData m_profilerData; diff --git a/include/NazaraSDK/World.inl b/include/NazaraSDK/World.inl index e0c60d4c4..4507a1b6b 100644 --- a/include/NazaraSDK/World.inl +++ b/include/NazaraSDK/World.inl @@ -10,16 +10,12 @@ namespace Ndk { /*! * \brief Constructs a World object - * - * \param addDefaultSystems Should default provided systems be used */ - inline World::World(bool addDefaultSystems) : + inline World::World() : m_orderedSystemsUpdated(false), m_isProfilerEnabled(false) { - if (addDefaultSystems) - AddDefaultSystems(); } /*! @@ -443,25 +439,31 @@ namespace Ndk m_dirtyEntities = std::move(world.m_dirtyEntities); m_entityBlocks = std::move(world.m_entityBlocks); m_freeEntityIds = std::move(world.m_freeEntityIds); + m_isProfilerEnabled = world.m_isProfilerEnabled; m_killedEntities = std::move(world.m_killedEntities); m_orderedSystems = std::move(world.m_orderedSystems); m_orderedSystemsUpdated = world.m_orderedSystemsUpdated; m_profilerData = std::move(world.m_profilerData); - m_isProfilerEnabled = world.m_isProfilerEnabled; + m_referencedByLists = std::move(world.m_referencedByLists); m_entities = std::move(world.m_entities); for (EntityBlock& block : m_entities) block.entity.SetWorld(this); + for (EntityList* list : m_referencedByLists) + list->SetWorld(this); + m_waitingEntities = std::move(world.m_waitingEntities); for (auto& blockPtr : m_waitingEntities) blockPtr->entity.SetWorld(this); m_systems = std::move(world.m_systems); for (const auto& systemPtr : m_systems) + { if (systemPtr) systemPtr->SetWorld(this); - + } + return *this; } @@ -480,4 +482,19 @@ namespace Ndk { m_orderedSystemsUpdated = false; } + + inline void World::RegisterEntityList(EntityList* list) + { + m_referencedByLists.push_back(list); + } + + inline void World::UnregisterEntityList(EntityList* list) + { + auto it = std::find(m_referencedByLists.begin(), m_referencedByLists.end(), list); + assert(it != m_referencedByLists.end()); + + // Swap and pop idiom + *it = m_referencedByLists.back(); + m_referencedByLists.pop_back(); + } } diff --git a/plugins/Assimp/CustomStream.cpp b/plugins/Assimp/CustomStream.cpp index 4e8392aad..d7ae0db27 100644 --- a/plugins/Assimp/CustomStream.cpp +++ b/plugins/Assimp/CustomStream.cpp @@ -79,28 +79,28 @@ aiFile* StreamOpener(aiFileIO* fileIO, const char* filePath, const char* openMod stream = reinterpret_cast(fileIOUserdata->originalStream); else { - ErrorFlags errFlags(ErrorFlag_ThrowExceptionDisabled, true); + ErrorFlags errFlags(ErrorMode::ThrowExceptionDisabled, true); ///TODO: Move to File::DecodeOpenMode OpenModeFlags openModeEnum = 0; if (std::strchr(openMode, 'r')) { - openModeEnum |= OpenMode_ReadOnly; + openModeEnum |= OpenMode::ReadOnly; if (std::strchr(openMode, '+')) - openModeEnum |= OpenMode_ReadWrite | OpenMode_MustExist; + openModeEnum |= OpenMode_ReadWrite | OpenMode::MustExist; } else if (std::strchr(openMode, 'w')) { - openModeEnum |= OpenMode_WriteOnly | OpenMode_Truncate; + openModeEnum |= OpenMode::WriteOnly | OpenMode::Truncate; if (std::strchr(openMode, '+')) - openModeEnum |= OpenMode_ReadOnly; + openModeEnum |= OpenMode::ReadOnly; } else if (std::strchr(openMode, 'a')) { - openModeEnum |= OpenMode_WriteOnly | OpenMode_Append; + openModeEnum |= OpenMode::WriteOnly | OpenMode::Append; if (std::strchr(openMode, '+')) - openModeEnum |= OpenMode_ReadOnly; + openModeEnum |= OpenMode::ReadOnly; } else { @@ -109,7 +109,7 @@ aiFile* StreamOpener(aiFileIO* fileIO, const char* filePath, const char* openMod } if (!std::strchr(openMode, 'b')) - openModeEnum |= OpenMode_Text; + openModeEnum |= OpenMode::Text; std::unique_ptr file = std::make_unique(); if (!file->Open(filePath, openModeEnum)) diff --git a/plugins/Assimp/CustomStream.hpp b/plugins/Assimp/CustomStream.hpp index 9ba461527..4b252b678 100644 --- a/plugins/Assimp/CustomStream.hpp +++ b/plugins/Assimp/CustomStream.hpp @@ -21,11 +21,11 @@ size_t StreamWrite(aiFile* file, const char* buffer, size_t size, size_t count); struct FileIOUserdata { - Nz::Stream* originalStream; - const char* originalFilePath; + Nz::Stream* originalStream; + const char* originalFilePath; }; aiFile* StreamOpener(aiFileIO* fileIO, const char* filePath, const char* openMode); void StreamCloser(aiFileIO* fileIO, aiFile* file); -#endif // NAZARA_ASSIMP_CUSTOM_STREAM_HPP \ No newline at end of file +#endif // NAZARA_ASSIMP_CUSTOM_STREAM_HPP diff --git a/plugins/Assimp/Plugin.cpp b/plugins/Assimp/Plugin.cpp index 10c1d1327..62c35a6f0 100644 --- a/plugins/Assimp/Plugin.cpp +++ b/plugins/Assimp/Plugin.cpp @@ -23,6 +23,7 @@ SOFTWARE. */ #include +#include #include #include #include @@ -35,6 +36,7 @@ SOFTWARE. #include #include #include +#include #include #include #include @@ -73,9 +75,13 @@ void ProcessJoints(aiNode* node, Skeleton* skeleton, const std::set ProcessJoints(node->mChildren[i], skeleton, joints); } -bool IsSupported(const std::string& extension) +bool IsSupported(const std::string_view& extension) { - std::string dotExt = '.' + extension; + std::string dotExt; + dotExt.reserve(extension.size() + 1); + dotExt += '.'; + dotExt += extension; + return (aiIsExtensionSupported(dotExt.data()) == AI_TRUE); } @@ -83,12 +89,12 @@ Ternary CheckAnimation(Stream& /*stream*/, const AnimationParams& parameters) { bool skip; if (parameters.custom.GetBooleanParameter("SkipAssimpLoader", &skip) && skip) - return Ternary_False; + return Ternary::False; - return Ternary_Unknown; + return Ternary::Unknown; } -AnimationRef LoadAnimation(Stream& stream, const AnimationParams& parameters) +std::shared_ptr LoadAnimation(Stream& stream, const AnimationParams& parameters) { std::string streamPath = stream.GetPath().generic_u8string(); @@ -140,7 +146,7 @@ AnimationRef LoadAnimation(Stream& stream, const AnimationParams& parameters) maxFrameCount = std::max({ maxFrameCount, nodeAnim->mNumPositionKeys, nodeAnim->mNumRotationKeys, nodeAnim->mNumScalingKeys }); } - AnimationRef anim = Animation::New(); + std::shared_ptr anim = std::make_shared(); anim->CreateSkeletal(maxFrameCount, animation->mNumChannels); @@ -178,12 +184,12 @@ Ternary CheckMesh(Stream& /*stream*/, const MeshParams& parameters) { bool skip; if (parameters.custom.GetBooleanParameter("SkipAssimpLoader", &skip) && skip) - return Ternary_False; + return Ternary::False; - return Ternary_Unknown; + return Ternary::Unknown; } -MeshRef LoadMesh(Stream& stream, const MeshParams& parameters) +std::shared_ptr LoadMesh(Stream& stream, const MeshParams& parameters) { std::string streamPath = stream.GetPath().generic_u8string(); @@ -220,19 +226,21 @@ MeshRef LoadMesh(Stream& stream, const MeshParams& parameters) int excludedComponents = 0; - if (!parameters.vertexDeclaration->HasComponent(VertexComponent_Color)) + if (!parameters.vertexDeclaration->HasComponent(VertexComponent::Color)) excludedComponents |= aiComponent_COLORS; - if (!parameters.vertexDeclaration->HasComponent(VertexComponent_Normal)) + if (!parameters.vertexDeclaration->HasComponent(VertexComponent::Normal)) excludedComponents |= aiComponent_NORMALS; - if (!parameters.vertexDeclaration->HasComponent(VertexComponent_Tangent)) + if (!parameters.vertexDeclaration->HasComponent(VertexComponent::Tangent)) excludedComponents |= aiComponent_TANGENTS_AND_BITANGENTS; - if (!parameters.vertexDeclaration->HasComponent(VertexComponent_TexCoord)) + if (!parameters.vertexDeclaration->HasComponent(VertexComponent::TexCoord)) excludedComponents |= aiComponent_TEXCOORDS; aiPropertyStore* properties = aiCreatePropertyStore(); + CallOnExit releaseProperties([&] { aiReleasePropertyStore(properties); }); + aiSetImportPropertyFloat(properties, AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE, float(smoothingAngle)); aiSetImportPropertyInteger(properties, AI_CONFIG_PP_LBW_MAX_WEIGHTS, 4); aiSetImportPropertyInteger(properties, AI_CONFIG_PP_SBP_REMOVE, ~aiPrimitiveType_TRIANGLE); //< We only want triangles @@ -241,7 +249,9 @@ MeshRef LoadMesh(Stream& stream, const MeshParams& parameters) aiSetImportPropertyInteger(properties, AI_CONFIG_PP_RVC_FLAGS, excludedComponents); const aiScene* scene = aiImportFileExWithProperties(userdata.originalFilePath, postProcess, &fileIO, properties); - aiReleasePropertyStore(properties); + CallOnExit releaseScene([&] { aiReleaseImport(scene); }); + + releaseProperties.CallAndReset(); if (!scene) { @@ -266,7 +276,7 @@ MeshRef LoadMesh(Stream& stream, const MeshParams& parameters) } } - MeshRef mesh = Mesh::New(); + std::shared_ptr mesh = std::make_shared(); if (animatedMesh) { mesh->CreateSkeletal(UInt32(joints.size())); @@ -297,9 +307,9 @@ MeshRef LoadMesh(Stream& stream, const MeshParams& parameters) // Index buffer bool largeIndices = (vertexCount > std::numeric_limits::max()); - IndexBufferRef indexBuffer = IndexBuffer::New(largeIndices, indexCount, parameters.storage, parameters.indexBufferFlags); + std::shared_ptr indexBuffer = std::make_shared(largeIndices, indexCount, parameters.storage, parameters.indexBufferFlags); - IndexMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite); + IndexMapper indexMapper(*indexBuffer, BufferAccess::DiscardAndWrite); IndexIterator index = indexMapper.begin(); for (unsigned int faceIdx = 0; faceIdx < iMesh->mNumFaces; ++faceIdx) @@ -319,8 +329,8 @@ MeshRef LoadMesh(Stream& stream, const MeshParams& parameters) if (normalTangentMatrix.HasScale()) normalTangentMatrix.ApplyScale(1.f / normalTangentMatrix.GetScale()); - VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent_Skinning), vertexCount, parameters.storage, parameters.vertexBufferFlags); - BufferMapper vertexMapper(vertexBuffer, BufferAccess_ReadWrite); + std::shared_ptr vertexBuffer = std::make_shared(VertexDeclaration::Get(VertexLayout::XYZ_Normal_UV_Tangent_Skinning), vertexCount, parameters.storage, parameters.vertexBufferFlags); + BufferMapper vertexMapper(*vertexBuffer, BufferAccess::ReadWrite); SkeletalMeshVertex* vertices = static_cast(vertexMapper.GetPointer()); for (std::size_t vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) @@ -352,7 +362,7 @@ MeshRef LoadMesh(Stream& stream, const MeshParams& parameters) } // Submesh - SkeletalMeshRef subMesh = SkeletalMesh::New(vertexBuffer, indexBuffer); + std::shared_ptr subMesh = std::make_shared(vertexBuffer, indexBuffer); subMesh->SetMaterialIndex(iMesh->mMaterialIndex); auto matIt = materials.find(iMesh->mMaterialIndex); @@ -380,20 +390,20 @@ MeshRef LoadMesh(Stream& stream, const MeshParams& parameters) if (wrapKey) { - SamplerWrap wrap = SamplerWrap_Clamp; + SamplerWrap wrap = SamplerWrap::Clamp; switch (mapMode[0]) { case aiTextureMapMode_Clamp: case aiTextureMapMode_Decal: - wrap = SamplerWrap_Clamp; + wrap = SamplerWrap::Clamp; break; case aiTextureMapMode_Mirror: - wrap = SamplerWrap_MirroredRepeat; + wrap = SamplerWrap::MirroredRepeat; break; case aiTextureMapMode_Wrap: - wrap = SamplerWrap_Repeat; + wrap = SamplerWrap::Repeat; break; default: @@ -455,9 +465,9 @@ MeshRef LoadMesh(Stream& stream, const MeshParams& parameters) // Index buffer bool largeIndices = (vertexCount > std::numeric_limits::max()); - IndexBufferRef indexBuffer = IndexBuffer::New(largeIndices, indexCount, parameters.storage, parameters.indexBufferFlags); + std::shared_ptr indexBuffer = std::make_shared(largeIndices, indexCount, parameters.storage, parameters.indexBufferFlags); - IndexMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite); + IndexMapper indexMapper(*indexBuffer, BufferAccess::DiscardAndWrite); IndexIterator index = indexMapper.begin(); for (unsigned int faceIdx = 0; faceIdx < iMesh->mNumFaces; ++faceIdx) @@ -479,18 +489,18 @@ MeshRef LoadMesh(Stream& stream, const MeshParams& parameters) if (normalTangentMatrix.HasScale()) normalTangentMatrix.ApplyScale(1.f / normalTangentMatrix.GetScale()); - VertexBufferRef vertexBuffer = VertexBuffer::New(parameters.vertexDeclaration, vertexCount, parameters.storage, parameters.vertexBufferFlags); + std::shared_ptr vertexBuffer = std::make_shared(parameters.vertexDeclaration, vertexCount, parameters.storage, parameters.vertexBufferFlags); - VertexMapper vertexMapper(vertexBuffer, BufferAccess_DiscardAndWrite); + VertexMapper vertexMapper(*vertexBuffer, BufferAccess::DiscardAndWrite); - auto posPtr = vertexMapper.GetComponentPtr(VertexComponent_Position); + auto posPtr = vertexMapper.GetComponentPtr(VertexComponent::Position); for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) { aiVector3D position = iMesh->mVertices[vertexIdx]; *posPtr++ = parameters.matrix * Vector3f(position.x, position.y, position.z); } - if (auto normalPtr = vertexMapper.GetComponentPtr(VertexComponent_Normal)) + if (auto normalPtr = vertexMapper.GetComponentPtr(VertexComponent::Normal)) { for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) { @@ -500,7 +510,7 @@ MeshRef LoadMesh(Stream& stream, const MeshParams& parameters) } bool generateTangents = false; - if (auto tangentPtr = vertexMapper.GetComponentPtr(VertexComponent_Tangent)) + if (auto tangentPtr = vertexMapper.GetComponentPtr(VertexComponent::Tangent)) { if (iMesh->HasTangentsAndBitangents()) { @@ -514,7 +524,7 @@ MeshRef LoadMesh(Stream& stream, const MeshParams& parameters) generateTangents = true; } - if (auto uvPtr = vertexMapper.GetComponentPtr(VertexComponent_TexCoord)) + if (auto uvPtr = vertexMapper.GetComponentPtr(VertexComponent::TexCoord)) { if (iMesh->HasTextureCoords(0)) { @@ -534,7 +544,7 @@ MeshRef LoadMesh(Stream& stream, const MeshParams& parameters) vertexMapper.Unmap(); // Submesh - StaticMeshRef subMesh = StaticMesh::New(vertexBuffer, indexBuffer); + std::shared_ptr subMesh = std::make_shared(vertexBuffer, indexBuffer); subMesh->GenerateAABB(); subMesh->SetMaterialIndex(iMesh->mMaterialIndex); @@ -566,20 +576,20 @@ MeshRef LoadMesh(Stream& stream, const MeshParams& parameters) if (wrapKey) { - SamplerWrap wrap = SamplerWrap_Clamp; + SamplerWrap wrap = SamplerWrap::Clamp; switch (mapMode[0]) { case aiTextureMapMode_Clamp: case aiTextureMapMode_Decal: - wrap = SamplerWrap_Clamp; + wrap = SamplerWrap::Clamp; break; case aiTextureMapMode_Mirror: - wrap = SamplerWrap_MirroredRepeat; + wrap = SamplerWrap::MirroredRepeat; break; case aiTextureMapMode_Wrap: - wrap = SamplerWrap_Repeat; + wrap = SamplerWrap::Repeat; break; default: @@ -628,23 +638,54 @@ MeshRef LoadMesh(Stream& stream, const MeshParams& parameters) mesh->Recenter(); } - aiReleaseImport(scene); - return mesh; } +namespace +{ + const Nz::AnimationLoader::Entry* animationLoaderEntry = nullptr; + const Nz::MeshLoader::Entry* meshLoaderEntry = nullptr; +} + extern "C" { NAZARA_EXPORT int PluginLoad() { - Nz::AnimationLoader::RegisterLoader(IsSupported, CheckAnimation, LoadAnimation); - Nz::MeshLoader::RegisterLoader(IsSupported, CheckMesh, LoadMesh); + Nz::Utility* utility = Nz::Utility::Instance(); + NazaraAssert(utility, "utility module is not instancied"); + + Nz::AnimationLoader& animationLoader = utility->GetAnimationLoader(); + animationLoaderEntry = animationLoader.RegisterLoader({ + IsSupported, + nullptr, + nullptr, + CheckAnimation, + LoadAnimation + }); + + Nz::MeshLoader& meshLoader = utility->GetMeshLoader(); + meshLoaderEntry = meshLoader.RegisterLoader({ + IsSupported, + nullptr, + nullptr, + CheckMesh, + LoadMesh + }); + return 1; } NAZARA_EXPORT void PluginUnload() { - Nz::AnimationLoader::RegisterLoader(IsSupported, CheckAnimation, LoadAnimation); - Nz::MeshLoader::UnregisterLoader(IsSupported, CheckMesh, LoadMesh); + Nz::Utility* utility = Nz::Utility::Instance(); + NazaraAssert(utility, "utility module is not instancied"); + + Nz::AnimationLoader& animationLoader = utility->GetAnimationLoader(); + animationLoader.UnregisterLoader(animationLoaderEntry); + animationLoaderEntry = nullptr; + + Nz::MeshLoader& meshLoader = utility->GetMeshLoader(); + meshLoader.UnregisterLoader(meshLoaderEntry); + meshLoaderEntry = nullptr; } } diff --git a/plugins/Assimp/xmake.lua b/plugins/Assimp/xmake.lua new file mode 100644 index 000000000..c2a7cc1b6 --- /dev/null +++ b/plugins/Assimp/xmake.lua @@ -0,0 +1,13 @@ +add_requires("assimp") + +target("PluginAssimp") + set_kind("shared") + set_group("Plugins") + + add_deps("NazaraUtility") + add_packages("assimp") + + add_headerfiles("**.hpp") + add_headerfiles("**.inl") + add_includedirs(".") + add_files("**.cpp") diff --git a/readme.md b/readme.md index 2eaabc09e..320c7fe7c 100644 --- a/readme.md +++ b/readme.md @@ -5,7 +5,7 @@ Linux | [![Travis CI Build Status](https://travis-ci.org/DigitalPulseSoftware/Na # Nazara Engine -Nazara Engine is a fast, complete, cross-platform, object-oriented API which can help you in your daily developper life. +Nazara Engine is a fast, complete, cross-platform, object-oriented API which can help you in your daily developer life. Its goal is to provide a set of useful classes : Its core provides unicode strings, filesystem access, hashs, threads, ... It also provide a set of libraries, such as audio, network, physics, renderer, 2D and 3D graphics engines, ... diff --git a/shaders/BasicMaterial/basicmaterial.frag.shaderflow b/shaders/BasicMaterial/basicmaterial.frag.shaderflow new file mode 100644 index 000000000..ead0fa7f7 --- /dev/null +++ b/shaders/BasicMaterial/basicmaterial.frag.shaderflow @@ -0,0 +1,690 @@ +{ + "buffers": [ + { + "bindingIndex": 5, + "name": "viewerData", + "structIndex": 2, + "type": "UniformBufferObject" + }, + { + "bindingIndex": 4, + "name": "instanceData", + "structIndex": 1, + "type": "UniformBufferObject" + }, + { + "bindingIndex": 3, + "name": "settings", + "structIndex": 0, + "type": "UniformBufferObject" + } + ], + "conditions": [ + { + "name": "HAS_DIFFUSE_TEXTURE" + }, + { + "name": "HAS_ALPHA_TEXTURE" + }, + { + "name": "ALPHA_TEST" + } + ], + "connections": [ + { + "in_id": "{359a78e1-df0d-467f-907e-7bff04a55db5}", + "in_index": 3, + "out_id": "{93fdbb4c-bc81-4100-89a9-b465793099b9}", + "out_index": 0 + }, + { + "in_id": "{359a78e1-df0d-467f-907e-7bff04a55db5}", + "in_index": 0, + "out_id": "{becdd0d4-2b28-44f5-86c2-2ed6b846326c}", + "out_index": 0 + }, + { + "in_id": "{92d95fe0-84f6-4d27-91ea-992d5f73c04e}", + "in_index": 0, + "out_id": "{359a78e1-df0d-467f-907e-7bff04a55db5}", + "out_index": 0 + }, + { + "in_id": "{bed466d8-5ed0-4e8a-bba7-1c809cb4c3f7}", + "in_index": 1, + "out_id": "{07a43c79-67e2-46b1-87d4-e00d2da22820}", + "out_index": 0 + }, + { + "in_id": "{93fdbb4c-bc81-4100-89a9-b465793099b9}", + "in_index": 0, + "out_id": "{6fcfbcd0-c2df-41dd-bb50-74b455b9021f}", + "out_index": 0 + }, + { + "in_id": "{becdd0d4-2b28-44f5-86c2-2ed6b846326c}", + "in_index": 0, + "out_id": "{f5a6874b-0559-4fd1-9836-27567f9696a4}", + "out_index": 0 + }, + { + "in_id": "{f5a6874b-0559-4fd1-9836-27567f9696a4}", + "in_index": 0, + "out_id": "{cf0ae20a-88cd-4788-9ed7-eaf014d8f971}", + "out_index": 0 + }, + { + "in_id": "{92d95fe0-84f6-4d27-91ea-992d5f73c04e}", + "in_index": 1, + "out_id": "{f5a6874b-0559-4fd1-9836-27567f9696a4}", + "out_index": 0 + }, + { + "in_id": "{be3547ff-0bf3-4701-9c27-c21e9d1322c3}", + "in_index": 0, + "out_id": "{92d95fe0-84f6-4d27-91ea-992d5f73c04e}", + "out_index": 0 + }, + { + "in_id": "{e1f86d56-eb21-4267-9075-e6b0cc875a6d}", + "in_index": 0, + "out_id": "{bed466d8-5ed0-4e8a-bba7-1c809cb4c3f7}", + "out_index": 0 + }, + { + "in_id": "{93fdbb4c-bc81-4100-89a9-b465793099b9}", + "in_index": 1, + "out_id": "{becdd0d4-2b28-44f5-86c2-2ed6b846326c}", + "out_index": 3 + }, + { + "in_id": "{359a78e1-df0d-467f-907e-7bff04a55db5}", + "in_index": 2, + "out_id": "{becdd0d4-2b28-44f5-86c2-2ed6b846326c}", + "out_index": 2 + }, + { + "in_id": "{fbaddbbe-f9cd-4e8d-b7a8-40c10c96f580}", + "in_index": 0, + "out_id": "{ac98a68f-0160-4189-af31-b8278e7c119c}", + "out_index": 0 + }, + { + "in_id": "{7750a050-b116-4e1b-bd89-b194c366d256}", + "in_index": 1, + "out_id": "{ca2c2ac5-39e0-4814-9432-fbf3e20d3cad}", + "out_index": 0 + }, + { + "in_id": "{3cdb5bb1-f572-4055-a1af-460b152b0c13}", + "in_index": 0, + "out_id": "{d7acd173-9188-43b5-bfa1-31f17dff44ad}", + "out_index": 0 + }, + { + "in_id": "{cf0ae20a-88cd-4788-9ed7-eaf014d8f971}", + "in_index": 0, + "out_id": "{c41cd67b-2f34-4ec4-acc6-2f7285e7c6e3}", + "out_index": 0 + }, + { + "in_id": "{e1f86d56-eb21-4267-9075-e6b0cc875a6d}", + "in_index": 1, + "out_id": "{07a43c79-67e2-46b1-87d4-e00d2da22820}", + "out_index": 0 + }, + { + "in_id": "{359a78e1-df0d-467f-907e-7bff04a55db5}", + "in_index": 1, + "out_id": "{becdd0d4-2b28-44f5-86c2-2ed6b846326c}", + "out_index": 1 + }, + { + "in_id": "{fbaddbbe-f9cd-4e8d-b7a8-40c10c96f580}", + "in_index": 1, + "out_id": "{db10f064-504d-4072-a49e-51a061b2efbe}", + "out_index": 0 + }, + { + "in_id": "{d7acd173-9188-43b5-bfa1-31f17dff44ad}", + "in_index": 1, + "out_id": "{1f9d52d7-4f44-4d96-8edb-fbc1239a93bb}", + "out_index": 0 + }, + { + "in_id": "{bed466d8-5ed0-4e8a-bba7-1c809cb4c3f7}", + "in_index": 0, + "out_id": "{fbaddbbe-f9cd-4e8d-b7a8-40c10c96f580}", + "out_index": 0 + }, + { + "in_id": "{f5a6874b-0559-4fd1-9836-27567f9696a4}", + "in_index": 1, + "out_id": "{e1f86d56-eb21-4267-9075-e6b0cc875a6d}", + "out_index": 0 + }, + { + "in_id": "{cf0ae20a-88cd-4788-9ed7-eaf014d8f971}", + "in_index": 1, + "out_id": "{74d3ca95-ae1d-496d-88c1-ce6c7327012a}", + "out_index": 0 + }, + { + "in_id": "{bb071807-e65e-4c31-acf0-d296efa665fa}", + "in_index": 0, + "out_id": "{92d95fe0-84f6-4d27-91ea-992d5f73c04e}", + "out_index": 0 + }, + { + "in_id": "{7750a050-b116-4e1b-bd89-b194c366d256}", + "in_index": 0, + "out_id": "{f9ba0cce-3b85-4f95-a79e-a2f64d955d89}", + "out_index": 0 + }, + { + "in_id": "{6fcfbcd0-c2df-41dd-bb50-74b455b9021f}", + "in_index": 0, + "out_id": "{7750a050-b116-4e1b-bd89-b194c366d256}", + "out_index": 0 + }, + { + "in_id": "{d7acd173-9188-43b5-bfa1-31f17dff44ad}", + "in_index": 0, + "out_id": "{fc7542b2-5752-4891-98c1-35b498da257b}", + "out_index": 0 + }, + { + "in_id": "{fc7542b2-5752-4891-98c1-35b498da257b}", + "in_index": 1, + "out_id": "{743930bd-1d81-4d4c-b7ec-175a34838d69}", + "out_index": 0 + }, + { + "in_id": "{fc7542b2-5752-4891-98c1-35b498da257b}", + "in_index": 0, + "out_id": "{bb071807-e65e-4c31-acf0-d296efa665fa}", + "out_index": 3 + } + ], + "inputs": [ + { + "locationIndex": 0, + "name": "vertNormal", + "role": "Normal", + "roleIndex": 0, + "type": "Float3" + }, + { + "locationIndex": 1, + "name": "vertUV", + "role": "TexCoord", + "roleIndex": 0, + "type": "Float2" + } + ], + "nodes": [ + { + "id": "{c41cd67b-2f34-4ec4-acc6-2f7285e7c6e3}", + "model": { + "input": "vertNormal", + "name": "Input", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 330.0833333333333, + "y": 236.19444444444446 + } + }, + { + "id": "{becdd0d4-2b28-44f5-86c2-2ed6b846326c}", + "model": { + "name": "vec_decompose", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 1022.5200000000003, + "y": -53.35999999999996 + } + }, + { + "id": "{cf0ae20a-88cd-4788-9ed7-eaf014d8f971}", + "model": { + "name": "vec_dot", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "lightFactor" + }, + "position": { + "x": 486.33333333333326, + "y": 285.61111111111114 + } + }, + { + "id": "{74d3ca95-ae1d-496d-88c1-ce6c7327012a}", + "model": { + "name": "vec3_constant", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "value": [ + 0, + -0.7070000171661377, + 0.7070000171661377 + ], + "variable_name": "lightDir" + }, + "position": { + "x": 294.1666666666667, + "y": 358.6666666666667 + } + }, + { + "id": "{fbaddbbe-f9cd-4e8d-b7a8-40c10c96f580}", + "model": { + "name": "SampleTexture", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 167.75, + "y": 473.97222222222194 + } + }, + { + "id": "{ac98a68f-0160-4189-af31-b8278e7c119c}", + "model": { + "name": "Texture", + "preview_enabled": true, + "preview_height": 64, + "preview_width": 64, + "texture": "MaterialDiffuseMap", + "variable_name": "" + }, + "position": { + "x": -10.194444444444457, + "y": 445 + } + }, + { + "id": "{db10f064-504d-4072-a49e-51a061b2efbe}", + "model": { + "input": "vertUV", + "name": "Input", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": -0.19444444444445708, + "y": 554.0000000000001 + } + }, + { + "id": "{f5a6874b-0559-4fd1-9836-27567f9696a4}", + "model": { + "name": "vecfloat_mul", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "textureColor" + }, + "position": { + "x": 1055.9166666666665, + "y": 458.6388888888888 + } + }, + { + "id": "{93fdbb4c-bc81-4100-89a9-b465793099b9}", + "model": { + "name": "float_mul", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 1051.286666666667, + "y": 195.20666666666665 + } + }, + { + "id": "{be3547ff-0bf3-4701-9c27-c21e9d1322c3}", + "model": { + "name": "Output", + "output": "RenderTarget0", + "preview_enabled": true, + "preview_height": 128, + "preview_width": 128, + "variable_name": "" + }, + "position": { + "x": 2598.5, + "y": 293.33333333333326 + } + }, + { + "id": "{bed466d8-5ed0-4e8a-bba7-1c809cb4c3f7}", + "model": { + "name": "vec_mul", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 377.1388888888888, + "y": 507.83333333333337 + } + }, + { + "id": "{07a43c79-67e2-46b1-87d4-e00d2da22820}", + "model": { + "buffer": "settings", + "field": "DiffuseColor", + "name": "BufferField", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 135.11111111111126, + "y": 643.5277777777775 + } + }, + { + "id": "{e1f86d56-eb21-4267-9075-e6b0cc875a6d}", + "model": { + "condition_name": "HAS_DIFFUSE_TEXTURE", + "name": "ConditionalExpression", + "preview_enabled": true, + "preview_height": 128, + "preview_width": 128, + "variable_name": "" + }, + "position": { + "x": 602.5, + "y": 566.5 + } + }, + { + "id": "{ca2c2ac5-39e0-4814-9432-fbf3e20d3cad}", + "model": { + "input": "vertUV", + "name": "Input", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 344.36666666666684, + "y": 53.300000000000026 + } + }, + { + "id": "{f9ba0cce-3b85-4f95-a79e-a2f64d955d89}", + "model": { + "name": "Texture", + "preview_enabled": true, + "preview_height": 64, + "preview_width": 64, + "texture": "MaterialAlphaMap", + "variable_name": "" + }, + "position": { + "x": 344.59999999999985, + "y": -35.10000000000005 + } + }, + { + "id": "{7750a050-b116-4e1b-bd89-b194c366d256}", + "model": { + "name": "SampleTexture", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 491.0333333333334, + "y": 18.366666666666674 + } + }, + { + "id": "{6fcfbcd0-c2df-41dd-bb50-74b455b9021f}", + "model": { + "name": "vec_decompose", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 682.0999999999998, + "y": 19.88000000000003 + } + }, + { + "id": "{359a78e1-df0d-467f-907e-7bff04a55db5}", + "model": { + "name": "vec_compose4", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 1240.62, + "y": -41.900000000000034 + } + }, + { + "id": "{bb071807-e65e-4c31-acf0-d296efa665fa}", + "model": { + "name": "vec_decompose", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 2270, + "y": 67 + } + }, + { + "id": "{92d95fe0-84f6-4d27-91ea-992d5f73c04e}", + "model": { + "condition_name": "HAS_ALPHA_TEXTURE", + "name": "ConditionalExpression", + "preview_enabled": true, + "preview_height": 128, + "preview_width": 128, + "variable_name": "" + }, + "position": { + "x": 1415.8933333333334, + "y": 135.44000000000005 + } + }, + { + "id": "{3cdb5bb1-f572-4055-a1af-460b152b0c13}", + "model": { + "name": "Discard", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 2694, + "y": 4 + } + }, + { + "id": "{d7acd173-9188-43b5-bfa1-31f17dff44ad}", + "model": { + "condition_name": "ALPHA_TEST", + "name": "ConditionalExpression", + "preview_enabled": true, + "preview_height": 128, + "preview_width": 128, + "variable_name": "" + }, + "position": { + "x": 2240, + "y": -174 + } + }, + { + "id": "{1f9d52d7-4f44-4d96-8edb-fbc1239a93bb}", + "model": { + "name": "bool_constant", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "value": false, + "variable_name": "" + }, + "position": { + "x": 2005, + "y": -99 + } + }, + { + "id": "{fc7542b2-5752-4891-98c1-35b498da257b}", + "model": { + "name": "float_lt", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 2000, + "y": -241 + } + }, + { + "id": "{743930bd-1d81-4d4c-b7ec-175a34838d69}", + "model": { + "buffer": "settings", + "field": "AlphaThreshold", + "name": "BufferField", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 1675, + "y": -254 + } + } + ], + "outputs": [ + { + "locationIndex": 0, + "name": "RenderTarget0", + "type": "Float4" + } + ], + "structs": [ + { + "members": [ + { + "name": "AlphaThreshold", + "type": "Float" + }, + { + "name": "DiffuseColor", + "type": "Float4" + } + ], + "name": "BasicSettings" + }, + { + "members": [ + { + "name": "worldMatrix", + "type": "Mat4x4" + }, + { + "name": "invWorldMatrix", + "type": "Mat4x4" + } + ], + "name": "InstanceData" + }, + { + "members": [ + { + "name": "projectionMatrix", + "type": "Mat4x4" + }, + { + "name": "invProjectionMatrix", + "type": "Mat4x4" + }, + { + "name": "viewMatrix", + "type": "Mat4x4" + }, + { + "name": "invViewMatrix", + "type": "Mat4x4" + }, + { + "name": "viewProjMatrix", + "type": "Mat4x4" + }, + { + "name": "invViewProjMatrix", + "type": "Mat4x4" + }, + { + "name": "renderTargetSize", + "type": "Float2" + }, + { + "name": "invRenderTargetSize", + "type": "Float2" + }, + { + "name": "eyePosition", + "type": "Float3" + } + ], + "name": "ViewerData" + } + ], + "textures": [ + { + "bindingIndex": 0, + "name": "MaterialAlphaMap", + "type": "Sampler2D" + }, + { + "bindingIndex": 1, + "name": "MaterialDiffuseMap", + "type": "Sampler2D" + }, + { + "bindingIndex": 2, + "name": "TextureOverlay", + "type": "Sampler2D" + } + ], + "type": "Fragment" +} diff --git a/shaders/BasicMaterial/basicmaterial.vert.shaderflow b/shaders/BasicMaterial/basicmaterial.vert.shaderflow new file mode 100644 index 000000000..4f51428e2 --- /dev/null +++ b/shaders/BasicMaterial/basicmaterial.vert.shaderflow @@ -0,0 +1,394 @@ +{ + "buffers": [ + { + "bindingIndex": 5, + "name": "viewerData", + "structIndex": 2, + "type": "UniformBufferObject" + }, + { + "bindingIndex": 4, + "name": "instanceData", + "structIndex": 1, + "type": "UniformBufferObject" + }, + { + "bindingIndex": 3, + "name": "settings", + "structIndex": 0, + "type": "UniformBufferObject" + } + ], + "conditions": [ + ], + "connections": [ + { + "in_id": "{1bb9712b-8bff-4398-9e4e-fba79a04df0e}", + "in_index": 1, + "out_id": "{a2fff9e2-af6e-4c7f-80ee-ca3492f3c5ab}", + "out_index": 0 + }, + { + "in_id": "{62731a4b-f054-4f78-82da-08d2584e51ab}", + "in_index": 1, + "out_id": "{7ac65f09-7f55-4a6e-9380-1bee5213f079}", + "out_index": 0 + }, + { + "in_id": "{62731a4b-f054-4f78-82da-08d2584e51ab}", + "in_index": 0, + "out_id": "{1bb9712b-8bff-4398-9e4e-fba79a04df0e}", + "out_index": 0 + }, + { + "in_id": "{43ce1867-629f-442b-a672-540fa67f1446}", + "in_index": 0, + "out_id": "{33840c70-4e37-4127-bab0-23c4a4cb6d7f}", + "out_index": 0 + }, + { + "in_id": "{63bb13f0-55e3-451b-860e-568b65e09b04}", + "in_index": 0, + "out_id": "{62731a4b-f054-4f78-82da-08d2584e51ab}", + "out_index": 0 + }, + { + "in_id": "{7ac65f09-7f55-4a6e-9380-1bee5213f079}", + "in_index": 0, + "out_id": "{c3b906bc-d230-4026-a32e-34c00eaf4481}", + "out_index": 0 + }, + { + "in_id": "{d8f4d14a-c67a-470f-87bf-8f60d9513c3b}", + "in_index": 0, + "out_id": "{d32dfb1d-c8a4-4315-a710-90d2a51f68e8}", + "out_index": 0 + }, + { + "in_id": "{1bb9712b-8bff-4398-9e4e-fba79a04df0e}", + "in_index": 0, + "out_id": "{d8f4d14a-c67a-470f-87bf-8f60d9513c3b}", + "out_index": 0 + }, + { + "in_id": "{0fc53363-dbce-4874-8de5-5ca05ae038b7}", + "in_index": 0, + "out_id": "{412684ce-0ec2-4db5-964c-10e5b68d43e8}", + "out_index": 0 + }, + { + "in_id": "{d8f4d14a-c67a-470f-87bf-8f60d9513c3b}", + "in_index": 1, + "out_id": "{c6058af1-6913-4218-a9b9-11adb5cdffa0}", + "out_index": 0 + } + ], + "inputs": [ + { + "locationIndex": 0, + "name": "inPos", + "role": "Position", + "roleIndex": 0, + "type": "Float3" + }, + { + "locationIndex": 1, + "name": "inNormals", + "role": "Normal", + "roleIndex": 0, + "type": "Float3" + }, + { + "locationIndex": 2, + "name": "inTexCoord", + "role": "TexCoord", + "roleIndex": 0, + "type": "Float2" + } + ], + "nodes": [ + { + "id": "{43ce1867-629f-442b-a672-540fa67f1446}", + "model": { + "name": "Output", + "output": "vertUV", + "preview_enabled": false, + "preview_height": 128, + "preview_width": 128, + "variable_name": "" + }, + "position": { + "x": 243, + "y": 292 + } + }, + { + "id": "{412684ce-0ec2-4db5-964c-10e5b68d43e8}", + "model": { + "input": "inNormals", + "name": "Input", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 79, + "y": 184 + } + }, + { + "id": "{0fc53363-dbce-4874-8de5-5ca05ae038b7}", + "model": { + "name": "Output", + "output": "vertNormal", + "preview_enabled": false, + "preview_height": 128, + "preview_width": 128, + "variable_name": "" + }, + "position": { + "x": 240, + "y": 192 + } + }, + { + "id": "{33840c70-4e37-4127-bab0-23c4a4cb6d7f}", + "model": { + "input": "inTexCoord", + "name": "Input", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 82, + "y": 287 + } + }, + { + "id": "{d8f4d14a-c67a-470f-87bf-8f60d9513c3b}", + "model": { + "name": "mat4_mul", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 248, + "y": 424 + } + }, + { + "id": "{1bb9712b-8bff-4398-9e4e-fba79a04df0e}", + "model": { + "name": "mat4_mul", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 463, + "y": 496 + } + }, + { + "id": "{c3b906bc-d230-4026-a32e-34c00eaf4481}", + "model": { + "input": "inPos", + "name": "Input", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 54, + "y": 675 + } + }, + { + "id": "{62731a4b-f054-4f78-82da-08d2584e51ab}", + "model": { + "name": "mat4vec_mul", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 699, + "y": 512 + } + }, + { + "id": "{7ac65f09-7f55-4a6e-9380-1bee5213f079}", + "model": { + "name": "cast_vec4", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "value": [ + 1, + 0, + 0, + 0 + ], + "variable_name": "" + }, + "position": { + "x": 345, + "y": 668 + } + }, + { + "id": "{63bb13f0-55e3-451b-860e-568b65e09b04}", + "model": { + "name": "PositionOutputValue", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 930, + "y": 524 + } + }, + { + "id": "{d32dfb1d-c8a4-4315-a710-90d2a51f68e8}", + "model": { + "buffer": "viewerData", + "field": "projectionMatrix", + "name": "BufferField", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 21, + "y": 374 + } + }, + { + "id": "{c6058af1-6913-4218-a9b9-11adb5cdffa0}", + "model": { + "buffer": "viewerData", + "field": "viewMatrix", + "name": "BufferField", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 25, + "y": 456 + } + }, + { + "id": "{a2fff9e2-af6e-4c7f-80ee-ca3492f3c5ab}", + "model": { + "buffer": "instanceData", + "field": "worldMatrix", + "name": "BufferField", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 27, + "y": 538 + } + } + ], + "outputs": [ + { + "locationIndex": 0, + "name": "vertNormal", + "type": "Float3" + }, + { + "locationIndex": 1, + "name": "vertUV", + "type": "Float2" + } + ], + "structs": [ + { + "members": [ + { + "name": "AlphaThreshold", + "type": "Float" + }, + { + "name": "DiffuseColor", + "type": "Float4" + } + ], + "name": "BasicSettings" + }, + { + "members": [ + { + "name": "worldMatrix", + "type": "Mat4x4" + }, + { + "name": "invWorldMatrix", + "type": "Mat4x4" + } + ], + "name": "InstanceData" + }, + { + "members": [ + { + "name": "projectionMatrix", + "type": "Mat4x4" + }, + { + "name": "invProjectionMatrix", + "type": "Mat4x4" + }, + { + "name": "viewMatrix", + "type": "Mat4x4" + }, + { + "name": "invViewMatrix", + "type": "Mat4x4" + }, + { + "name": "viewProjMatrix", + "type": "Mat4x4" + }, + { + "name": "invViewProjMatrix", + "type": "Mat4x4" + }, + { + "name": "renderTargetSize", + "type": "Float2" + }, + { + "name": "invRenderTargetSize", + "type": "Float2" + }, + { + "name": "eyePosition", + "type": "Float3" + } + ], + "name": "ViewerData" + } + ], + "textures": [ + ], + "type": "Vertex" +} diff --git a/shaders/Fullscreen/basicmaterial.frag.shaderflow b/shaders/Fullscreen/basicmaterial.frag.shaderflow new file mode 100644 index 000000000..187273850 --- /dev/null +++ b/shaders/Fullscreen/basicmaterial.frag.shaderflow @@ -0,0 +1,113 @@ +{ + "buffers": [ + ], + "conditions": [ + ], + "connections": [ + { + "in_id": "{fbaddbbe-f9cd-4e8d-b7a8-40c10c96f580}", + "in_index": 1, + "out_id": "{db10f064-504d-4072-a49e-51a061b2efbe}", + "out_index": 0 + }, + { + "in_id": "{fbaddbbe-f9cd-4e8d-b7a8-40c10c96f580}", + "in_index": 0, + "out_id": "{04c30f54-5492-4b70-99fd-d6fe96c023e4}", + "out_index": 0 + }, + { + "in_id": "{38c8bbb6-6c85-49ff-abfa-e409bf0393ef}", + "in_index": 0, + "out_id": "{fbaddbbe-f9cd-4e8d-b7a8-40c10c96f580}", + "out_index": 0 + } + ], + "inputs": [ + { + "locationIndex": 0, + "name": "vertUV", + "role": "TexCoord", + "roleIndex": 0, + "type": "Float2" + } + ], + "nodes": [ + { + "id": "{fbaddbbe-f9cd-4e8d-b7a8-40c10c96f580}", + "model": { + "name": "SampleTexture", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 167.75, + "y": 473.97222222222194 + } + }, + { + "id": "{db10f064-504d-4072-a49e-51a061b2efbe}", + "model": { + "input": "vertUV", + "name": "Input", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": -0.19444444444445708, + "y": 554.0000000000001 + } + }, + { + "id": "{04c30f54-5492-4b70-99fd-d6fe96c023e4}", + "model": { + "name": "Texture", + "preview_enabled": true, + "preview_height": 64, + "preview_width": 64, + "texture": "Texture", + "variable_name": "" + }, + "position": { + "x": 21.666666666666668, + "y": 475 + } + }, + { + "id": "{38c8bbb6-6c85-49ff-abfa-e409bf0393ef}", + "model": { + "name": "Output", + "output": "RenderTarget0", + "preview_enabled": true, + "preview_height": 128, + "preview_width": 128, + "variable_name": "" + }, + "position": { + "x": 343, + "y": 482 + } + } + ], + "outputs": [ + { + "locationIndex": 0, + "name": "RenderTarget0", + "type": "Float4" + } + ], + "structs": [ + ], + "textures": [ + { + "bindingIndex": 0, + "name": "Texture", + "type": "Sampler2D" + } + ], + "type": "Fragment" +} diff --git a/shaders/Fullscreen/basicmaterial.vert.shaderflow b/shaders/Fullscreen/basicmaterial.vert.shaderflow new file mode 100644 index 000000000..9c051cc86 --- /dev/null +++ b/shaders/Fullscreen/basicmaterial.vert.shaderflow @@ -0,0 +1,135 @@ +{ + "buffers": [ + ], + "conditions": [ + ], + "connections": [ + { + "in_id": "{7ac65f09-7f55-4a6e-9380-1bee5213f079}", + "in_index": 0, + "out_id": "{c3b906bc-d230-4026-a32e-34c00eaf4481}", + "out_index": 0 + }, + { + "in_id": "{63bb13f0-55e3-451b-860e-568b65e09b04}", + "in_index": 0, + "out_id": "{7ac65f09-7f55-4a6e-9380-1bee5213f079}", + "out_index": 0 + }, + { + "in_id": "{f8e2a7b7-6780-4014-a803-34020084ceed}", + "in_index": 0, + "out_id": "{6d6b0d04-46ea-4f5f-8e0b-0502adfdc149}", + "out_index": 0 + } + ], + "inputs": [ + { + "locationIndex": 0, + "name": "inPos", + "role": "Position", + "roleIndex": 0, + "type": "Float3" + }, + { + "locationIndex": 1, + "name": "inTexCoord", + "role": "TexCoord", + "roleIndex": 0, + "type": "Float2" + } + ], + "nodes": [ + { + "id": "{c3b906bc-d230-4026-a32e-34c00eaf4481}", + "model": { + "input": "inPos", + "name": "Input", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 216.49999999999997, + "y": 664.1666666666667 + } + }, + { + "id": "{7ac65f09-7f55-4a6e-9380-1bee5213f079}", + "model": { + "name": "cast_vec4", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "value": [ + 1, + 0, + 0, + 0 + ], + "variable_name": "" + }, + "position": { + "x": 345, + "y": 668 + } + }, + { + "id": "{63bb13f0-55e3-451b-860e-568b65e09b04}", + "model": { + "name": "PositionOutputValue", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 521.6666666666667, + "y": 668.1666666666667 + } + }, + { + "id": "{6d6b0d04-46ea-4f5f-8e0b-0502adfdc149}", + "model": { + "input": "inTexCoord", + "name": "Input", + "preview_enabled": false, + "preview_height": 64, + "preview_width": 64, + "variable_name": "" + }, + "position": { + "x": 208.33333333333334, + "y": 761.666666666667 + } + }, + { + "id": "{f8e2a7b7-6780-4014-a803-34020084ceed}", + "model": { + "name": "Output", + "output": "vertUV", + "preview_enabled": false, + "preview_height": 128, + "preview_width": 128, + "variable_name": "" + }, + "position": { + "x": 492.5, + "y": 765 + } + } + ], + "outputs": [ + { + "locationIndex": 0, + "name": "vertUV", + "type": "Float2" + } + ], + "structs": [ + ], + "textures": [ + ], + "type": "Vertex" +} diff --git a/src/Nazara/Audio/Audio.cpp b/src/Nazara/Audio/Audio.cpp index d1ea24372..0202cfa5b 100644 --- a/src/Nazara/Audio/Audio.cpp +++ b/src/Nazara/Audio/Audio.cpp @@ -7,7 +7,10 @@ #include #include #include -#include +#include +#include +#include +#include #include #include #include @@ -30,58 +33,30 @@ namespace Nz if (!OpenAL::Initialize()) throw std::runtime_error("failed to initialize OpenAL"); - if (!SoundBuffer::Initialize()) - throw std::runtime_error("failed to initialize sound buffers"); - // Definition of the orientation by default SetListenerDirection(Vector3f::Forward()); // Loaders - Loaders::Register_sndfile(); + m_soundBufferLoader.RegisterLoader(Loaders::GetSoundBufferLoader_drwav()); + m_soundStreamLoader.RegisterLoader(Loaders::GetSoundStreamLoader_drwav()); + m_soundBufferLoader.RegisterLoader(Loaders::GetSoundBufferLoader_libflac()); + m_soundStreamLoader.RegisterLoader(Loaders::GetSoundStreamLoader_libflac()); + m_soundBufferLoader.RegisterLoader(Loaders::GetSoundBufferLoader_libvorbis()); + m_soundStreamLoader.RegisterLoader(Loaders::GetSoundStreamLoader_libvorbis()); + m_soundBufferLoader.RegisterLoader(Loaders::GetSoundBufferLoader_minimp3()); + m_soundStreamLoader.RegisterLoader(Loaders::GetSoundStreamLoader_minimp3()); } Audio::~Audio() { - // Loaders - Loaders::Unregister_sndfile(); - - SoundBuffer::Uninitialize(); OpenAL::Uninitialize(); } - /*! - * \brief Gets the format of the audio - * \return AudioFormat Enumeration type for the format - * - * \param channelCount Number of channels - * - * \remark Produces a NazaraError if the number of channels is erroneous (3 or 5) and AudioFormat_Unknown is returned - */ - - AudioFormat Audio::GetAudioFormat(unsigned int channelCount) - { - switch (channelCount) - { - case 1: - case 2: - case 4: - case 6: - case 7: - case 8: - return static_cast(channelCount); - - default: - NazaraError("Invalid channel count: " + NumberToString(channelCount)); - return AudioFormat_Unknown; - } - } - /*! * \brief Gets the factor of the doppler effect * \return Global factor of the doppler effect */ - - float Audio::GetDopplerFactor() + float Audio::GetDopplerFactor() const { return alGetFloat(AL_DOPPLER_FACTOR); } @@ -90,8 +65,7 @@ namespace Nz * \brief Gets the global volume * \return Float between [0, inf) with 100.f being the default */ - - float Audio::GetGlobalVolume() + float Audio::GetGlobalVolume() const { ALfloat gain = 0.f; alGetListenerf(AL_GAIN, &gain); @@ -105,8 +79,7 @@ namespace Nz * * \see GetListenerRotation */ - - Vector3f Audio::GetListenerDirection() + Vector3f Audio::GetListenerDirection() const { ALfloat orientation[6]; alGetListenerfv(AL_ORIENTATION, orientation); @@ -120,8 +93,7 @@ namespace Nz * * \see GetListenerVelocity */ - - Vector3f Audio::GetListenerPosition() + Vector3f Audio::GetListenerPosition() const { Vector3f position; alGetListenerfv(AL_POSITION, &position.x); @@ -133,8 +105,7 @@ namespace Nz * \brief Gets the rotation of the listener * \return Rotation of the listener */ - - Quaternionf Audio::GetListenerRotation() + Quaternionf Audio::GetListenerRotation() const { ALfloat orientation[6]; alGetListenerfv(AL_ORIENTATION, orientation); @@ -150,8 +121,7 @@ namespace Nz * * \see GetListenerPosition */ - - Vector3f Audio::GetListenerVelocity() + Vector3f Audio::GetListenerVelocity() const { Vector3f velocity; alGetListenerfv(AL_VELOCITY, &velocity.x); @@ -159,12 +129,47 @@ namespace Nz return velocity; } + /*! + * \brief Gets the default SoundBuffer loader + * \return A reference to the default SoundBuffer loader + */ + SoundBufferLoader& Audio::GetSoundBufferLoader() + { + return m_soundBufferLoader; + } + + /*! + * \brief Gets the default SoundBuffer loader + * \return A constant reference to the default SoundBuffer loader + */ + const SoundBufferLoader& Audio::GetSoundBufferLoader() const + { + return m_soundBufferLoader; + } + + /*! + * \brief Gets the default SoundStream loader + * \return A reference to the default SoundStream loader + */ + SoundStreamLoader& Audio::GetSoundStreamLoader() + { + return m_soundStreamLoader; + } + + /*! + * \brief Gets the default SoundStream loader + * \return A constant reference to the default SoundStream loader + */ + const SoundStreamLoader& Audio::GetSoundStreamLoader() const + { + return m_soundStreamLoader; + } + /*! * \brief Gets the speed of sound * \return Speed of sound */ - - float Audio::GetSpeedOfSound() + float Audio::GetSpeedOfSound() const { return alGetFloat(AL_SPEED_OF_SOUND); } @@ -175,13 +180,12 @@ namespace Nz * * \param format Format to check */ - - bool Audio::IsFormatSupported(AudioFormat format) + bool Audio::IsFormatSupported(AudioFormat format) const { - if (format == AudioFormat_Unknown) + if (format == AudioFormat::Unknown) return false; - return OpenAL::AudioFormat[format] != 0; + return OpenAL::AudioFormat[UnderlyingCast(format)] != 0; } /*! diff --git a/src/Nazara/Audio/Formats/drwavLoader.cpp b/src/Nazara/Audio/Formats/drwavLoader.cpp new file mode 100644 index 000000000..31e898e6e --- /dev/null +++ b/src/Nazara/Audio/Formats/drwavLoader.cpp @@ -0,0 +1,344 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Audio module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DR_WAV_IMPLEMENTATION +#define DR_WAV_NO_STDIO +#include + +#include + +namespace Nz +{ + namespace + { + std::optional GuessFormat(UInt32 channelCount) + { + switch (channelCount) + { + case 1: + return AudioFormat::I16_Mono; + + case 2: + return AudioFormat::I16_Stereo; + + case 4: + return AudioFormat::I16_Quad; + + case 6: + return AudioFormat::I16_5_1; + + case 7: + return AudioFormat::I16_6_1; + + case 8: + return AudioFormat::I16_7_1; + + default: + return std::nullopt; + } + } + + std::size_t ReadCallback(void* pUserData, void* pBufferOut, size_t bytesToRead) + { + Stream* stream = static_cast(pUserData); + return static_cast(stream->Read(pBufferOut, bytesToRead)); + } + + drwav_bool32 SeekCallback(void* pUserData, int offset, drwav_seek_origin origin) + { + Stream* stream = static_cast(pUserData); + switch (origin) + { + case drwav_seek_origin_start: + return stream->SetCursorPos(offset); + + case drwav_seek_origin_current: + return (stream->Read(nullptr, static_cast(offset)) != 0); + + default: + NazaraInternalError("Seek mode not handled"); + return false; + } + } + + bool IsSupported(const std::string_view& extension) + { + return extension == "riff" || extension == "rf64" || extension == "wav" || extension == "w64"; + } + + Ternary CheckWav(Stream& stream) + { + drwav wav; + if (!drwav_init(&wav, &ReadCallback, &SeekCallback, &stream, nullptr)) + return Ternary::False; + + drwav_uninit(&wav); + return Ternary::True; + } + + std::shared_ptr LoadSoundBuffer(Stream& stream, const SoundBufferParams& parameters) + { + drwav wav; + if (!drwav_init(&wav, &ReadCallback, &SeekCallback, &stream, nullptr)) + { + NazaraError("failed to decode wav stream"); + return {}; + } + + CallOnExit uninitOnExit([&] { drwav_uninit(&wav); }); + + std::optional formatOpt = GuessFormat(wav.channels); + if (!formatOpt) + { + NazaraError("unexpected channel count: " + std::to_string(wav.channels)); + return {}; + } + + AudioFormat format = *formatOpt; + + UInt64 sampleCount = wav.totalPCMFrameCount * wav.channels; + std::unique_ptr samples = std::make_unique(sampleCount); //< std::vector would default-init to zero + + if (drwav_read_pcm_frames_s16(&wav, wav.totalPCMFrameCount, samples.get()) != wav.totalPCMFrameCount) + { + NazaraError("failed to read stream content"); + return {}; + } + + if (parameters.forceMono && format != AudioFormat::I16_Mono) + { + MixToMono(samples.get(), samples.get(), static_cast(wav.channels), wav.totalPCMFrameCount); + + format = AudioFormat::I16_Mono; + sampleCount = wav.totalPCMFrameCount; + } + + return std::make_shared(format, sampleCount, wav.sampleRate, samples.get()); + } + + class drwavStream : public SoundStream + { + public: + drwavStream() : + m_readSampleCount(0) + { + std::memset(&m_decoder, 0, sizeof(m_decoder)); + } + + ~drwavStream() + { + drwav_uninit(&m_decoder); + } + + UInt32 GetDuration() const override + { + return m_duration; + } + + AudioFormat GetFormat() const override + { + if (m_mixToMono) + return AudioFormat::I16_Mono; + else + return m_format; + } + + std::mutex& GetMutex() override + { + return m_mutex; + } + + UInt64 GetSampleCount() const override + { + return m_sampleCount; + } + + UInt32 GetSampleRate() const override + { + return m_sampleRate; + } + + bool Open(const std::filesystem::path& filePath, bool forceMono) + { + std::unique_ptr file = std::make_unique(); + if (!file->Open(filePath, OpenMode::ReadOnly)) + { + NazaraError("failed to open stream from file: " + Error::GetLastError()); + return false; + } + + m_ownedStream = std::move(file); + return Open(*m_ownedStream, forceMono); + } + + bool Open(const void* data, std::size_t size, bool forceMono) + { + m_ownedStream = std::make_unique(data, size); + return Open(*m_ownedStream, forceMono); + } + + bool Open(Stream& stream, bool forceMono) + { + if (!drwav_init(&m_decoder, &ReadCallback, &SeekCallback, &stream, nullptr)) + { + NazaraError("failed to decode wav stream"); + return {}; + } + + CallOnExit resetOnError([this] + { + drwav_uninit(&m_decoder); + std::memset(&m_decoder, 0, sizeof(m_decoder)); + }); + + std::optional formatOpt = GuessFormat(m_decoder.channels); + if (!formatOpt) + { + NazaraError("unexpected channel count: " + std::to_string(m_decoder.channels)); + return false; + } + + m_format = *formatOpt; + + m_duration = static_cast(1000ULL * m_decoder.totalPCMFrameCount / (m_decoder.sampleRate * m_decoder.channels)); + m_sampleCount = m_decoder.totalPCMFrameCount * m_decoder.channels; + m_sampleRate = m_decoder.sampleRate; + + // Mixing to mono will be done on the fly + if (forceMono && m_format != AudioFormat::I16_Mono) + { + m_mixToMono = true; + m_sampleCount = m_decoder.totalPCMFrameCount; + } + else + m_mixToMono = false; + + resetOnError.Reset(); + + return true; + } + + UInt64 Read(void* buffer, UInt64 sampleCount) override + { + // Convert to mono in the fly if necessary + if (m_mixToMono) + { + // Keep a buffer to the side to prevent allocation + m_mixBuffer.resize(sampleCount * m_decoder.channels); + std::size_t readSample = drwav_read_pcm_frames_s16(&m_decoder, sampleCount, static_cast(m_mixBuffer.data())); + m_readSampleCount += readSample; + + MixToMono(m_mixBuffer.data(), static_cast(buffer), m_decoder.channels, sampleCount); + + return readSample; + } + else + { + UInt64 readSample = drwav_read_pcm_frames_s16(&m_decoder, sampleCount / m_decoder.channels, static_cast(buffer)); + m_readSampleCount += readSample * m_decoder.channels; + + return readSample * m_decoder.channels; + } + } + + void Seek(UInt64 offset) override + { + drwav_seek_to_pcm_frame(&m_decoder, (m_mixToMono) ? offset : offset / m_decoder.channels); + m_readSampleCount = offset; + } + + UInt64 Tell() override + { + return m_readSampleCount; + } + + private: + std::mutex m_mutex; + std::unique_ptr m_ownedStream; + std::vector m_mixBuffer; + AudioFormat m_format; + drwav m_decoder; + UInt32 m_duration; + UInt32 m_sampleRate; + UInt64 m_readSampleCount; + UInt64 m_sampleCount; + bool m_mixToMono; + }; + + std::shared_ptr LoadSoundStreamFile(const std::filesystem::path& filePath, const SoundStreamParams& parameters) + { + std::shared_ptr soundStream = std::make_shared(); + if (!soundStream->Open(filePath, parameters.forceMono)) + { + NazaraError("failed to open sound stream"); + return {}; + } + + return soundStream; + } + + std::shared_ptr LoadSoundStreamMemory(const void* data, std::size_t size, const SoundStreamParams& parameters) + { + std::shared_ptr soundStream = std::make_shared(); + if (!soundStream->Open(data, size, parameters.forceMono)) + { + NazaraError("failed to open music stream"); + return {}; + } + + return soundStream; + } + + std::shared_ptr LoadSoundStreamStream(Stream& stream, const SoundStreamParams& parameters) + { + std::shared_ptr soundStream = std::make_shared(); + if (!soundStream->Open(stream, parameters.forceMono)) + { + NazaraError("failed to open music stream"); + return {}; + } + + return soundStream; + } + } + + namespace Loaders + { + SoundBufferLoader::Entry GetSoundBufferLoader_drwav() + { + SoundBufferLoader::Entry loaderEntry; + loaderEntry.extensionSupport = IsSupported; + loaderEntry.streamChecker = [](Stream& stream, const SoundBufferParams&) { return CheckWav(stream); }; + loaderEntry.streamLoader = LoadSoundBuffer; + + return loaderEntry; + } + + SoundStreamLoader::Entry GetSoundStreamLoader_drwav() + { + SoundStreamLoader::Entry loaderEntry; + loaderEntry.extensionSupport = IsSupported; + loaderEntry.streamChecker = [](Stream& stream, const SoundStreamParams&) { return CheckWav(stream); }; + loaderEntry.fileLoader = LoadSoundStreamFile; + loaderEntry.memoryLoader = LoadSoundStreamMemory; + loaderEntry.streamLoader = LoadSoundStreamStream; + + return loaderEntry; + } + } +} diff --git a/src/Nazara/Audio/Formats/drwavLoader.hpp b/src/Nazara/Audio/Formats/drwavLoader.hpp new file mode 100644 index 000000000..49d4adb17 --- /dev/null +++ b/src/Nazara/Audio/Formats/drwavLoader.hpp @@ -0,0 +1,20 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_LOADERS_DRWAV_HPP +#define NAZARA_LOADERS_DRWAV_HPP + +#include +#include +#include + +namespace Nz::Loaders +{ + SoundBufferLoader::Entry GetSoundBufferLoader_drwav(); + SoundStreamLoader::Entry GetSoundStreamLoader_drwav(); +} + +#endif diff --git a/src/Nazara/Audio/Formats/libflacLoader.cpp b/src/Nazara/Audio/Formats/libflacLoader.cpp new file mode 100644 index 000000000..b46017d88 --- /dev/null +++ b/src/Nazara/Audio/Formats/libflacLoader.cpp @@ -0,0 +1,611 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Audio module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + namespace + { + std::optional GuessFormat(UInt32 channelCount) + { + switch (channelCount) + { + case 1: + return AudioFormat::I16_Mono; + + case 2: + return AudioFormat::I16_Stereo; + + case 4: + return AudioFormat::I16_Quad; + + case 6: + return AudioFormat::I16_5_1; + + case 7: + return AudioFormat::I16_6_1; + + case 8: + return AudioFormat::I16_7_1; + + default: + return std::nullopt; + } + } + + + struct Userdata + { + std::function errorCallback; + std::function metadataCallback; + std::function writeCallback; + Stream* stream; + }; + + FLAC__bool EofCallback(const FLAC__StreamDecoder* /*decoder*/, void* client_data) + { + Userdata* ud = static_cast(client_data); + return ud->stream->EndOfStream(); + } + + void ErrorCallback(const FLAC__StreamDecoder* decoder, FLAC__StreamDecoderErrorStatus status, void* client_data) + { + Userdata* ud = static_cast(client_data); + assert(ud->errorCallback); + return ud->errorCallback(decoder, status); + } + + FLAC__StreamDecoderLengthStatus LengthCallback(const FLAC__StreamDecoder* /*decoder*/, FLAC__uint64* stream_length, void* client_data) + { + Userdata* ud = static_cast(client_data); + *stream_length = ud->stream->GetSize(); + + return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; + } + + void MetadataCallback(const FLAC__StreamDecoder* decoder, const FLAC__StreamMetadata* metadata, void* client_data) + { + Userdata* ud = static_cast(client_data); + if (ud->metadataCallback) + ud->metadataCallback(decoder, metadata); + } + + FLAC__StreamDecoderReadStatus ReadCallback(const FLAC__StreamDecoder* /*decoder*/, FLAC__byte buffer[], size_t* bytes, void* client_data) + { + Userdata* ud = static_cast(client_data); + std::size_t readBytes = ud->stream->Read(buffer, *bytes); + + *bytes = readBytes; + if (readBytes == 0 && ud->stream->EndOfStream()) + return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + else + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + } + + FLAC__StreamDecoderSeekStatus SeekCallback(const FLAC__StreamDecoder* /*decoder*/, FLAC__uint64 absolute_byte_offset, void* client_data) + { + Userdata* ud = static_cast(client_data); + if (ud->stream->SetCursorPos(absolute_byte_offset)) + return FLAC__STREAM_DECODER_SEEK_STATUS_OK; + else + return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; + } + + FLAC__StreamDecoderTellStatus TellCallback(const FLAC__StreamDecoder* /*decoder*/, FLAC__uint64* absolute_byte_offset, void* client_data) + { + Userdata* ud = static_cast(client_data); + *absolute_byte_offset = ud->stream->GetCursorPos(); + return FLAC__STREAM_DECODER_TELL_STATUS_OK; + } + + FLAC__StreamDecoderWriteStatus WriteCallback(const FLAC__StreamDecoder* decoder, const FLAC__Frame* frame, const FLAC__int32* const buffer[], void* client_data) + { + Userdata* ud = static_cast(client_data); + if (ud->writeCallback) + return ud->writeCallback(decoder, frame, buffer); + else + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; + } + + template + bool DecodeFrameSamplesImpl(const FLAC__Frame* frame, const FLAC__int32* const buffer[], TargetType* samples, UInt32 frameIndex, UInt32 frameCount) + { + constexpr UInt32 TargetBits = sizeof(TargetType) * CHAR_BIT; + for (; frameIndex < frameCount; ++frameIndex) + { + for (UInt32 channelIndex = 0; channelIndex < frame->header.channels; ++channelIndex) + { + Int32 sample = buffer[channelIndex][frameIndex]; + if constexpr (Bits > TargetBits) + sample >>= (Bits - TargetBits); + else + sample <<= (TargetBits - Bits); + + *samples++ = static_cast(sample); + } + } + + return true; + } + + bool DecodeFrameSamples(const FLAC__Frame* frame, const FLAC__int32* const buffer[], Int16* samples, UInt32 frameIndex, UInt32 frameCount) + { + switch (frame->header.bits_per_sample) + { + case 8: return DecodeFrameSamplesImpl<8>(frame, buffer, samples, frameIndex, frameCount); + case 12: return DecodeFrameSamplesImpl<12>(frame, buffer, samples, frameIndex, frameCount); + case 16: return DecodeFrameSamplesImpl<16>(frame, buffer, samples, frameIndex, frameCount); + case 20: return DecodeFrameSamplesImpl<20>(frame, buffer, samples, frameIndex, frameCount); + case 24: return DecodeFrameSamplesImpl<24>(frame, buffer, samples, frameIndex, frameCount); + case 32: return DecodeFrameSamplesImpl<32>(frame, buffer, samples, frameIndex, frameCount); + default: return false; + } + } + + bool DecodeFrameSamples(const FLAC__Frame* frame, const FLAC__int32* const buffer[], Int16* samples) + { + return DecodeFrameSamples(frame, buffer, samples, 0, frame->header.blocksize); + } + + bool IsSupported(const std::string_view& extension) + { + return extension == "flac"; + } + + Ternary CheckFlac(Stream& stream) + { + FLAC__StreamDecoder* decoder = FLAC__stream_decoder_new(); + CallOnExit freeDecoder([&] { FLAC__stream_decoder_delete(decoder); }); + + bool hasError = false; + + Userdata ud; + ud.stream = &stream; + ud.errorCallback = [&](const FLAC__StreamDecoder* /*decoder*/, FLAC__StreamDecoderErrorStatus /*status*/) + { + hasError = true; + }; + + FLAC__StreamDecoderInitStatus status = FLAC__stream_decoder_init_stream(decoder, &ReadCallback, &SeekCallback, &TellCallback, &LengthCallback, &EofCallback, &WriteCallback, &MetadataCallback, &ErrorCallback, &ud); + if (status != FLAC__STREAM_DECODER_INIT_STATUS_OK) + { + NazaraWarning(FLAC__StreamDecoderInitStatusString[status]); //< an error shouldn't happen at this state + return Ternary::False; + } + + CallOnExit finishDecoder([&] { FLAC__stream_decoder_finish(decoder); }); + + if (!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) + return Ternary::False; + + if (hasError) + return Ternary::False; + + return Ternary::True; + } + + std::shared_ptr LoadSoundBuffer(Stream& stream, const SoundBufferParams& parameters) + { + FLAC__StreamDecoder* decoder = FLAC__stream_decoder_new(); + CallOnExit freeDecoder([&] { FLAC__stream_decoder_delete(decoder); }); + + bool hasError = false; + + Userdata ud; + ud.stream = &stream; + ud.errorCallback = [&](const FLAC__StreamDecoder* /*decoder*/, FLAC__StreamDecoderErrorStatus status) + { + hasError = true; + NazaraError(FLAC__StreamDecoderErrorStatusString[status]); + }; + + std::unique_ptr samples; + UInt32 channelCount = 0; + UInt64 frameCount = 0; + UInt64 sampleCount = 0; + UInt64 sampleRate = 0; + + ud.metadataCallback = [&](const FLAC__StreamDecoder* /*decoder*/, const FLAC__StreamMetadata* meta) + { + if (meta->type == FLAC__METADATA_TYPE_STREAMINFO) + { + channelCount = meta->data.stream_info.channels; + frameCount = meta->data.stream_info.total_samples; + sampleCount = frameCount * channelCount; + sampleRate = meta->data.stream_info.sample_rate; + + samples = std::make_unique(channelCount * frameCount); + } + }; + + UInt64 sampleIndex = 0; + ud.writeCallback = [&](const FLAC__StreamDecoder* /*decoder*/, const FLAC__Frame* frame, const FLAC__int32* const buffer[]) + { + std::size_t frameSampleCount = frame->header.blocksize * frame->header.channels; + if (sampleIndex + frameSampleCount > sampleCount) + { + NazaraError("too many sample encountered"); + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + + if (!DecodeFrameSamples(frame, buffer, samples.get() + sampleIndex)) + { + NazaraError("failed to decode samples"); + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + + sampleIndex += frameSampleCount; + + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; + }; + + FLAC__StreamDecoderInitStatus status = FLAC__stream_decoder_init_stream(decoder, &ReadCallback, &SeekCallback, &TellCallback, &LengthCallback, &EofCallback, &WriteCallback, &MetadataCallback, &ErrorCallback, &ud); + if (status != FLAC__STREAM_DECODER_INIT_STATUS_OK) + { + NazaraWarning(FLAC__StreamDecoderInitStatusString[status]); //< an error shouldn't happen at this state + return {}; + } + + CallOnExit finishDecoder([&] { FLAC__stream_decoder_finish(decoder); }); + + if (!FLAC__stream_decoder_process_until_end_of_stream(decoder)) + { + NazaraError("flac decoding failed"); + return {}; + } + + if (hasError) + { + NazaraError("an error occurred during decoding"); + return {}; + } + + if (channelCount == 0 || frameCount == 0 || sampleCount == 0 || sampleRate == 0) + { + NazaraError("invalid metadata"); + return {}; + } + + std::optional formatOpt = GuessFormat(channelCount); + if (!formatOpt) + { + NazaraError("unexpected channel count: " + std::to_string(channelCount)); + return {}; + } + + AudioFormat format = *formatOpt; + + if (parameters.forceMono && format != AudioFormat::I16_Mono) + { + MixToMono(samples.get(), samples.get(), channelCount, frameCount); + + format = AudioFormat::I16_Mono; + sampleCount = frameCount; + } + + return std::make_shared(format, sampleCount, sampleRate, samples.get()); + } + + class libflacStream : public SoundStream + { + public: + libflacStream() : + m_decoder(nullptr), + m_readSampleCount(0), + m_errored(false) + { + } + + ~libflacStream() + { + if (m_decoder) + { + FLAC__stream_decoder_finish(m_decoder); + FLAC__stream_decoder_delete(m_decoder); + } + } + + UInt32 GetDuration() const override + { + return m_duration; + } + + AudioFormat GetFormat() const override + { + if (m_mixToMono) + return AudioFormat::I16_Mono; + else + return m_format; + } + + std::mutex& GetMutex() override + { + return m_mutex; + } + + UInt64 GetSampleCount() const override + { + return m_sampleCount; + } + + UInt32 GetSampleRate() const override + { + return m_sampleRate; + } + + bool Open(const std::filesystem::path& filePath, bool forceMono) + { + std::unique_ptr file = std::make_unique(); + if (!file->Open(filePath, OpenMode::ReadOnly)) + { + NazaraError("failed to open stream from file: " + Error::GetLastError()); + return false; + } + + m_ownedStream = std::move(file); + return Open(*m_ownedStream, forceMono); + } + + bool Open(const void* data, std::size_t size, bool forceMono) + { + m_ownedStream = std::make_unique(data, size); + return Open(*m_ownedStream, forceMono); + } + + bool Open(Stream& stream, bool forceMono) + { + m_userData.stream = &stream; + m_userData.errorCallback = [this](const FLAC__StreamDecoder* /*decoder*/, FLAC__StreamDecoderErrorStatus status) + { + m_errored = true; + NazaraError(FLAC__StreamDecoderErrorStatusString[status]); + }; + + FLAC__StreamDecoder* decoder = FLAC__stream_decoder_new(); + CallOnExit freeDecoder([&] { FLAC__stream_decoder_delete(decoder); }); + + UInt64 frameCount; + + m_userData.metadataCallback = [&](const FLAC__StreamDecoder* /*decoder*/, const FLAC__StreamMetadata* meta) + { + m_channelCount = meta->data.stream_info.channels; + frameCount = meta->data.stream_info.total_samples; + m_sampleCount = frameCount * m_channelCount; + m_sampleRate = meta->data.stream_info.sample_rate; + + m_duration = UInt32(1000ULL * frameCount / m_sampleRate); + }; + + FLAC__StreamDecoderInitStatus status = FLAC__stream_decoder_init_stream(decoder, &ReadCallback, &SeekCallback, &TellCallback, &LengthCallback, &EofCallback, &WriteCallback, &MetadataCallback, &ErrorCallback, &m_userData); + if (status != FLAC__STREAM_DECODER_INIT_STATUS_OK) + { + NazaraWarning(FLAC__StreamDecoderInitStatusString[status]); //< an error shouldn't happen at this state + return {}; + } + + CallOnExit finishDecoder([&] { FLAC__stream_decoder_finish(decoder); }); + + if (!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) + { + NazaraError("failed to decode metadata"); + return false; + } + + std::optional formatOpt = GuessFormat(m_channelCount); + if (!formatOpt) + { + NazaraError("unexpected channel count: " + std::to_string(m_channelCount)); + return false; + } + + m_format = *formatOpt; + + // Mixing to mono will be done on the fly + if (forceMono && m_format != AudioFormat::I16_Mono) + { + m_mixToMono = true; + m_sampleCount = frameCount; + } + else + m_mixToMono = false; + + finishDecoder.Reset(); + freeDecoder.Reset(); + m_decoder = decoder; + + return true; + } + + UInt64 Read(void* buffer, UInt64 sampleCount) override + { + // Convert to mono in the fly if necessary + if (m_mixToMono) + { + // Keep a buffer to the side to prevent allocation + m_mixBuffer.resize(sampleCount * m_channelCount); + + std::size_t readSample = ReadFlac(m_mixBuffer.data(), sampleCount * m_channelCount); + MixToMono(m_mixBuffer.data(), static_cast(buffer), m_channelCount, sampleCount); + + return readSample / m_channelCount; + } + else + return ReadFlac(static_cast(buffer), sampleCount); + } + + UInt64 ReadFlac(Int16* buffer, UInt64 sampleCount) + { + // Read overflown buffer first + UInt64 readSample = std::min(m_overflowBuffer.size(), sampleCount); + if (readSample > 0) + { + std::memcpy(buffer, m_overflowBuffer.data(), readSample * sizeof(Int16)); + m_overflowBuffer.erase(m_overflowBuffer.begin(), m_overflowBuffer.begin() + readSample); + sampleCount -= readSample; + } + + if (sampleCount == 0) + return readSample; + + m_userData.writeCallback = [&](const FLAC__StreamDecoder* /*decoder*/, const FLAC__Frame* frame, const FLAC__int32* const framebuffer[]) + { + UInt32 frameCount = frame->header.blocksize; + UInt32 blockSampleCount = frameCount * frame->header.channels; + if (blockSampleCount > sampleCount) + { + std::size_t overflownOffset = m_overflowBuffer.size(); + m_overflowBuffer.resize(overflownOffset + blockSampleCount - sampleCount); + + if (sampleCount > 0) + { + assert(sampleCount % frame->header.channels == 0); + if (!DecodeFrameSamples(frame, framebuffer, buffer + readSample, 0, static_cast(sampleCount / frame->header.channels))) + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + + readSample += sampleCount; + } + + if (!DecodeFrameSamples(frame, framebuffer, &m_overflowBuffer[overflownOffset], static_cast(sampleCount / frame->header.channels), frameCount)) + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + + sampleCount = 0; + } + else + { + if (!DecodeFrameSamples(frame, framebuffer, buffer + readSample)) + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + + readSample += blockSampleCount; + sampleCount -= blockSampleCount; + } + + if (m_mixToMono) + m_readSampleCount += frameCount; + else + m_readSampleCount += blockSampleCount; + + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; + }; + + CallOnExit resetWriteCallback([&] { m_userData.writeCallback = nullptr; }); + + while (sampleCount > 0) + { + if (!FLAC__stream_decoder_process_single(m_decoder)) + break; //< an error occurred + + if (FLAC__stream_decoder_get_state(m_decoder) == FLAC__STREAM_DECODER_END_OF_STREAM) + break; //< we hit the end of the stream + } + + return readSample; + } + + void Seek(UInt64 offset) override + { + FLAC__stream_decoder_seek_absolute(m_decoder, (m_mixToMono) ? offset : offset / m_channelCount); + m_readSampleCount = offset; + } + + UInt64 Tell() override + { + return m_readSampleCount; + } + + private: + std::mutex m_mutex; + std::unique_ptr m_ownedStream; + std::vector m_mixBuffer; + std::vector m_overflowBuffer; + FLAC__StreamDecoder* m_decoder; + AudioFormat m_format; + Userdata m_userData; + UInt32 m_channelCount; + UInt32 m_duration; + UInt32 m_sampleRate; + UInt64 m_readSampleCount; + UInt64 m_sampleCount; + bool m_errored; + bool m_mixToMono; + }; + + std::shared_ptr LoadSoundStreamFile(const std::filesystem::path& filePath, const SoundStreamParams& parameters) + { + std::shared_ptr soundStream = std::make_shared(); + if (!soundStream->Open(filePath, parameters.forceMono)) + { + NazaraError("failed to open sound stream"); + return {}; + } + + return soundStream; + } + + std::shared_ptr LoadSoundStreamMemory(const void* data, std::size_t size, const SoundStreamParams& parameters) + { + std::shared_ptr soundStream = std::make_shared(); + if (!soundStream->Open(data, size, parameters.forceMono)) + { + NazaraError("failed to open music stream"); + return {}; + } + + return soundStream; + } + + std::shared_ptr LoadSoundStreamStream(Stream& stream, const SoundStreamParams& parameters) + { + std::shared_ptr soundStream = std::make_shared(); + if (!soundStream->Open(stream, parameters.forceMono)) + { + NazaraError("failed to open music stream"); + return {}; + } + + return soundStream; + } + } + + namespace Loaders + { + SoundBufferLoader::Entry GetSoundBufferLoader_libflac() + { + SoundBufferLoader::Entry loaderEntry; + loaderEntry.extensionSupport = IsSupported; + loaderEntry.streamChecker = [](Stream& stream, const SoundBufferParams&) { return CheckFlac(stream); }; + loaderEntry.streamLoader = LoadSoundBuffer; + + return loaderEntry; + } + + SoundStreamLoader::Entry GetSoundStreamLoader_libflac() + { + SoundStreamLoader::Entry loaderEntry; + loaderEntry.extensionSupport = IsSupported; + loaderEntry.streamChecker = [](Stream& stream, const SoundStreamParams&) { return CheckFlac(stream); }; + loaderEntry.fileLoader = LoadSoundStreamFile; + loaderEntry.memoryLoader = LoadSoundStreamMemory; + loaderEntry.streamLoader = LoadSoundStreamStream; + + return loaderEntry; + } + } +} + diff --git a/src/Nazara/Audio/Formats/libflacLoader.hpp b/src/Nazara/Audio/Formats/libflacLoader.hpp new file mode 100644 index 000000000..3640f2d6f --- /dev/null +++ b/src/Nazara/Audio/Formats/libflacLoader.hpp @@ -0,0 +1,20 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_LOADERS_LIBFLAC_HPP +#define NAZARA_LOADERS_LIBFLAC_HPP + +#include +#include +#include + +namespace Nz::Loaders +{ + SoundBufferLoader::Entry GetSoundBufferLoader_libflac(); + SoundStreamLoader::Entry GetSoundStreamLoader_libflac(); +} + +#endif diff --git a/src/Nazara/Audio/Formats/libvorbisLoader.cpp b/src/Nazara/Audio/Formats/libvorbisLoader.cpp new file mode 100644 index 000000000..bc540e587 --- /dev/null +++ b/src/Nazara/Audio/Formats/libvorbisLoader.cpp @@ -0,0 +1,435 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Audio module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OV_EXCLUDE_STATIC_CALLBACKS +#include + +#include + +namespace Nz +{ + namespace + { + std::optional GuessFormat(UInt32 channelCount) + { + switch (channelCount) + { + case 1: + return AudioFormat::I16_Mono; + + case 2: + return AudioFormat::I16_Stereo; + + case 4: + return AudioFormat::I16_Quad; + + case 6: + return AudioFormat::I16_5_1; + + case 7: + return AudioFormat::I16_6_1; + + case 8: + return AudioFormat::I16_7_1; + + default: + return std::nullopt; + } + } + + std::size_t ReadCallback(void* ptr, size_t size, size_t nmemb, void* datasource) + { + Stream* stream = static_cast(datasource); + return static_cast(stream->Read(ptr, size * nmemb)); + } + + int SeekCallback(void* datasource, ogg_int64_t offset, int whence) + { + Stream* stream = static_cast(datasource); + switch (whence) + { + case SEEK_CUR: + stream->Read(nullptr, static_cast(offset)); + break; + + case SEEK_END: + stream->SetCursorPos(stream->GetSize() + offset); // offset is negative here + break; + + case SEEK_SET: + stream->SetCursorPos(offset); + break; + + default: + NazaraInternalError("Seek mode not handled"); + return false; + } + + return 0; + } + + long TellCallback(void* datasource) + { + Stream* stream = static_cast(datasource); + return static_cast(stream->GetCursorPos()); + } + + static ov_callbacks s_callbacks = { + &ReadCallback, + &SeekCallback, + nullptr, + &TellCallback + }; + + + std::string ErrToString(int errCode) + { + switch (errCode) + { + case 0: return "no error"; + case OV_EBADHEADER: return "invalid Vorbis bitstream header"; + case OV_EBADLINK: return "an invalid stream section was supplied to libvorbisfile, or the requested link is corrupt"; + case OV_EFAULT: return "internal logic fault"; + case OV_EINVAL: return "an invalid stream section was supplied to libvorbisfile, or the requested link is corrupt"; + case OV_ENOTVORBIS: return "bitstream does not contain any Vorbis data"; + case OV_EREAD: return "a read from media returned an error"; + case OV_EVERSION: return "Vorbis version mismatch"; + case OV_HOLE: return "there was an interruption in the data"; + default: return "unknown error"; + } + } + + UInt64 ReadOgg(OggVorbis_File* file, void* buffer, UInt64 sampleCount) + { + constexpr int bigendian = (GetPlatformEndianness() == Endianness::LittleEndian) ? 0 : 1; + + char* ptr = reinterpret_cast(buffer); + UInt64 remainingBytes = sampleCount * sizeof(Int16); + do + { + long readBytes = ov_read(file, ptr, int(remainingBytes), bigendian, 2, 1, nullptr); + if (readBytes == 0) + break; //< End of file + + if (readBytes < 0) + { + NazaraError("an error occurred while reading file: " + ErrToString(readBytes)); + return 0; + } + + assert(readBytes > 0 && readBytes <= remainingBytes); + + ptr += readBytes; + remainingBytes -= readBytes; + } + while (remainingBytes > 0); + + return sampleCount - remainingBytes / sizeof(Int16); + } + + bool IsSupported(const std::string_view& extension) + { + static std::set supportedExtensions = { + "oga", "ogg", "ogm", "ogv", "ogx", "opus", "spx" + }; + + return supportedExtensions.find(extension) != supportedExtensions.end(); + } + + Ternary CheckOgg(Stream& stream) + { + OggVorbis_File file; + if (ov_test_callbacks(&stream, &file, nullptr, 0, s_callbacks) != 0) + return Ternary::False; + + ov_clear(&file); + return Ternary::True; + } + + std::shared_ptr LoadSoundBuffer(Stream& stream, const SoundBufferParams& parameters) + { + OggVorbis_File file; + int err = ov_open_callbacks(&stream, &file, nullptr, 0, s_callbacks); + if (err != 0) + { + NazaraError(ErrToString(err)); + return {}; + } + + CallOnExit clearOnExit([&] { ov_clear(&file); }); + + vorbis_info* info = ov_info(&file, -1); + assert(info); + + std::optional formatOpt = GuessFormat(info->channels); + if (!formatOpt) + { + NazaraError("unexpected channel count: " + std::to_string(info->channels)); + return {}; + } + + AudioFormat format = *formatOpt; + + UInt64 frameCount = UInt64(ov_pcm_total(&file, -1)); + UInt64 sampleCount = UInt64(frameCount * info->channels); + std::unique_ptr samples = std::make_unique(sampleCount); //< std::vector would default-init to zero + + UInt64 readSample = ReadOgg(&file, samples.get(), sampleCount); + if (readSample == 0) + return {}; + + if (readSample != sampleCount) + { + NazaraError("failed to read the whole file"); + return {}; + } + + if (parameters.forceMono && format != AudioFormat::I16_Mono) + { + MixToMono(samples.get(), samples.get(), static_cast(info->channels), frameCount); + + format = AudioFormat::I16_Mono; + sampleCount = frameCount; + } + + return std::make_shared(format, sampleCount, info->rate, samples.get()); + } + + class libvorbisStream : public SoundStream + { + public: + libvorbisStream() + { + m_decoder.datasource = nullptr; + } + + ~libvorbisStream() + { + if (m_decoder.datasource) + ov_clear(&m_decoder); + } + + UInt32 GetDuration() const override + { + return m_duration; + } + + AudioFormat GetFormat() const override + { + if (m_mixToMono) + return AudioFormat::I16_Mono; + else + return m_format; + } + + std::mutex& GetMutex() override + { + return m_mutex; + } + + UInt64 GetSampleCount() const override + { + return m_sampleCount; + } + + UInt32 GetSampleRate() const override + { + return m_sampleRate; + } + + bool Open(const std::filesystem::path& filePath, bool forceMono) + { + std::unique_ptr file = std::make_unique(); + if (!file->Open(filePath, OpenMode::ReadOnly)) + { + NazaraError("failed to open stream from file: " + Error::GetLastError()); + return false; + } + + m_ownedStream = std::move(file); + return Open(*m_ownedStream, forceMono); + } + + bool Open(const void* data, std::size_t size, bool forceMono) + { + m_ownedStream = std::make_unique(data, size); + return Open(*m_ownedStream, forceMono); + } + + bool Open(Stream& stream, bool forceMono) + { + int err = ov_open_callbacks(&stream, &m_decoder, nullptr, 0, s_callbacks); + if (err != 0) + { + NazaraError(ErrToString(err)); + return {}; + } + + CallOnExit clearOnError([&] + { + ov_clear(&m_decoder); + m_decoder.datasource = nullptr; + }); + + vorbis_info* info = ov_info(&m_decoder, -1); + assert(info); + + std::optional formatOpt = GuessFormat(info->channels); + if (!formatOpt) + { + NazaraError("unexpected channel count: " + std::to_string(info->channels)); + return {}; + } + + m_format = *formatOpt; + + UInt64 frameCount = UInt64(ov_pcm_total(&m_decoder, -1)); + + m_channelCount = info->channels; + m_duration = UInt32(1000ULL * frameCount / info->rate); + m_sampleCount = UInt64(frameCount * info->channels); + m_sampleRate = info->rate; + + // Mixing to mono will be done on the fly + if (forceMono && m_format != AudioFormat::I16_Mono) + { + m_mixToMono = true; + m_sampleCount = frameCount; + } + else + m_mixToMono = false; + + clearOnError.Reset(); + + return true; + } + + UInt64 Read(void* buffer, UInt64 sampleCount) override + { + // Convert to mono in the fly if necessary + if (m_mixToMono) + { + // Keep a buffer to the side to prevent allocation + m_mixBuffer.resize(sampleCount * m_channelCount); + + std::size_t readSample = ReadOgg(&m_decoder, m_mixBuffer.data(), sampleCount * m_channelCount); + MixToMono(m_mixBuffer.data(), static_cast(buffer), m_channelCount, sampleCount); + + return readSample / m_channelCount; + } + else + { + UInt64 readSample = ReadOgg(&m_decoder, buffer, sampleCount); + return readSample; + } + } + + void Seek(UInt64 offset) override + { + if (!m_mixToMono) + offset /= m_channelCount; + + ov_pcm_seek(&m_decoder, Int64(offset)); + } + + UInt64 Tell() override + { + UInt64 offset = UInt64(ov_pcm_tell(&m_decoder)); + if (!m_mixToMono) + offset *= m_channelCount; + + return offset; + } + + private: + std::mutex m_mutex; + std::unique_ptr m_ownedStream; + std::vector m_mixBuffer; + AudioFormat m_format; + OggVorbis_File m_decoder; + UInt32 m_channelCount; + UInt32 m_duration; + UInt32 m_sampleRate; + UInt64 m_sampleCount; + bool m_mixToMono; + }; + + std::shared_ptr LoadSoundStreamFile(const std::filesystem::path& filePath, const SoundStreamParams& parameters) + { + std::shared_ptr soundStream = std::make_shared(); + if (!soundStream->Open(filePath, parameters.forceMono)) + { + NazaraError("failed to open sound stream"); + return {}; + } + + return soundStream; + } + + std::shared_ptr LoadSoundStreamMemory(const void* data, std::size_t size, const SoundStreamParams& parameters) + { + std::shared_ptr soundStream = std::make_shared(); + if (!soundStream->Open(data, size, parameters.forceMono)) + { + NazaraError("failed to open music stream"); + return {}; + } + + return soundStream; + } + + std::shared_ptr LoadSoundStreamStream(Stream& stream, const SoundStreamParams& parameters) + { + std::shared_ptr soundStream = std::make_shared(); + if (!soundStream->Open(stream, parameters.forceMono)) + { + NazaraError("failed to open music stream"); + return {}; + } + + return soundStream; + } + } + + namespace Loaders + { + SoundBufferLoader::Entry GetSoundBufferLoader_libvorbis() + { + SoundBufferLoader::Entry loaderEntry; + loaderEntry.extensionSupport = IsSupported; + loaderEntry.streamChecker = [](Stream& stream, const SoundBufferParams&) { return CheckOgg(stream); }; + loaderEntry.streamLoader = LoadSoundBuffer; + + return loaderEntry; + } + + SoundStreamLoader::Entry GetSoundStreamLoader_libvorbis() + { + SoundStreamLoader::Entry loaderEntry; + loaderEntry.extensionSupport = IsSupported; + loaderEntry.streamChecker = [](Stream& stream, const SoundStreamParams&) { return CheckOgg(stream); }; + loaderEntry.fileLoader = LoadSoundStreamFile; + loaderEntry.memoryLoader = LoadSoundStreamMemory; + loaderEntry.streamLoader = LoadSoundStreamStream; + + return loaderEntry; + } + } +} + diff --git a/src/Nazara/Audio/Formats/libvorbisLoader.hpp b/src/Nazara/Audio/Formats/libvorbisLoader.hpp new file mode 100644 index 000000000..b82d53bad --- /dev/null +++ b/src/Nazara/Audio/Formats/libvorbisLoader.hpp @@ -0,0 +1,20 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_LOADERS_LIBVORBIS_HPP +#define NAZARA_LOADERS_LIBVORBIS_HPP + +#include +#include +#include + +namespace Nz::Loaders +{ + SoundBufferLoader::Entry GetSoundBufferLoader_libvorbis(); + SoundStreamLoader::Entry GetSoundStreamLoader_libvorbis(); +} + +#endif diff --git a/src/Nazara/Audio/Formats/minimp3Loader.cpp b/src/Nazara/Audio/Formats/minimp3Loader.cpp new file mode 100644 index 000000000..da5329048 --- /dev/null +++ b/src/Nazara/Audio/Formats/minimp3Loader.cpp @@ -0,0 +1,369 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Audio module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MINIMP3_IMPLEMENTATION +#define MINIMP3_NO_STDIO +#include + +#include + +namespace Nz +{ + namespace + { + std::optional GuessFormat(UInt32 channelCount) + { + switch (channelCount) + { + case 1: + return AudioFormat::I16_Mono; + + case 2: + return AudioFormat::I16_Stereo; + + case 4: + return AudioFormat::I16_Quad; + + case 6: + return AudioFormat::I16_5_1; + + case 7: + return AudioFormat::I16_6_1; + + case 8: + return AudioFormat::I16_7_1; + + default: + return std::nullopt; + } + } + + std::string ErrToString(int errCode) + { + switch (errCode) + { + case 0: return "no error"; + case MP3D_E_PARAM: return "wrong parameters"; + case MP3D_E_MEMORY: return "not enough memory"; + case MP3D_E_IOERROR: return "I/O error"; + case MP3D_E_USER: return "aborted"; + case MP3D_E_DECODE: return "decoding error"; + default: return "unknown error"; + } + } + + size_t ReadCallback(void* buf, size_t size, void* user_data) + { + Stream* stream = static_cast(user_data); + return static_cast(stream->Read(buf, size)); + } + + int SeekCallback(uint64_t position, void* user_data) + { + Stream* stream = static_cast(user_data); + return (stream->SetCursorPos(position)) ? 0 : MP3D_E_IOERROR; + } + + bool IsSupported(const std::string_view& extension) + { + return extension == "mp3"; + } + + Ternary CheckMp3(Stream& stream) + { + mp3dec_io_t io; + io.read = &ReadCallback; + io.read_data = &stream; + io.seek = &SeekCallback; + io.seek_data = &stream; + + std::vector buffer(MINIMP3_BUF_SIZE); + return (mp3dec_detect_cb(&io, buffer.data(), buffer.size()) == 0) ? Ternary::True : Ternary::False; + } + + std::shared_ptr LoadSoundBuffer(Stream& stream, const SoundBufferParams& parameters) + { + static_assert(std::is_same_v); + + mp3dec_io_t io; + io.read = &ReadCallback; + io.read_data = &stream; + io.seek = &SeekCallback; + io.seek_data = &stream; + + struct UserData + { + std::vector samples; + }; + + UserData userdata; + + mp3dec_t dec; + mp3dec_file_info_t info; + std::vector buffer(MINIMP3_BUF_SIZE); + int err = mp3dec_load_cb(&dec, &io, buffer.data(), buffer.size(), &info, nullptr, &userdata); + if (err != 0) + { + NazaraError(ErrToString(err)); + return {}; + } + + CallOnExit freeBuffer([&] { std::free(info.buffer); }); + + std::optional formatOpt = GuessFormat(info.channels); + if (!formatOpt) + { + NazaraError("unexpected channel count: " + std::to_string(info.channels)); + return {}; + } + + AudioFormat format = *formatOpt; + + UInt64 sampleCount = UInt64(info.samples); + + if (parameters.forceMono && format != AudioFormat::I16_Mono) + { + UInt64 frameCount = UInt64(info.samples / info.channels); + MixToMono(info.buffer, info.buffer, UInt32(info.channels), frameCount); + + format = AudioFormat::I16_Mono; + sampleCount = frameCount; + } + + return std::make_shared(format, sampleCount, info.hz, info.buffer); + } + + class minimp3Stream : public SoundStream + { + public: + minimp3Stream() : + m_readSampleCount(0) + { + std::memset(&m_decoder, 0, sizeof(m_decoder)); + } + + ~minimp3Stream() + { + mp3dec_ex_close(&m_decoder); + } + + UInt32 GetDuration() const override + { + return m_duration; + } + + AudioFormat GetFormat() const override + { + if (m_mixToMono) + return AudioFormat::I16_Mono; + else + return m_format; + } + + std::mutex& GetMutex() override + { + return m_mutex; + } + + UInt64 GetSampleCount() const override + { + return m_sampleCount; + } + + UInt32 GetSampleRate() const override + { + return m_sampleRate; + } + + bool Open(const std::filesystem::path& filePath, bool forceMono) + { + std::unique_ptr file = std::make_unique(); + if (!file->Open(filePath, OpenMode::ReadOnly)) + { + NazaraError("failed to open stream from file: " + Error::GetLastError()); + return false; + } + + m_ownedStream = std::move(file); + return Open(*m_ownedStream, forceMono); + } + + bool Open(const void* data, std::size_t size, bool forceMono) + { + m_ownedStream = std::make_unique(data, size); + return Open(*m_ownedStream, forceMono); + } + + bool Open(Stream& stream, bool forceMono) + { + m_io.read = &ReadCallback; + m_io.read_data = &stream; + m_io.seek = &SeekCallback; + m_io.seek_data = &stream; + + int err = mp3dec_ex_open_cb(&m_decoder, &m_io, MP3D_SEEK_TO_SAMPLE); + if (err != 0) + { + NazaraError(ErrToString(err)); + return {}; + } + + CallOnExit resetOnError([this] + { + mp3dec_ex_close(&m_decoder); + std::memset(&m_decoder, 0, sizeof(m_decoder)); + }); + + std::optional formatOpt = GuessFormat(m_decoder.info.channels); + if (!formatOpt) + { + NazaraError("unexpected channel count: " + std::to_string(m_decoder.info.channels)); + return false; + } + + m_format = *formatOpt; + + m_duration = static_cast(1000ULL * m_decoder.samples / (m_decoder.info.hz * m_decoder.info.channels)); + m_sampleCount = m_decoder.samples; + m_sampleRate = m_decoder.info.hz; + + // Mixing to mono will be done on the fly + if (forceMono && m_format != AudioFormat::I16_Mono) + { + m_mixToMono = true; + m_sampleCount = static_cast(m_decoder.samples / m_decoder.info.channels); + } + else + m_mixToMono = false; + + resetOnError.Reset(); + + return true; + } + + UInt64 Read(void* buffer, UInt64 sampleCount) override + { + // Convert to mono in the fly if necessary + if (m_mixToMono) + { + UInt32 channelCount = GetChannelCount(m_format); + + // Keep a buffer to the side to prevent allocation + m_mixBuffer.resize(channelCount * sampleCount); + std::size_t readSample = mp3dec_ex_read(&m_decoder, m_mixBuffer.data(), channelCount * sampleCount); + m_readSampleCount += readSample; + + MixToMono(m_mixBuffer.data(), static_cast(buffer), channelCount, sampleCount); + + return readSample / channelCount; + } + else + { + UInt64 readSample = mp3dec_ex_read(&m_decoder, static_cast(buffer), sampleCount); + m_readSampleCount += readSample; + + return readSample; + } + } + + void Seek(UInt64 offset) override + { + mp3dec_ex_seek(&m_decoder, offset); + m_readSampleCount = offset; + } + + UInt64 Tell() override + { + return m_readSampleCount; + } + + private: + std::mutex m_mutex; + std::unique_ptr m_ownedStream; + std::vector m_mixBuffer; + AudioFormat m_format; + mp3dec_ex_t m_decoder; + mp3dec_io_t m_io; + UInt32 m_duration; + UInt32 m_sampleRate; + UInt64 m_readSampleCount; + UInt64 m_sampleCount; + bool m_mixToMono; + }; + + std::shared_ptr LoadSoundStreamFile(const std::filesystem::path& filePath, const SoundStreamParams& parameters) + { + std::shared_ptr soundStream = std::make_shared(); + if (!soundStream->Open(filePath, parameters.forceMono)) + { + NazaraError("failed to open sound stream"); + return {}; + } + + return soundStream; + } + + std::shared_ptr LoadSoundStreamMemory(const void* data, std::size_t size, const SoundStreamParams& parameters) + { + std::shared_ptr soundStream = std::make_shared(); + if (!soundStream->Open(data, size, parameters.forceMono)) + { + NazaraError("failed to open music stream"); + return {}; + } + + return soundStream; + } + + std::shared_ptr LoadSoundStreamStream(Stream& stream, const SoundStreamParams& parameters) + { + std::shared_ptr soundStream = std::make_shared(); + if (!soundStream->Open(stream, parameters.forceMono)) + { + NazaraError("failed to open music stream"); + return {}; + } + + return soundStream; + } + } + + namespace Loaders + { + SoundBufferLoader::Entry GetSoundBufferLoader_minimp3() + { + SoundBufferLoader::Entry loaderEntry; + loaderEntry.extensionSupport = IsSupported; + loaderEntry.streamChecker = [](Stream& stream, const SoundBufferParams&) { return CheckMp3(stream); }; + loaderEntry.streamLoader = LoadSoundBuffer; + + return loaderEntry; + } + + SoundStreamLoader::Entry GetSoundStreamLoader_minimp3() + { + SoundStreamLoader::Entry loaderEntry; + loaderEntry.extensionSupport = IsSupported; + loaderEntry.streamChecker = [](Stream& stream, const SoundStreamParams&) { return CheckMp3(stream); }; + loaderEntry.fileLoader = LoadSoundStreamFile; + loaderEntry.memoryLoader = LoadSoundStreamMemory; + loaderEntry.streamLoader = LoadSoundStreamStream; + + return loaderEntry; + } + } +} diff --git a/src/Nazara/Audio/Formats/minimp3Loader.hpp b/src/Nazara/Audio/Formats/minimp3Loader.hpp new file mode 100644 index 000000000..4d40ef00b --- /dev/null +++ b/src/Nazara/Audio/Formats/minimp3Loader.hpp @@ -0,0 +1,20 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_LOADERS_MINIMP3_HPP +#define NAZARA_LOADERS_MINIMP3_HPP + +#include +#include +#include + +namespace Nz::Loaders +{ + SoundBufferLoader::Entry GetSoundBufferLoader_minimp3(); + SoundStreamLoader::Entry GetSoundStreamLoader_minimp3(); +} + +#endif diff --git a/src/Nazara/Audio/Formats/sndfileLoader.cpp b/src/Nazara/Audio/Formats/sndfileLoader.cpp deleted file mode 100644 index 06e4a523c..000000000 --- a/src/Nazara/Audio/Formats/sndfileLoader.cpp +++ /dev/null @@ -1,380 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Audio module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Nz -{ - namespace Detail - { - sf_count_t GetSize(void* user_data) - { - Stream* stream = static_cast(user_data); - return stream->GetSize(); - } - - sf_count_t Read(void* ptr, sf_count_t count, void* user_data) - { - Stream* stream = static_cast(user_data); - return static_cast(stream->Read(ptr, static_cast(count))); - } - - sf_count_t Seek(sf_count_t offset, int whence, void* user_data) - { - Stream* stream = static_cast(user_data); - switch (whence) - { - case SEEK_CUR: - stream->Read(nullptr, static_cast(offset)); - break; - - case SEEK_END: - stream->SetCursorPos(stream->GetSize() + offset); // L'offset est négatif ici - break; - - case SEEK_SET: - stream->SetCursorPos(offset); - break; - - default: - NazaraInternalError("Seek mode not handled"); - } - - return stream->GetCursorPos(); - } - - sf_count_t Tell(void* user_data) - { - Stream* stream = static_cast(user_data); - return stream->GetCursorPos(); - } - - static SF_VIRTUAL_IO callbacks = {GetSize, Seek, Read, nullptr, Tell}; - - class sndfileStream : public SoundStream - { - public: - sndfileStream() : - m_handle(nullptr) - { - } - - ~sndfileStream() - { - if (m_handle) - sf_close(m_handle); - } - - UInt32 GetDuration() const override - { - return m_duration; - } - - AudioFormat GetFormat() const override - { - // Nous avons besoin du nombre de canaux d'origine pour convertir en mono, nous trichons donc un peu... - if (m_mixToMono) - return AudioFormat_Mono; - else - return m_format; - } - - std::mutex& GetMutex() override - { - return m_mutex; - } - - UInt64 GetSampleCount() const override - { - return m_sampleCount; - } - - UInt32 GetSampleRate() const override - { - return m_sampleRate; - } - - bool Open(const std::filesystem::path& filePath, bool forceMono) - { - // Nous devons gérer nous-même le flux car il doit rester ouvert après le passage du loader - // (les flux automatiquement ouverts par le ResourceLoader étant fermés après celui-ci) - std::unique_ptr file = std::make_unique(); - if (!file->Open(filePath, OpenMode_ReadOnly)) - { - NazaraError("Failed to open stream from file: " + Error::GetLastError()); - return false; - } - - m_ownedStream = std::move(file); - return Open(*m_ownedStream, forceMono); - } - - bool Open(const void* data, std::size_t size, bool forceMono) - { - m_ownedStream = std::make_unique(data, size); - return Open(*m_ownedStream, forceMono); - } - - bool Open(Stream& stream, bool forceMono) - { - SF_INFO infos; - infos.format = 0; // Unknown format - - m_handle = sf_open_virtual(&callbacks, SFM_READ, &infos, &stream); - if (!m_handle) - { - NazaraError("Failed to open sound: " + std::string(sf_strerror(m_handle))); - return false; - } - - // Un peu de RRID - CallOnExit onExit([this] - { - sf_close(m_handle); - m_handle = nullptr; - }); - - m_format = Audio::Instance()->GetAudioFormat(infos.channels); - if (m_format == AudioFormat_Unknown) - { - NazaraError("Channel count not handled"); - return false; - } - - m_sampleCount = infos.channels*infos.frames; - m_sampleRate = infos.samplerate; - - // Durée de la musique (s) = samples / channels*rate - m_duration = static_cast(1000ULL*m_sampleCount / (m_format*m_sampleRate)); - - // https://github.com/LaurentGomila/SFML/issues/271 - // http://www.mega-nerd.com/libsndfile/command.html#SFC_SET_SCALE_FLOAT_INT_READ - ///FIXME: Seulement le Vorbis ? - if (infos.format & SF_FORMAT_VORBIS) - sf_command(m_handle, SFC_SET_SCALE_FLOAT_INT_READ, nullptr, SF_TRUE); - - // On mixera en mono lors de la lecture - if (forceMono && m_format != AudioFormat_Mono) - { - m_mixToMono = true; - m_sampleCount = static_cast(infos.frames); - } - else - m_mixToMono = false; - - onExit.Reset(); - - return true; - } - - UInt64 Read(void* buffer, UInt64 sampleCount) override - { - // Si la musique a été demandée en mono, nous devons la convertir à la volée lors de la lecture - if (m_mixToMono) - { - // On garde un buffer sur le côté pour éviter la réallocation - m_mixBuffer.resize(m_format * sampleCount); - sf_count_t readSampleCount = sf_read_short(m_handle, m_mixBuffer.data(), m_format * sampleCount); - MixToMono(m_mixBuffer.data(), static_cast(buffer), m_format, sampleCount); - - return readSampleCount / m_format; - } - else - return sf_read_short(m_handle, static_cast(buffer), sampleCount); - } - - void Seek(UInt64 offset) override - { - sf_seek(m_handle, offset*m_sampleRate / 1000, SEEK_SET); - } - - UInt64 Tell() override - { - return sf_seek(m_handle, 0, SEEK_CUR) * 1000 / m_sampleRate; - } - - private: - std::vector m_mixBuffer; - std::unique_ptr m_ownedStream; - AudioFormat m_format; - SNDFILE* m_handle; - bool m_mixToMono; - std::mutex m_mutex; - UInt32 m_duration; - UInt32 m_sampleRate; - UInt64 m_sampleCount; - }; - - bool IsSupported(const std::string& extension) - { - static std::set supportedExtensions = { - "aiff", "au", "avr", "caf", "flac", "htk", "ircam", "mat4", "mat5", "mpc2k", - "nist","ogg", "pvf", "raw", "rf64", "sd2", "sds", "svx", "voc", "w64", "wav", "wve" - }; - - return supportedExtensions.find(extension) != supportedExtensions.end(); - } - - Ternary CheckSoundStream(Stream& stream, const SoundStreamParams& parameters) - { - NazaraUnused(parameters); - - SF_INFO info; - info.format = 0; // Format inconnu - - // Si on peut ouvrir le flux, c'est qu'il est dans un format compatible - SNDFILE* file = sf_open_virtual(&callbacks, SFM_READ, &info, &stream); - if (file) - { - sf_close(file); - return Ternary_True; - } - else - return Ternary_False; - } - - SoundStreamRef LoadSoundStreamFile(const std::filesystem::path& filePath, const SoundStreamParams& parameters) - { - std::unique_ptr soundStream = std::make_unique(); - if (!soundStream->Open(filePath, parameters.forceMono)) - { - NazaraError("Failed to open sound stream"); - return nullptr; - } - - soundStream->SetPersistent(false); - return soundStream.release(); - } - - SoundStreamRef LoadSoundStreamMemory(const void* data, std::size_t size, const SoundStreamParams& parameters) - { - std::unique_ptr soundStream(new sndfileStream); - if (!soundStream->Open(data, size, parameters.forceMono)) - { - NazaraError("Failed to open music stream"); - return nullptr; - } - - soundStream->SetPersistent(false); - return soundStream.release(); - } - - SoundStreamRef LoadSoundStreamStream(Stream& stream, const SoundStreamParams& parameters) - { - std::unique_ptr soundStream(new sndfileStream); - if (!soundStream->Open(stream, parameters.forceMono)) - { - NazaraError("Failed to open music stream"); - return nullptr; - } - - soundStream->SetPersistent(false); - return soundStream.release(); - } - - Ternary CheckSoundBuffer(Stream& stream, const SoundBufferParams& parameters) - { - NazaraUnused(parameters); - - SF_INFO info; - info.format = 0; - - SNDFILE* file = sf_open_virtual(&callbacks, SFM_READ, &info, &stream); - if (file) - { - sf_close(file); - return Ternary_True; - } - else - return Ternary_False; - } - - SoundBufferRef LoadSoundBuffer(Stream& stream, const SoundBufferParams& parameters) - { - SF_INFO info; - info.format = 0; - - SNDFILE* file = sf_open_virtual(&callbacks, SFM_READ, &info, &stream); - if (!file) - { - NazaraError("Failed to load sound file: " + std::string(sf_strerror(file))); - return nullptr; - } - - // Lynix utilise RAII... - // C'est très efficace ! - // MemoryLeak est confus... - CallOnExit onExit([file] - { - sf_close(file); - }); - - AudioFormat format = Audio::Instance()->GetAudioFormat(info.channels); - if (format == AudioFormat_Unknown) - { - NazaraError("Channel count not handled"); - return nullptr; - } - - // https://github.com/LaurentGomila/SFML/issues/271 - // http://www.mega-nerd.com/libsndfile/command.html#SFC_SET_SCALE_FLOAT_INT_READ - ///FIXME: Seulement le Vorbis ? - if (info.format & SF_FORMAT_VORBIS) - sf_command(file, SFC_SET_SCALE_FLOAT_INT_READ, nullptr, SF_TRUE); - - unsigned int sampleCount = static_cast(info.frames * info.channels); - std::unique_ptr samples(new Int16[sampleCount]); - - if (sf_read_short(file, samples.get(), sampleCount) != sampleCount) - { - NazaraError("Failed to read samples"); - return nullptr; - } - - // Une conversion en mono est-elle nécessaire ? - if (parameters.forceMono && format != AudioFormat_Mono) - { - // Nous effectuons la conversion en mono dans le même buffer (il va de toute façon être copié) - MixToMono(samples.get(), samples.get(), static_cast(info.channels), static_cast(info.frames)); - - format = AudioFormat_Mono; - sampleCount = static_cast(info.frames); - } - - return SoundBuffer::New(format, sampleCount, info.samplerate, samples.get()); - } - } - - namespace Loaders - { - void Register_sndfile() - { - SoundBufferLoader::RegisterLoader(Detail::IsSupported, Detail::CheckSoundBuffer, Detail::LoadSoundBuffer); - SoundStreamLoader::RegisterLoader(Detail::IsSupported, Detail::CheckSoundStream, Detail::LoadSoundStreamStream, Detail::LoadSoundStreamFile, Detail::LoadSoundStreamMemory); - } - - void Unregister_sndfile() - { - SoundBufferLoader::UnregisterLoader(Detail::IsSupported, Detail::CheckSoundBuffer, Detail::LoadSoundBuffer); - SoundStreamLoader::UnregisterLoader(Detail::IsSupported, Detail::CheckSoundStream, Detail::LoadSoundStreamStream, Detail::LoadSoundStreamFile, Detail::LoadSoundStreamMemory); - } - } -} diff --git a/src/Nazara/Audio/Formats/sndfileLoader.hpp b/src/Nazara/Audio/Formats/sndfileLoader.hpp deleted file mode 100644 index f97dfd25b..000000000 --- a/src/Nazara/Audio/Formats/sndfileLoader.hpp +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_LOADERS_SNDFILE_HPP -#define NAZARA_LOADERS_SNDFILE_HPP - -#include - -namespace Nz -{ - namespace Loaders - { - void Register_sndfile(); - void Unregister_sndfile(); - } -} - -#endif // NAZARA_LOADERS_SNDFILE_HPP diff --git a/src/Nazara/Audio/Music.cpp b/src/Nazara/Audio/Music.cpp index 7c101eeec..8e07cc1d1 100644 --- a/src/Nazara/Audio/Music.cpp +++ b/src/Nazara/Audio/Music.cpp @@ -3,12 +3,14 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include +#include +#include #include #include #include -#include #include #include #include @@ -26,23 +28,25 @@ namespace Nz struct MusicImpl { ALenum audioFormat; + std::atomic_bool streaming = false; std::atomic processedSamples; std::vector chunkSamples; std::mutex bufferLock; - SoundStreamRef stream; + std::shared_ptr stream; std::thread thread; - UInt64 playingOffset; + UInt64 streamOffset; bool loop = false; - bool streaming = false; unsigned int sampleRate; }; + Music::Music() = default; + Music::Music(Music&&) noexcept = default; + /*! * \brief Destructs the object and calls Destroy * * \see Destroy */ - Music::~Music() { Destroy(); @@ -55,7 +59,7 @@ namespace Nz * \param soundStream Sound stream which is the source for the music */ - bool Music::Create(SoundStream* soundStream) + bool Music::Create(std::shared_ptr soundStream) { NazaraAssert(soundStream, "Invalid stream"); @@ -63,11 +67,11 @@ namespace Nz AudioFormat format = soundStream->GetFormat(); - m_impl = new MusicImpl; + m_impl = std::make_unique(); m_impl->sampleRate = soundStream->GetSampleRate(); - m_impl->audioFormat = OpenAL::AudioFormat[format]; - m_impl->chunkSamples.resize(format * m_impl->sampleRate); // One second of samples - m_impl->stream = soundStream; + m_impl->audioFormat = OpenAL::AudioFormat[UnderlyingCast(format)]; + m_impl->chunkSamples.resize(GetChannelCount(format) * m_impl->sampleRate); // One second of samples + m_impl->stream = std::move(soundStream); SetPlayingOffset(0); @@ -85,8 +89,7 @@ namespace Nz { StopThread(); - delete m_impl; - m_impl = nullptr; + m_impl.reset(); } } @@ -146,7 +149,7 @@ namespace Nz ALint samples = 0; alGetSourcei(m_source, AL_SAMPLE_OFFSET, &samples); - return static_cast((1000ULL * (samples + (m_impl->processedSamples / m_impl->stream->GetFormat()))) / m_impl->sampleRate); + return static_cast((1000ULL * (samples + (m_impl->processedSamples / GetChannelCount(m_impl->stream->GetFormat())))) / m_impl->sampleRate); } /*! @@ -188,8 +191,8 @@ namespace Nz SoundStatus status = GetInternalStatus(); // To compensate any delays (or the timelaps between Play() and the thread startup) - if (m_impl->streaming && status == SoundStatus_Stopped) - status = SoundStatus_Playing; + if (m_impl->streaming && status == SoundStatus::Stopped) + status = SoundStatus::Playing; return status; } @@ -216,8 +219,8 @@ namespace Nz */ bool Music::OpenFromFile(const std::filesystem::path& filePath, const SoundStreamParams& params) { - if (SoundStreamRef soundStream = SoundStream::OpenFromFile(filePath, params)) - return Create(soundStream); + if (std::shared_ptr soundStream = SoundStream::OpenFromFile(filePath, params)) + return Create(std::move(soundStream)); else return false; } @@ -234,8 +237,8 @@ namespace Nz */ bool Music::OpenFromMemory(const void* data, std::size_t size, const SoundStreamParams& params) { - if (SoundStreamRef soundStream = SoundStream::OpenFromMemory(data, size, params)) - return Create(soundStream); + if (std::shared_ptr soundStream = SoundStream::OpenFromMemory(data, size, params)) + return Create(std::move(soundStream)); else return false; } @@ -251,8 +254,8 @@ namespace Nz */ bool Music::OpenFromStream(Stream& stream, const SoundStreamParams& params) { - if (SoundStreamRef soundStream = SoundStream::OpenFromStream(stream, params)) - return Create(soundStream); + if (std::shared_ptr soundStream = SoundStream::OpenFromStream(stream, params)) + return Create(std::move(soundStream)); else return false; } @@ -288,11 +291,11 @@ namespace Nz { switch (GetStatus()) { - case SoundStatus_Playing: + case SoundStatus::Playing: SetPlayingOffset(0); break; - case SoundStatus_Paused: + case SoundStatus::Paused: alSourcePlay(m_source); break; @@ -302,9 +305,22 @@ namespace Nz } else { - // Starting streaming's thread + std::mutex mutex; + std::condition_variable cv; + + // Starting streaming thread m_impl->streaming = true; - m_impl->thread = std::thread(&Music::MusicThread, this); + + std::exception_ptr exceptionPtr; + + std::unique_lock lock(mutex); + m_impl->thread = std::thread(&Music::MusicThread, this, std::ref(cv), std::ref(mutex), std::ref(exceptionPtr)); + + // Wait until thread signal it has properly started (or an error occurred) + cv.wait(lock); + + if (exceptionPtr) + std::rethrow_exception(exceptionPtr); } } @@ -326,8 +342,10 @@ namespace Nz if (isPlaying) Stop(); - m_impl->playingOffset = offset; - m_impl->processedSamples = UInt64(offset) * m_impl->sampleRate * m_impl->stream->GetFormat() / 1000ULL; + UInt64 sampleOffset = UInt64(offset) * m_impl->sampleRate * GetChannelCount(m_impl->stream->GetFormat()) / 1000ULL; + + m_impl->processedSamples = sampleOffset; + m_impl->streamOffset = sampleOffset; if (isPlaying) Play(); @@ -346,6 +364,8 @@ namespace Nz SetPlayingOffset(0); } + Music& Music::operator=(Music&&) noexcept = default; + bool Music::FillAndQueueBuffer(unsigned int buffer) { std::size_t sampleCount = m_impl->chunkSamples.size(); @@ -353,7 +373,7 @@ namespace Nz { std::lock_guard lock(m_impl->stream->GetMutex()); - m_impl->stream->Seek(m_impl->playingOffset); + m_impl->stream->Seek(m_impl->streamOffset); // Fill the buffer by reading from the stream for (;;) @@ -370,7 +390,7 @@ namespace Nz break; } - m_impl->playingOffset = m_impl->stream->Tell(); + m_impl->streamOffset = m_impl->stream->Tell(); } // Update the buffer (send it to OpenAL) and queue it if we got any data @@ -383,26 +403,66 @@ namespace Nz return sampleRead != sampleCount; // End of stream (Does not happen when looping) } - void Music::MusicThread() + void Music::MusicThread(std::condition_variable& cv, std::mutex& m, std::exception_ptr& err) { // Allocation of streaming buffers - ALuint buffers[NAZARA_AUDIO_STREAMED_BUFFER_COUNT]; - alGenBuffers(NAZARA_AUDIO_STREAMED_BUFFER_COUNT, buffers); + std::array buffers; + alGenBuffers(NAZARA_AUDIO_STREAMED_BUFFER_COUNT, buffers.data()); - for (unsigned int buffer : buffers) + CallOnExit freebuffers([&] { - if (FillAndQueueBuffer(buffer)) - break; // We have reached the end of the stream, there is no use to add new buffers + alDeleteBuffers(NAZARA_AUDIO_STREAMED_BUFFER_COUNT, buffers.data()); + }); + + + try + { + for (ALuint buffer : buffers) + { + if (FillAndQueueBuffer(buffer)) + break; // We have reached the end of the stream, there is no use to add new buffers + } } + catch (const std::exception&) + { + err = std::current_exception(); + + std::unique_lock lock(m); + cv.notify_all(); + return; + } + + CallOnExit unqueueBuffers([&] + { + // We delete buffers from the stream + ALint queuedBufferCount; + alGetSourcei(m_source, AL_BUFFERS_QUEUED, &queuedBufferCount); + + ALuint buffer; + for (ALint i = 0; i < queuedBufferCount; ++i) + alSourceUnqueueBuffers(m_source, 1, &buffer); + }); alSourcePlay(m_source); + + CallOnExit stopSource([&] + { + // Stop playing of the sound (in the case where it has not been already done) + alSourceStop(m_source); + }); + + // Signal we're good + { + std::unique_lock lock(m); + cv.notify_all(); + } // m & cv no longer exists from here // Reading loop (Filling new buffers as playing) while (m_impl->streaming) { // The reading has stopped, we have reached the end of the stream SoundStatus status = GetInternalStatus(); - if (status == SoundStatus_Stopped) + if (status == SoundStatus::Stopped) { m_impl->streaming = false; break; @@ -434,27 +494,14 @@ namespace Nz // We go back to sleep std::this_thread::sleep_for(std::chrono::milliseconds(50)); } - - // Stop playing of the sound (in the case where it has not been already done) - alSourceStop(m_source); - - // We delete buffers from the stream - ALint queuedBufferCount; - alGetSourcei(m_source, AL_BUFFERS_QUEUED, &queuedBufferCount); - - ALuint buffer; - for (ALint i = 0; i < queuedBufferCount; ++i) - alSourceUnqueueBuffers(m_source, 1, &buffer); - - alDeleteBuffers(NAZARA_AUDIO_STREAMED_BUFFER_COUNT, buffers); } void Music::StopThread() { if (m_impl->streaming) - { m_impl->streaming = false; + + if (m_impl->thread.joinable()) m_impl->thread.join(); - } } } diff --git a/src/Nazara/Audio/OpenAL.cpp b/src/Nazara/Audio/OpenAL.cpp index 3e516115c..1a41a18f8 100644 --- a/src/Nazara/Audio/OpenAL.cpp +++ b/src/Nazara/Audio/OpenAL.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include #include @@ -347,8 +348,7 @@ namespace Nz s_library.Unload(); } - ///WARNING: The integer value is the number of canals owned by the format - ALenum OpenAL::AudioFormat[AudioFormat_Max+1] = {0}; // Added values with loading of OpenAL + ALenum OpenAL::AudioFormat[AudioFormatCount] = {0}; // Added values with loading of OpenAL /*! * \brief Closes the device @@ -440,19 +440,19 @@ namespace Nz } // We complete the formats table - AudioFormat[AudioFormat_Mono] = AL_FORMAT_MONO16; - AudioFormat[AudioFormat_Stereo] = AL_FORMAT_STEREO16; + AudioFormat[UnderlyingCast(AudioFormat::I16_Mono)] = AL_FORMAT_MONO16; + AudioFormat[UnderlyingCast(AudioFormat::I16_Stereo)] = AL_FORMAT_STEREO16; // "The presence of an enum value does not guarantee the applicability of an extension to the current context." if (alIsExtensionPresent("AL_EXT_MCFORMATS")) { - AudioFormat[AudioFormat_Quad] = alGetEnumValue("AL_FORMAT_QUAD16"); - AudioFormat[AudioFormat_5_1] = alGetEnumValue("AL_FORMAT_51CHN16"); - AudioFormat[AudioFormat_6_1] = alGetEnumValue("AL_FORMAT_61CHN16"); - AudioFormat[AudioFormat_7_1] = alGetEnumValue("AL_FORMAT_71CHN16"); + AudioFormat[UnderlyingCast(AudioFormat::I16_Quad)] = alGetEnumValue("AL_FORMAT_QUAD16"); + AudioFormat[UnderlyingCast(AudioFormat::I16_5_1)] = alGetEnumValue("AL_FORMAT_51CHN16"); + AudioFormat[UnderlyingCast(AudioFormat::I16_6_1)] = alGetEnumValue("AL_FORMAT_61CHN16"); + AudioFormat[UnderlyingCast(AudioFormat::I16_7_1)] = alGetEnumValue("AL_FORMAT_71CHN16"); } else if (alIsExtensionPresent("AL_LOKI_quadriphonic")) - AudioFormat[AudioFormat_Quad] = alGetEnumValue("AL_FORMAT_QUAD16_LOKI"); + AudioFormat[UnderlyingCast(AudioFormat::I16_Quad)] = alGetEnumValue("AL_FORMAT_QUAD16_LOKI"); return true; } diff --git a/src/Nazara/Audio/Sound.cpp b/src/Nazara/Audio/Sound.cpp index ec7306a99..5e02f8dfa 100644 --- a/src/Nazara/Audio/Sound.cpp +++ b/src/Nazara/Audio/Sound.cpp @@ -23,21 +23,9 @@ namespace Nz * * \param soundBuffer Buffer to read sound from */ - Sound::Sound(const SoundBuffer* soundBuffer) + Sound::Sound(std::shared_ptr soundBuffer) { - SetBuffer(soundBuffer); - } - - /*! - * \brief Constructs a Sound object which is a copy of another - * - * \param sound Sound to copy - */ - Sound::Sound(const Sound& sound) : - SoundEmitter(sound) - { - SetBuffer(sound.m_buffer); - EnableLooping(sound.IsLooping()); + SetBuffer(std::move(soundBuffer)); } /*! @@ -66,7 +54,7 @@ namespace Nz * \brief Gets the internal buffer * \return Internal buffer */ - const SoundBuffer* Sound::GetBuffer() const + const std::shared_ptr& Sound::GetBuffer() const { return m_buffer; } @@ -131,15 +119,6 @@ namespace Nz return m_buffer != nullptr; } - /*! - * \brief Checks whether the sound is playing - * \return true if it is the case - */ - bool Sound::IsPlaying() const - { - return GetStatus() == SoundStatus_Playing; - } - /*! * \brief Loads the sound from file * \return true if loading is successful @@ -151,7 +130,7 @@ namespace Nz */ bool Sound::LoadFromFile(const std::filesystem::path& filePath, const SoundBufferParams& params) { - SoundBufferRef buffer = SoundBuffer::LoadFromFile(filePath, params); + std::shared_ptr buffer = SoundBuffer::LoadFromFile(filePath, params); if (!buffer) { NazaraError("Failed to load buffer from file (" + filePath.generic_u8string() + ')'); @@ -174,7 +153,7 @@ namespace Nz */ bool Sound::LoadFromMemory(const void* data, std::size_t size, const SoundBufferParams& params) { - SoundBufferRef buffer = SoundBuffer::LoadFromMemory(data, size, params); + std::shared_ptr buffer = SoundBuffer::LoadFromMemory(data, size, params); if (!buffer) { NazaraError("Failed to load buffer from memory (" + PointerToString(data) + ')'); @@ -196,7 +175,7 @@ namespace Nz */ bool Sound::LoadFromStream(Stream& stream, const SoundBufferParams& params) { - SoundBufferRef buffer = SoundBuffer::LoadFromStream(stream, params); + std::shared_ptr buffer = SoundBuffer::LoadFromStream(stream, params); if (!buffer) { NazaraError("Failed to load buffer from stream"); @@ -237,7 +216,7 @@ namespace Nz * * \remark Produces a NazaraError if buffer is invalid with NAZARA_AUDIO_SAFE defined */ - void Sound::SetBuffer(const SoundBuffer* buffer) + void Sound::SetBuffer(std::shared_ptr buffer) { NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); NazaraAssert(!buffer || buffer->IsValid(), "Invalid sound buffer"); @@ -247,7 +226,7 @@ namespace Nz Stop(); - m_buffer = buffer; + m_buffer = std::move(buffer); if (m_buffer) alSourcei(m_source, AL_BUFFER, m_buffer->GetOpenALBuffer()); diff --git a/src/Nazara/Audio/SoundBuffer.cpp b/src/Nazara/Audio/SoundBuffer.cpp index 2c562f2ae..fe078846c 100644 --- a/src/Nazara/Audio/SoundBuffer.cpp +++ b/src/Nazara/Audio/SoundBuffer.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include #include @@ -45,6 +46,8 @@ namespace Nz UInt32 sampleRate; }; + SoundBuffer::SoundBuffer() = default; + /*! * \brief Constructs a SoundBuffer object * @@ -71,17 +74,7 @@ namespace Nz #endif } - /*! - * \brief Destructs the object and calls Destroy - * - * \see Destroy - */ - SoundBuffer::~SoundBuffer() - { - OnSoundBufferRelease(this); - - Destroy(); - } + SoundBuffer::~SoundBuffer() = default; /*! * \brief Creates the SoundBuffer object @@ -138,7 +131,7 @@ namespace Nz CallOnExit clearBufferOnExit([buffer] () { alDeleteBuffers(1, &buffer); }); - alBufferData(buffer, OpenAL::AudioFormat[format], samples, static_cast(sampleCount*sizeof(Int16)), static_cast(sampleRate)); + alBufferData(buffer, OpenAL::AudioFormat[UnderlyingCast(format)], samples, static_cast(sampleCount*sizeof(Int16)), static_cast(sampleRate)); if (alGetError() != AL_NO_ERROR) { @@ -146,9 +139,9 @@ namespace Nz return false; } - m_impl = new SoundBufferImpl; + m_impl = std::make_unique(); m_impl->buffer = buffer; - m_impl->duration = static_cast((1000ULL*sampleCount / (format * sampleRate))); + m_impl->duration = static_cast((1000ULL*sampleCount / (GetChannelCount(format) * sampleRate))); m_impl->format = format; m_impl->sampleCount = sampleCount; m_impl->sampleRate = sampleRate; @@ -163,16 +156,9 @@ namespace Nz /*! * \brief Destroys the current sound buffer and frees resources */ - void SoundBuffer::Destroy() { - if (m_impl) - { - OnSoundBufferDestroy(this); - - delete m_impl; - m_impl = nullptr; - } + m_impl.reset(); } /*! @@ -259,7 +245,10 @@ namespace Nz */ bool SoundBuffer::IsFormatSupported(AudioFormat format) { - return Audio::Instance()->IsFormatSupported(format); + Audio* audio = Audio::Instance(); + NazaraAssert(audio, "Audio module has not been initialized"); + + return audio->IsFormatSupported(format); } /*! @@ -269,9 +258,12 @@ namespace Nz * \param filePath Path to the file * \param params Parameters for the sound buffer */ - SoundBufferRef SoundBuffer::LoadFromFile(const std::filesystem::path& filePath, const SoundBufferParams& params) + std::shared_ptr SoundBuffer::LoadFromFile(const std::filesystem::path& filePath, const SoundBufferParams& params) { - return SoundBufferLoader::LoadFromFile(filePath, params); + Audio* audio = Audio::Instance(); + NazaraAssert(audio, "Audio module has not been initialized"); + + return audio->GetSoundBufferLoader().LoadFromFile(filePath, params); } /*! @@ -282,9 +274,12 @@ namespace Nz * \param size Size of the memory * \param params Parameters for the sound buffer */ - SoundBufferRef SoundBuffer::LoadFromMemory(const void* data, std::size_t size, const SoundBufferParams& params) + std::shared_ptr SoundBuffer::LoadFromMemory(const void* data, std::size_t size, const SoundBufferParams& params) { - return SoundBufferLoader::LoadFromMemory(data, size, params); + Audio* audio = Audio::Instance(); + NazaraAssert(audio, "Audio module has not been initialized"); + + return audio->GetSoundBufferLoader().LoadFromMemory(data, size, params); } /*! @@ -294,9 +289,12 @@ namespace Nz * \param stream Stream to the sound buffer * \param params Parameters for the sound buffer */ - SoundBufferRef SoundBuffer::LoadFromStream(Stream& stream, const SoundBufferParams& params) + std::shared_ptr SoundBuffer::LoadFromStream(Stream& stream, const SoundBufferParams& params) { - return SoundBufferLoader::LoadFromStream(stream, params); + Audio* audio = Audio::Instance(); + NazaraAssert(audio, "Audio module has not been initialized"); + + return audio->GetSoundBufferLoader().LoadFromStream(stream, params); } /*! @@ -317,41 +315,4 @@ namespace Nz return m_impl->buffer; } - - /*! - * \brief Initializes the libraries and managers - * \return true if initialization is successful - * - * \remark Produces a NazaraError if sub-initialization failed - */ - bool SoundBuffer::Initialize() - { - if (!SoundBufferLibrary::Initialize()) - { - NazaraError("Failed to initialise library"); - return false; - } - - if (!SoundBufferManager::Initialize()) - { - NazaraError("Failed to initialise manager"); - return false; - } - - return true; - } - - /*! - * \brief Uninitializes the libraries and managers - */ - void SoundBuffer::Uninitialize() - { - SoundBufferManager::Uninitialize(); - SoundBufferLibrary::Uninitialize(); - } - - SoundBufferLibrary::LibraryMap SoundBuffer::s_library; - SoundBufferLoader::LoaderList SoundBuffer::s_loaders; - SoundBufferManager::ManagerMap SoundBuffer::s_managerMap; - SoundBufferManager::ManagerParams SoundBuffer::s_managerParameters; } diff --git a/src/Nazara/Audio/SoundEmitter.cpp b/src/Nazara/Audio/SoundEmitter.cpp index c81f26846..deeb27855 100644 --- a/src/Nazara/Audio/SoundEmitter.cpp +++ b/src/Nazara/Audio/SoundEmitter.cpp @@ -326,18 +326,18 @@ namespace Nz { case AL_INITIAL: case AL_STOPPED: - return SoundStatus_Stopped; + return SoundStatus::Stopped; case AL_PAUSED: - return SoundStatus_Paused; + return SoundStatus::Paused; case AL_PLAYING: - return SoundStatus_Playing; + return SoundStatus::Playing; default: NazaraInternalError("Source state unrecognized"); } - return SoundStatus_Stopped; + return SoundStatus::Stopped; } } diff --git a/src/Nazara/Audio/SoundStream.cpp b/src/Nazara/Audio/SoundStream.cpp index e4f1a766e..8f388f67a 100644 --- a/src/Nazara/Audio/SoundStream.cpp +++ b/src/Nazara/Audio/SoundStream.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include namespace Nz { @@ -18,23 +19,57 @@ namespace Nz * * \remark This class is abstract */ - SoundStream::~SoundStream() = default; - SoundStreamRef SoundStream::OpenFromFile(const std::filesystem::path& filePath, const SoundStreamParams& params) + /*! + * \brief Opens the sound stream from file + * \return true if loading is successful + * + * \param filePath Path to the file + * \param params Parameters for the sound stream + * + * \remark The file must stay valid until the sound stream is destroyed + */ + std::shared_ptr SoundStream::OpenFromFile(const std::filesystem::path& filePath, const SoundStreamParams& params) { - return SoundStreamLoader::LoadFromFile(filePath, params); + Audio* audio = Audio::Instance(); + NazaraAssert(audio, "Audio module has not been initialized"); + + return audio->GetSoundStreamLoader().LoadFromFile(filePath, params); } - SoundStreamRef SoundStream::OpenFromMemory(const void* data, std::size_t size, const SoundStreamParams& params) + /*! + * \brief Opens the sound stream from memory + * \return true if loading is successful + * + * \param data Raw memory + * \param size Size of the memory + * \param params Parameters for the sound stream + * + * \remark The memory block must stay valid until the sound stream is destroyed + */ + std::shared_ptr SoundStream::OpenFromMemory(const void* data, std::size_t size, const SoundStreamParams& params) { - return SoundStreamLoader::LoadFromMemory(data, size, params); + Audio* audio = Audio::Instance(); + NazaraAssert(audio, "Audio module has not been initialized"); + + return audio->GetSoundStreamLoader().LoadFromMemory(data, size, params); } - SoundStreamRef SoundStream::OpenFromStream(Stream& stream, const SoundStreamParams& params) + /*! + * \brief Opens the sound stream from stream + * \return true if loading is successful + * + * \param stream Stream to the sound stream + * \param params Parameters for the sound stream + * + * \remark The stream must stay valid until the sound stream is destroyed + */ + std::shared_ptr SoundStream::OpenFromStream(Stream& stream, const SoundStreamParams& params) { - return SoundStreamLoader::LoadFromStream(stream, params); - } + Audio* audio = Audio::Instance(); + NazaraAssert(audio, "Audio module has not been initialized"); - SoundStreamLoader::LoaderList SoundStream::s_loaders; + return audio->GetSoundStreamLoader().LoadFromStream(stream, params); + } } diff --git a/src/Nazara/Core/AbstractHash.cpp b/src/Nazara/Core/AbstractHash.cpp index dff2570bc..b70c3d5fc 100644 --- a/src/Nazara/Core/AbstractHash.cpp +++ b/src/Nazara/Core/AbstractHash.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include #include @@ -40,42 +41,42 @@ namespace Nz std::unique_ptr AbstractHash::Get(HashType type) { - NazaraAssert(type <= HashType_Max, "Hash type value out of enum"); + NazaraAssert(type <= HashType::Max, "Hash type value out of enum"); switch (type) { - case HashType_Fletcher16: + case HashType::Fletcher16: return std::make_unique(); - case HashType_CRC32: + case HashType::CRC32: return std::make_unique(); - case HashType_CRC64: + case HashType::CRC64: return std::make_unique(); - case HashType_MD5: + case HashType::MD5: return std::make_unique(); - case HashType_SHA1: + case HashType::SHA1: return std::make_unique(); - case HashType_SHA224: + case HashType::SHA224: return std::make_unique(); - case HashType_SHA256: + case HashType::SHA256: return std::make_unique(); - case HashType_SHA384: + case HashType::SHA384: return std::make_unique(); - case HashType_SHA512: + case HashType::SHA512: return std::make_unique(); - case HashType_Whirlpool: + case HashType::Whirlpool: return std::make_unique(); } - NazaraInternalError("Hash type not handled (0x" + NumberToString(type, 16) + ')'); + NazaraInternalError("Hash type not handled (0x" + NumberToString(UnderlyingCast(type), 16) + ')'); return nullptr; } } diff --git a/src/Nazara/Core/AbstractLogger.cpp b/src/Nazara/Core/AbstractLogger.cpp index 8eba0df9b..da9614364 100644 --- a/src/Nazara/Core/AbstractLogger.cpp +++ b/src/Nazara/Core/AbstractLogger.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include @@ -11,13 +12,13 @@ namespace Nz namespace { const char* errorType[] = { - "Assert failed: ", // ErrorType_AssertFailed - "Internal error: ", // ErrorType_Internal - "Error: ", // ErrorType_Normal - "Warning: " // ErrorType_Warning + "Assert failed: ", // ErrorType::AssertFailed + "Internal error: ", // ErrorType::Internal + "Error: ", // ErrorType::Normal + "Warning: " // ErrorType::Warning }; - static_assert(sizeof(errorType) / sizeof(const char*) == ErrorType_Max + 1, "Error type array is incomplete"); + static_assert(sizeof(errorType) / sizeof(const char*) == ErrorTypeCount, "Error type array is incomplete"); } /*! @@ -27,7 +28,6 @@ namespace Nz * * \remark This class is abstract */ - AbstractLogger::~AbstractLogger() = default; /*! @@ -39,11 +39,10 @@ namespace Nz * \param file Filename * \param function Name of the function throwing the error */ - void AbstractLogger::WriteError(ErrorType type, const std::string_view& error, unsigned int line, const char* file, const char* function) { std::ostringstream ss; - ss << errorType[type] << error; + ss << errorType[UnderlyingCast(type)] << error; if (line != 0 && file && function) ss << " (" << file << ':' << line << ": " << function << ')'; diff --git a/src/Nazara/Core/Core.cpp b/src/Nazara/Core/Core.cpp index 17db66a9f..e1cd2862a 100644 --- a/src/Nazara/Core/Core.cpp +++ b/src/Nazara/Core/Core.cpp @@ -29,6 +29,7 @@ namespace Nz Core::~Core() { + LogUninit(); HardwareInfo::Uninitialize(); Log::Uninitialize(); PluginManager::Uninitialize(); diff --git a/src/Nazara/Core/Error.cpp b/src/Nazara/Core/Error.cpp index 348950bec..ff928b24e 100644 --- a/src/Nazara/Core/Error.cpp +++ b/src/Nazara/Core/Error.cpp @@ -31,7 +31,7 @@ namespace Nz * \return Flag */ - UInt32 Error::GetFlags() + ErrorModeFlags Error::GetFlags() { return s_flags; } @@ -88,7 +88,7 @@ namespace Nz #if defined(NAZARA_PLATFORM_WINDOWS) wchar_t* buffer = nullptr; - FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, + DWORD length = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, code, 0, @@ -96,6 +96,9 @@ namespace Nz 0, nullptr); + if (length == 0) + return ""; + CallOnExit freeOnExit([buffer] { LocalFree(buffer); }); return FromWideString(buffer); #elif defined(NAZARA_PLATFORM_POSIX) @@ -113,7 +116,7 @@ namespace Nz * \param flags Flags for the error */ - void Error::SetFlags(UInt32 flags) + void Error::SetFlags(ErrorModeFlags flags) { s_flags = flags; } @@ -130,7 +133,7 @@ namespace Nz void Error::Trigger(ErrorType type, std::string error) { - if (type == ErrorType_AssertFailed || (s_flags & ErrorFlag_Silent) == 0 || (s_flags & ErrorFlag_SilentDisabled) != 0) + if (type == ErrorType::AssertFailed || (s_flags & ErrorMode::Silent) == 0 || (s_flags & ErrorMode::SilentDisabled) != 0) Log::WriteError(type, error); s_lastError = std::move(error); @@ -139,12 +142,12 @@ namespace Nz s_lastErrorLine = 0; #if NAZARA_CORE_EXIT_ON_ASSERT_FAILURE - if (type == ErrorType_AssertFailed) + if (type == ErrorType::AssertFailed) std::abort(); #endif - if (type == ErrorType_AssertFailed || (type != ErrorType_Warning && - (s_flags & ErrorFlag_ThrowException) != 0 && (s_flags & ErrorFlag_ThrowExceptionDisabled) == 0)) + if (type == ErrorType::AssertFailed || (type != ErrorType::Warning && + (s_flags & ErrorMode::ThrowException) != 0 && (s_flags & ErrorMode::ThrowExceptionDisabled) == 0)) throw std::runtime_error(s_lastError); } @@ -165,7 +168,7 @@ namespace Nz { file = GetCurrentFileRelativeToEngine(file); - if (type == ErrorType_AssertFailed || (s_flags & ErrorFlag_Silent) == 0 || (s_flags & ErrorFlag_SilentDisabled) != 0) + if (type == ErrorType::AssertFailed || (s_flags & ErrorMode::Silent) == 0 || (s_flags & ErrorMode::SilentDisabled) != 0) Log::WriteError(type, error, line, file, function); s_lastError = std::move(error); @@ -174,12 +177,12 @@ namespace Nz s_lastErrorLine = line; #if NAZARA_CORE_EXIT_ON_ASSERT_FAILURE - if (type == ErrorType_AssertFailed) + if (type == ErrorType::AssertFailed) std::abort(); #endif - if (type == ErrorType_AssertFailed || (type != ErrorType_Warning && - (s_flags & ErrorFlag_ThrowException) != 0 && (s_flags & ErrorFlag_ThrowExceptionDisabled) == 0)) + if (type == ErrorType::AssertFailed || (type != ErrorType::Warning && + (s_flags & ErrorMode::ThrowException) != 0 && (s_flags & ErrorMode::ThrowExceptionDisabled) == 0)) throw std::runtime_error(s_lastError); } @@ -194,7 +197,7 @@ namespace Nz return file; } - UInt32 Error::s_flags = ErrorFlag_None; + ErrorModeFlags Error::s_flags = ErrorMode::None; std::string Error::s_lastError; const char* Error::s_lastErrorFunction = ""; const char* Error::s_lastErrorFile = ""; diff --git a/src/Nazara/Core/ErrorFlags.cpp b/src/Nazara/Core/ErrorFlags.cpp index 478799672..8a4b424ab 100644 --- a/src/Nazara/Core/ErrorFlags.cpp +++ b/src/Nazara/Core/ErrorFlags.cpp @@ -21,7 +21,7 @@ namespace Nz * \param replace Replace the entirely the old flag if true, else do a "OR" */ - ErrorFlags::ErrorFlags(UInt32 flags, bool replace) : + ErrorFlags::ErrorFlags(ErrorModeFlags flags, bool replace) : m_previousFlags(Error::GetFlags()) { SetFlags(flags, replace); @@ -40,8 +40,7 @@ namespace Nz * \brief Gets the previous flag * \return Previous flag */ - - UInt32 ErrorFlags::GetPreviousFlags() const + ErrorModeFlags ErrorFlags::GetPreviousFlags() const { return m_previousFlags; } @@ -52,8 +51,7 @@ namespace Nz * \param flags Flags for the error * \param replace Replace the entirely the old flag if true, else do a "OR" */ - - void ErrorFlags::SetFlags(UInt32 flags, bool replace) + void ErrorFlags::SetFlags(ErrorModeFlags flags, bool replace) { if (!replace) flags |= m_previousFlags; diff --git a/src/Nazara/Core/File.cpp b/src/Nazara/Core/File.cpp index 3b1be9ada..56bd2ae41 100644 --- a/src/Nazara/Core/File.cpp +++ b/src/Nazara/Core/File.cpp @@ -91,7 +91,7 @@ namespace Nz { m_impl.reset(); - m_openMode = OpenMode_NotOpen; + m_openMode = OpenMode::NotOpen; } } @@ -226,13 +226,13 @@ namespace Nz if (m_filePath.empty()) return false; - if (openMode == OpenMode_NotOpen) + if (openMode == OpenMode::NotOpen) return false; std::unique_ptr impl = std::make_unique(this); if (!impl->Open(m_filePath, openMode)) { - ErrorFlags flags(ErrorFlag_Silent); // Silent by default + ErrorFlags flags(ErrorMode::Silent); // Silent by default NazaraError("Failed to open \"" + m_filePath.generic_u8string() + "\": " + Error::GetLastSystemError()); return false; } @@ -240,10 +240,10 @@ namespace Nz m_openMode = openMode; m_impl = std::move(impl); - if (m_openMode & OpenMode_Text) - m_streamOptions |= StreamOption_Text; + if (m_openMode & OpenMode::Text) + m_streamOptions |= StreamOption::Text; else - m_streamOptions &= ~StreamOption_Text; + m_streamOptions &= ~StreamOption::Text; return true; } @@ -296,7 +296,7 @@ namespace Nz { NazaraAssert(IsOpen(), "File is not open"); - return m_impl->SetCursorPos(CursorPosition_AtBegin, offset); + return m_impl->SetCursorPos(CursorPosition::AtBegin, offset); } /*! @@ -382,8 +382,8 @@ namespace Nz { // If we don't have to read, we move forward UInt64 currentPos = m_impl->GetCursorPos(); - - m_impl->SetCursorPos(CursorPosition_AtCurrent, size); + if (!m_impl->SetCursorPos(CursorPosition::AtCurrent, size)) + return 0; return static_cast(m_impl->GetCursorPos() - currentPos); } @@ -429,7 +429,7 @@ namespace Nz NazaraAssert(hash, "Invalid hash"); File file(originalFile.GetPath()); - if (!file.Open(OpenMode_ReadOnly)) + if (!file.Open(OpenMode::ReadOnly)) { NazaraError("Unable to open file"); return false; diff --git a/src/Nazara/Core/HardwareInfo.cpp b/src/Nazara/Core/HardwareInfo.cpp index a048ef99b..e190507f5 100644 --- a/src/Nazara/Core/HardwareInfo.cpp +++ b/src/Nazara/Core/HardwareInfo.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include #include @@ -27,55 +28,53 @@ namespace Nz ProcessorVendor vendorEnum; }; - // Exceptionellement, la valeur "unknown" est intégrée - const char* vendorNames[] = + const char* s_vendorNames[] = { - "Unknown", // ProcessorVendor_Unknown - "Advanced Micro Devices", // ProcessorVendor_AMD - "Centaur Technology", // ProcessorVendor_Centaur - "Cyrix Corporation", // ProcessorVendor_Cyrix - "Intel Corporation", // ProcessorVendor_Intel - "Kernel-based Virtual Machine", // ProcessorVendor_KVM - "Microsoft Hyper-V", // ProcessorVendor_HyperV - "National Semiconductor", // ProcessorVendor_NSC - "NexGen", // ProcessorVendor_NexGen - "Rise Technology", // ProcessorVendor_Rise - "Silicon Integrated Systems", // ProcessorVendor_SIS - "Transmeta Corporation", // ProcessorVendor_Transmeta - "United Microelectronics Corporation", // ProcessorVendor_UMC - "VIA Technologies", // ProcessorVendor_VIA - "VMware", // ProcessorVendor_VMware - "Vortex86", // ProcessorVendor_Vortex - "Xen" // ProcessorVendor_XenHVM + "Advanced Micro Devices", // ProcessorVendor::AMD + "Centaur Technology", // ProcessorVendor::Centaur + "Cyrix Corporation", // ProcessorVendor::Cyrix + "Intel Corporation", // ProcessorVendor::Intel + "Kernel-based Virtual Machine", // ProcessorVendor::KVM + "Microsoft Hyper-V", // ProcessorVendor::HyperV + "National Semiconductor", // ProcessorVendor::NSC + "NexGen", // ProcessorVendor::NexGen + "Rise Technology", // ProcessorVendor::Rise + "Silicon Integrated Systems", // ProcessorVendor::SIS + "Transmeta Corporation", // ProcessorVendor::Transmeta + "United Microelectronics Corporation", // ProcessorVendor::UMC + "VIA Technologies", // ProcessorVendor::VIA + "VMware", // ProcessorVendor::VMware + "Vortex86", // ProcessorVendor::Vortex + "Xen" // ProcessorVendor::XenHVM }; - static_assert(sizeof(vendorNames)/sizeof(const char*) == ProcessorVendor_Max+2, "Processor vendor name array is incomplete"); + static_assert(sizeof(s_vendorNames)/sizeof(const char*) == ProcessorVendorCount, "Processor vendor name array is incomplete"); VendorString vendorStrings[] = { // Triés par ordre alphabétique (Majuscules primant sur minuscules) - {"AMDisbetter!", ProcessorVendor_AMD}, - {"AuthenticAMD", ProcessorVendor_AMD}, - {"CentaurHauls", ProcessorVendor_Centaur}, - {"CyrixInstead", ProcessorVendor_Cyrix}, - {"GenuineIntel", ProcessorVendor_Intel}, - {"GenuineTMx86", ProcessorVendor_Transmeta}, - {"Geode by NSC", ProcessorVendor_NSC}, - {"KVMKVMKVMKVM", ProcessorVendor_KVM}, - {"Microsoft Hv", ProcessorVendor_HyperV}, - {"NexGenDriven", ProcessorVendor_NexGen}, - {"RiseRiseRise", ProcessorVendor_Rise}, - {"SiS SiS SiS ", ProcessorVendor_SIS}, - {"TransmetaCPU", ProcessorVendor_Transmeta}, - {"UMC UMC UMC ", ProcessorVendor_UMC}, - {"VIA VIA VIA ", ProcessorVendor_VIA}, - {"VMwareVMware", ProcessorVendor_VMware}, - {"Vortex86 SoC", ProcessorVendor_Vortex}, - {"XenVMMXenVMM", ProcessorVendor_XenHVM} + {"AMDisbetter!", ProcessorVendor::AMD}, + {"AuthenticAMD", ProcessorVendor::AMD}, + {"CentaurHauls", ProcessorVendor::Centaur}, + {"CyrixInstead", ProcessorVendor::Cyrix}, + {"GenuineIntel", ProcessorVendor::Intel}, + {"GenuineTMx86", ProcessorVendor::Transmeta}, + {"Geode by NSC", ProcessorVendor::NSC}, + {"KVMKVMKVMKVM", ProcessorVendor::KVM}, + {"Microsoft Hv", ProcessorVendor::HyperV}, + {"NexGenDriven", ProcessorVendor::NexGen}, + {"RiseRiseRise", ProcessorVendor::Rise}, + {"SiS SiS SiS ", ProcessorVendor::SIS}, + {"TransmetaCPU", ProcessorVendor::Transmeta}, + {"UMC UMC UMC ", ProcessorVendor::UMC}, + {"VIA VIA VIA ", ProcessorVendor::VIA}, + {"VMwareVMware", ProcessorVendor::VMware}, + {"Vortex86 SoC", ProcessorVendor::Vortex}, + {"XenVMMXenVMM", ProcessorVendor::XenHVM} }; - ProcessorVendor s_vendorEnum = ProcessorVendor_Unknown; - bool s_capabilities[ProcessorCap_Max+1] = {false}; + ProcessorVendor s_vendorEnum = ProcessorVendor::Unknown; + bool s_capabilities[ProcessorCapCount] = {false}; bool s_initialized = false; char s_brandString[48] = "Not initialized"; @@ -155,7 +154,7 @@ namespace Nz if (!Initialize()) NazaraError("Failed to initialize HardwareInfo"); - return vendorNames[s_vendorEnum+1]; + return s_vendorNames[UnderlyingCast(s_vendorEnum)]; } /*! @@ -180,15 +179,7 @@ namespace Nz bool HardwareInfo::HasCapability(ProcessorCap capability) { - #ifdef NAZARA_DEBUG - if (capability > ProcessorCap_Max) - { - NazaraError("Capability type out of enum"); - return false; - } - #endif - - return s_capabilities[capability]; + return s_capabilities[UnderlyingCast(capability)]; } /*! @@ -226,7 +217,7 @@ namespace Nz UInt32 manufacturerId[3] = {ebx, edx, ecx}; // Identification of conceptor - s_vendorEnum = ProcessorVendor_Unknown; + s_vendorEnum = ProcessorVendor::Unknown; for (const VendorString& vendorString : vendorStrings) { if (std::memcmp(manufacturerId, vendorString.vendor, 12) == 0) @@ -238,18 +229,18 @@ namespace Nz if (eax >= 1) { - // Retrieval of certain capacities of the processor (ECX et EDX, function 1) + // Retrieval of certain capacities of the processor (ECX and EDX, function 1) HardwareInfoImpl::Cpuid(1, 0, registers); - s_capabilities[ProcessorCap_AVX] = (ecx & (1U << 28)) != 0; - s_capabilities[ProcessorCap_FMA3] = (ecx & (1U << 12)) != 0; - s_capabilities[ProcessorCap_MMX] = (edx & (1U << 23)) != 0; - s_capabilities[ProcessorCap_SSE] = (edx & (1U << 25)) != 0; - s_capabilities[ProcessorCap_SSE2] = (edx & (1U << 26)) != 0; - s_capabilities[ProcessorCap_SSE3] = (ecx & (1U << 0)) != 0; - s_capabilities[ProcessorCap_SSSE3] = (ecx & (1U << 9)) != 0; - s_capabilities[ProcessorCap_SSE41] = (ecx & (1U << 19)) != 0; - s_capabilities[ProcessorCap_SSE42] = (ecx & (1U << 20)) != 0; + s_capabilities[UnderlyingCast(ProcessorCap::AVX)] = (ecx & (1U << 28)) != 0; + s_capabilities[UnderlyingCast(ProcessorCap::FMA3)] = (ecx & (1U << 12)) != 0; + s_capabilities[UnderlyingCast(ProcessorCap::MMX)] = (edx & (1U << 23)) != 0; + s_capabilities[UnderlyingCast(ProcessorCap::SSE)] = (edx & (1U << 25)) != 0; + s_capabilities[UnderlyingCast(ProcessorCap::SSE2)] = (edx & (1U << 26)) != 0; + s_capabilities[UnderlyingCast(ProcessorCap::SSE3)] = (ecx & (1U << 0)) != 0; + s_capabilities[UnderlyingCast(ProcessorCap::SSSE3)] = (ecx & (1U << 9)) != 0; + s_capabilities[UnderlyingCast(ProcessorCap::SSE41)] = (ecx & (1U << 19)) != 0; + s_capabilities[UnderlyingCast(ProcessorCap::SSE42)] = (ecx & (1U << 20)) != 0; } // Retrieval of biggest extended function handled (EAX, function 0x80000000) @@ -261,10 +252,10 @@ namespace Nz // Retrieval of extended capabilities of the processor (ECX and EDX, function 0x80000001) HardwareInfoImpl::Cpuid(0x80000001, 0, registers); - s_capabilities[ProcessorCap_x64] = (edx & (1U << 29)) != 0; // Support of 64bits, independent of the OS - s_capabilities[ProcessorCap_FMA4] = (ecx & (1U << 16)) != 0; - s_capabilities[ProcessorCap_SSE4a] = (ecx & (1U << 6)) != 0; - s_capabilities[ProcessorCap_XOP] = (ecx & (1U << 11)) != 0; + s_capabilities[UnderlyingCast(ProcessorCap::x64)] = (edx & (1U << 29)) != 0; // Support of 64bits, independent of the OS + s_capabilities[UnderlyingCast(ProcessorCap::FMA4)] = (ecx & (1U << 16)) != 0; + s_capabilities[UnderlyingCast(ProcessorCap::SSE4a)] = (ecx & (1U << 6)) != 0; + s_capabilities[UnderlyingCast(ProcessorCap::XOP)] = (ecx & (1U << 11)) != 0; if (maxSupportedExtendedFunction >= 0x80000004) { diff --git a/src/Nazara/Core/MemoryView.cpp b/src/Nazara/Core/MemoryView.cpp index 12d8c3fe5..ef9062aa6 100644 --- a/src/Nazara/Core/MemoryView.cpp +++ b/src/Nazara/Core/MemoryView.cpp @@ -25,7 +25,7 @@ namespace Nz */ MemoryView::MemoryView(void* ptr, UInt64 size) : - Stream(StreamOption_None, OpenMode_ReadWrite), + Stream(StreamOption::None, OpenMode_ReadWrite), m_ptr(static_cast(ptr)), m_pos(0), m_size(size) @@ -42,7 +42,7 @@ namespace Nz */ MemoryView::MemoryView(const void* ptr, UInt64 size) : - Stream(StreamOption_None, OpenMode_ReadOnly), + Stream(StreamOption::None, OpenMode::ReadOnly), m_ptr(static_cast(const_cast(ptr))), //< Okay, right, const_cast is bad, but this pointer is still read-only m_pos(0), m_size(size) diff --git a/src/Nazara/Core/ParameterList.cpp b/src/Nazara/Core/ParameterList.cpp index c22ee24e6..87b80822a 100644 --- a/src/Nazara/Core/ParameterList.cpp +++ b/src/Nazara/Core/ParameterList.cpp @@ -39,8 +39,8 @@ namespace Nz */ void ParameterList::Clear() { - for (auto it = m_parameters.begin(); it != m_parameters.end(); ++it) - DestroyValue(it->second); + for (auto& parameter : m_parameters) + DestroyValue(parameter.second); m_parameters.clear(); } @@ -62,7 +62,7 @@ namespace Nz { NazaraAssert(value, "Invalid pointer"); - ErrorFlags flags(ErrorFlag_Silent | ErrorFlag_ThrowExceptionDisabled); + ErrorFlags flags(ErrorMode::Silent | ErrorMode::ThrowExceptionDisabled); auto it = m_parameters.find(name); if (it == m_parameters.end()) @@ -73,15 +73,15 @@ namespace Nz switch (it->second.type) { - case ParameterType_Boolean: + case ParameterType::Boolean: *value = it->second.value.boolVal; return true; - case ParameterType_Integer: + case ParameterType::Integer: *value = (it->second.value.intVal != 0); return true; - case ParameterType_String: + case ParameterType::String: { if (it->second.value.stringVal == "1" || it->second.value.stringVal == "yes" || it->second.value.stringVal == "true") { @@ -97,11 +97,11 @@ namespace Nz break; } - case ParameterType_Color: - case ParameterType_Double: - case ParameterType_None: - case ParameterType_Pointer: - case ParameterType_Userdata: + case ParameterType::Color: + case ParameterType::Double: + case ParameterType::None: + case ParameterType::Pointer: + case ParameterType::Userdata: break; } @@ -124,7 +124,7 @@ namespace Nz { NazaraAssert(value, "Invalid pointer"); - ErrorFlags flags(ErrorFlag_Silent | ErrorFlag_ThrowExceptionDisabled); + ErrorFlags flags(ErrorMode::Silent | ErrorMode::ThrowExceptionDisabled); auto it = m_parameters.find(name); if (it == m_parameters.end()) @@ -135,17 +135,17 @@ namespace Nz switch (it->second.type) { - case ParameterType_Color: + case ParameterType::Color: *value = it->second.value.colorVal; return true; - case ParameterType_Boolean: - case ParameterType_Double: - case ParameterType_Integer: - case ParameterType_String: - case ParameterType_None: - case ParameterType_Pointer: - case ParameterType_Userdata: + case ParameterType::Boolean: + case ParameterType::Double: + case ParameterType::Integer: + case ParameterType::String: + case ParameterType::None: + case ParameterType::Pointer: + case ParameterType::Userdata: break; } @@ -170,7 +170,7 @@ namespace Nz { NazaraAssert(value, "Invalid pointer"); - ErrorFlags flags(ErrorFlag_Silent | ErrorFlag_ThrowExceptionDisabled); + ErrorFlags flags(ErrorMode::Silent | ErrorMode::ThrowExceptionDisabled); auto it = m_parameters.find(name); if (it == m_parameters.end()) @@ -181,15 +181,15 @@ namespace Nz switch (it->second.type) { - case ParameterType_Double: + case ParameterType::Double: *value = it->second.value.doubleVal; return true; - case ParameterType_Integer: + case ParameterType::Integer: *value = static_cast(it->second.value.intVal); return true; - case ParameterType_String: + case ParameterType::String: { const std::string& str = it->second.value.stringVal; @@ -206,11 +206,11 @@ namespace Nz return true; } - case ParameterType_Boolean: - case ParameterType_Color: - case ParameterType_None: - case ParameterType_Pointer: - case ParameterType_Userdata: + case ParameterType::Boolean: + case ParameterType::Color: + case ParameterType::None: + case ParameterType::Pointer: + case ParameterType::Userdata: break; } @@ -236,7 +236,7 @@ namespace Nz { NazaraAssert(value, "Invalid pointer"); - ErrorFlags flags(ErrorFlag_Silent | ErrorFlag_ThrowExceptionDisabled); + ErrorFlags flags(ErrorMode::Silent | ErrorMode::ThrowExceptionDisabled); auto it = m_parameters.find(name); if (it == m_parameters.end()) @@ -247,19 +247,19 @@ namespace Nz switch (it->second.type) { - case ParameterType_Boolean: + case ParameterType::Boolean: *value = (it->second.value.boolVal) ? 1 : 0; return true; - case ParameterType_Double: + case ParameterType::Double: *value = static_cast(it->second.value.doubleVal); return true; - case ParameterType_Integer: + case ParameterType::Integer: *value = it->second.value.intVal; return true; - case ParameterType_String: + case ParameterType::String: { const std::string& str = it->second.value.stringVal; @@ -276,10 +276,10 @@ namespace Nz return true; } - case ParameterType_Color: - case ParameterType_None: - case ParameterType_Pointer: - case ParameterType_Userdata: + case ParameterType::Color: + case ParameterType::None: + case ParameterType::Pointer: + case ParameterType::Userdata: break; } @@ -325,7 +325,7 @@ namespace Nz { NazaraAssert(value, "Invalid pointer"); - ErrorFlags flags(ErrorFlag_Silent | ErrorFlag_ThrowExceptionDisabled); + ErrorFlags flags(ErrorMode::Silent | ErrorMode::ThrowExceptionDisabled); auto it = m_parameters.find(name); if (it == m_parameters.end()) @@ -336,20 +336,20 @@ namespace Nz switch (it->second.type) { - case ParameterType_Pointer: + case ParameterType::Pointer: *value = it->second.value.ptrVal; return true; - case ParameterType_Userdata: + case ParameterType::Userdata: *value = it->second.value.userdataVal->ptr; return true; - case ParameterType_Boolean: - case ParameterType_Color: - case ParameterType_Double: - case ParameterType_Integer: - case ParameterType_None: - case ParameterType_String: + case ParameterType::Boolean: + case ParameterType::Color: + case ParameterType::Double: + case ParameterType::Integer: + case ParameterType::None: + case ParameterType::String: break; } @@ -379,7 +379,7 @@ namespace Nz { NazaraAssert(value, "Invalid pointer"); - ErrorFlags flags(ErrorFlag_Silent | ErrorFlag_ThrowExceptionDisabled); + ErrorFlags flags(ErrorMode::Silent | ErrorMode::ThrowExceptionDisabled); auto it = m_parameters.find(name); if (it == m_parameters.end()) @@ -390,35 +390,35 @@ namespace Nz switch (it->second.type) { - case ParameterType_Boolean: + case ParameterType::Boolean: *value = (it->second.value.boolVal) ? "true" : "false"; return true; - case ParameterType_Color: + case ParameterType::Color: *value = it->second.value.colorVal.ToString(); return true; - case ParameterType_Double: + case ParameterType::Double: *value = std::to_string(it->second.value.doubleVal); return true; - case ParameterType_Integer: + case ParameterType::Integer: *value = std::to_string(it->second.value.intVal); return true; - case ParameterType_String: + case ParameterType::String: *value = it->second.value.stringVal; return true; - case ParameterType_Pointer: + case ParameterType::Pointer: *value = PointerToString(it->second.value.ptrVal); return true; - case ParameterType_Userdata: + case ParameterType::Userdata: *value = PointerToString(it->second.value.userdataVal->ptr); return true; - case ParameterType_None: + case ParameterType::None: *value = std::string(); return true; } @@ -444,7 +444,7 @@ namespace Nz { NazaraAssert(value, "Invalid pointer"); - ErrorFlags flags(ErrorFlag_Silent | ErrorFlag_ThrowExceptionDisabled); + ErrorFlags flags(ErrorMode::Silent | ErrorMode::ThrowExceptionDisabled); auto it = m_parameters.find(name); if (it == m_parameters.end()) @@ -455,7 +455,7 @@ namespace Nz const auto& parameter = it->second; - if (parameter.type == ParameterType_Userdata) + if (parameter.type == ParameterType::Userdata) { *value = parameter.value.userdataVal->ptr; return true; @@ -506,7 +506,7 @@ namespace Nz void ParameterList::SetParameter(const std::string& name) { Parameter& parameter = CreateValue(name); - parameter.type = ParameterType_None; + parameter.type = ParameterType::None; } /*! @@ -520,7 +520,7 @@ namespace Nz void ParameterList::SetParameter(const std::string& name, const Color& value) { Parameter& parameter = CreateValue(name); - parameter.type = ParameterType_Color; + parameter.type = ParameterType::Color; PlacementNew(¶meter.value.colorVal, value); } @@ -536,7 +536,7 @@ namespace Nz void ParameterList::SetParameter(const std::string& name, const std::string& value) { Parameter& parameter = CreateValue(name); - parameter.type = ParameterType_String; + parameter.type = ParameterType::String; PlacementNew(¶meter.value.stringVal, value); } @@ -552,7 +552,7 @@ namespace Nz void ParameterList::SetParameter(const std::string& name, const char* value) { Parameter& parameter = CreateValue(name); - parameter.type = ParameterType_String; + parameter.type = ParameterType::String; PlacementNew(¶meter.value.stringVal, value); } @@ -568,7 +568,7 @@ namespace Nz void ParameterList::SetParameter(const std::string& name, bool value) { Parameter& parameter = CreateValue(name); - parameter.type = ParameterType_Boolean; + parameter.type = ParameterType::Boolean; parameter.value.boolVal = value; } @@ -583,7 +583,7 @@ namespace Nz void ParameterList::SetParameter(const std::string& name, double value) { Parameter& parameter = CreateValue(name); - parameter.type = ParameterType_Double; + parameter.type = ParameterType::Double; parameter.value.doubleVal = value; } @@ -598,7 +598,7 @@ namespace Nz void ParameterList::SetParameter(const std::string& name, long long value) { Parameter& parameter = CreateValue(name); - parameter.type = ParameterType_Integer; + parameter.type = ParameterType::Integer; parameter.value.intVal = value; } @@ -616,7 +616,7 @@ namespace Nz void ParameterList::SetParameter(const std::string& name, void* value) { Parameter& parameter = CreateValue(name); - parameter.type = ParameterType_Pointer; + parameter.type = ParameterType::Pointer; parameter.value.ptrVal = value; } @@ -637,28 +637,28 @@ namespace Nz ss << it->first << ": "; switch (it->second.type) { - case ParameterType_Boolean: + case ParameterType::Boolean: ss << "Boolean(" << parameter.value.boolVal << ")"; break; - case ParameterType_Color: + case ParameterType::Color: ss << "Color(" << parameter.value.colorVal << ")"; break; - case ParameterType_Double: + case ParameterType::Double: ss << "Double(" << parameter.value.doubleVal << ")"; break; - case ParameterType_Integer: + case ParameterType::Integer: ss << "Integer(" << parameter.value.intVal << ")"; break; - case ParameterType_String: + case ParameterType::String: ss << "std::string(" << parameter.value.stringVal << ")"; break; - case ParameterType_Pointer: + case ParameterType::Pointer: ss << "Pointer(" << parameter.value.ptrVal << ")"; break; - case ParameterType_Userdata: + case ParameterType::Userdata: ss << "Userdata(" << parameter.value.userdataVal->ptr << ")"; break; - case ParameterType_None: + case ParameterType::None: ss << "None"; break; } @@ -686,7 +686,7 @@ namespace Nz void ParameterList::SetParameter(const std::string& name, void* value, Destructor destructor) { Parameter& parameter = CreateValue(name); - parameter.type = ParameterType_Userdata; + parameter.type = ParameterType::Userdata; parameter.value.userdataVal = new Parameter::UserdataValue(destructor, value); } @@ -706,28 +706,28 @@ namespace Nz switch (it->second.type) { - case ParameterType_Boolean: - case ParameterType_Color: - case ParameterType_Double: - case ParameterType_Integer: - case ParameterType_Pointer: + case ParameterType::Boolean: + case ParameterType::Color: + case ParameterType::Double: + case ParameterType::Integer: + case ParameterType::Pointer: std::memcpy(¶meter, &it->second, sizeof(Parameter)); break; - case ParameterType_String: - parameter.type = ParameterType_String; + case ParameterType::String: + parameter.type = ParameterType::String; PlacementNew(¶meter.value.stringVal, it->second.value.stringVal); break; - case ParameterType_Userdata: - parameter.type = ParameterType_Userdata; + case ParameterType::Userdata: + parameter.type = ParameterType::Userdata; parameter.value.userdataVal = it->second.value.userdataVal; ++(parameter.value.userdataVal->counter); break; - case ParameterType_None: - parameter.type = ParameterType_None; + case ParameterType::None: + parameter.type = ParameterType::None; break; } } @@ -762,11 +762,11 @@ namespace Nz { switch (parameter.type) { - case ParameterType_String: + case ParameterType::String: PlacementDestroy(¶meter.value.stringVal); break; - case ParameterType_Userdata: + case ParameterType::Userdata: { Parameter::UserdataValue* userdata = parameter.value.userdataVal; if (--userdata->counter == 0) @@ -777,12 +777,12 @@ namespace Nz break; } - case ParameterType_Boolean: - case ParameterType_Color: - case ParameterType_Double: - case ParameterType_Integer: - case ParameterType_None: - case ParameterType_Pointer: + case ParameterType::Boolean: + case ParameterType::Color: + case ParameterType::Double: + case ParameterType::Integer: + case ParameterType::None: + case ParameterType::Pointer: break; } } diff --git a/src/Nazara/Core/PluginManager.cpp b/src/Nazara/Core/PluginManager.cpp index ffbbeda67..44d14d4c7 100644 --- a/src/Nazara/Core/PluginManager.cpp +++ b/src/Nazara/Core/PluginManager.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include #include @@ -15,9 +16,9 @@ namespace Nz using PluginLoad = int (*)(); using PluginUnload = void (*)(); - std::filesystem::path s_pluginFiles[] = + const char* s_pluginFiles[] = { - "PluginAssimp", // Plugin_Assimp + "PluginAssimp", // Plugin::Assimp }; } @@ -77,7 +78,7 @@ namespace Nz bool PluginManager::Mount(Plugin plugin) { - std::filesystem::path pluginName = s_pluginFiles[plugin]; + std::filesystem::path pluginName = s_pluginFiles[UnderlyingCast(plugin)]; #ifdef NAZARA_DEBUG std::filesystem::path debugPath = pluginName; @@ -195,7 +196,7 @@ namespace Nz void PluginManager::Unmount(Plugin plugin) { - Unmount(s_pluginFiles[plugin]); + Unmount(s_pluginFiles[UnderlyingCast(plugin)]); } /*! diff --git a/src/Nazara/Core/Posix/FileImpl.cpp b/src/Nazara/Core/Posix/FileImpl.cpp index b64370fbb..f994475c6 100644 --- a/src/Nazara/Core/Posix/FileImpl.cpp +++ b/src/Nazara/Core/Posix/FileImpl.cpp @@ -3,11 +3,12 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include #include -#include #include +#include #include #include @@ -61,20 +62,20 @@ namespace Nz if ((mode & OpenMode_ReadWrite) == OpenMode_ReadWrite) flags = O_CREAT | O_RDWR; - else if ((mode & OpenMode_ReadOnly) == OpenMode_ReadOnly) + else if ((mode & OpenMode::ReadOnly) == OpenMode::ReadOnly) flags = O_RDONLY; - else if ((mode & OpenMode_WriteOnly) == OpenMode_WriteOnly) + else if ((mode & OpenMode::WriteOnly) == OpenMode::WriteOnly) flags = O_CREAT | O_WRONLY; else return false; - if (mode & OpenMode_Append) + if (mode & OpenMode::Append) flags |= O_APPEND; - if (mode & OpenMode_MustExist) + if (mode & OpenMode::MustExist) flags &= ~O_CREAT; - if (mode & OpenMode_Truncate) + if (mode & OpenMode::Truncate) flags |= O_TRUNC; int fileDescriptor = Open_def(filePath.generic_u8string().data(), flags, permissions); @@ -111,7 +112,7 @@ namespace Nz return false; } - if (mode & OpenMode_Lock) + if (mode & OpenMode::Lock) { initialize_flock(lock); @@ -147,20 +148,20 @@ namespace Nz int moveMethod; switch (pos) { - case CursorPosition_AtBegin: + case CursorPosition::AtBegin: moveMethod = SEEK_SET; break; - case CursorPosition_AtCurrent: + case CursorPosition::AtCurrent: moveMethod = SEEK_CUR; break; - case CursorPosition_AtEnd: + case CursorPosition::AtEnd: moveMethod = SEEK_END; break; default: - NazaraInternalError("Cursor position not handled (0x" + NumberToString(pos, 16) + ')'); + NazaraInternalError("Cursor position not handled (0x" + NumberToString(UnderlyingCast(pos), 16) + ')'); return false; } diff --git a/src/Nazara/Core/StdLogger.cpp b/src/Nazara/Core/StdLogger.cpp index 92602393b..8e7225cb6 100644 --- a/src/Nazara/Core/StdLogger.cpp +++ b/src/Nazara/Core/StdLogger.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include @@ -11,13 +12,13 @@ namespace Nz namespace { const char* errorType[] = { - "Assert failed", // ErrorType_AssertFailed - "Internal error", // ErrorType_Internal - "Error", // ErrorType_Normal - "Warning" // ErrorType_Warning + "Assert failed", // ErrorType::AssertFailed + "Internal error", // ErrorType::Internal + "Error", // ErrorType::Normal + "Warning" // ErrorType::Warning }; - static_assert(sizeof(errorType) / sizeof(const char*) == ErrorType_Max + 1, "Error type array is incomplete"); + static_assert(sizeof(errorType) / sizeof(const char*) == ErrorTypeCount, "Error type array is incomplete"); } /*! @@ -80,7 +81,7 @@ namespace Nz void StdLogger::WriteError(ErrorType type, const std::string_view& error, unsigned int line, const char* file, const char* function) { - fprintf(stderr, "%s: ", errorType[type]); + fprintf(stderr, "%s: ", errorType[UnderlyingCast(type)]); fwrite(error.data(), sizeof(char), error.size(), stdout); if (line != 0 && file && function) diff --git a/src/Nazara/Core/Stream.cpp b/src/Nazara/Core/Stream.cpp index 9abc0a14a..1b4a6030b 100644 --- a/src/Nazara/Core/Stream.cpp +++ b/src/Nazara/Core/Stream.cpp @@ -78,7 +78,7 @@ namespace Nz std::ptrdiff_t pos = ptr - buffer; if (ptr != buffer) { - if (m_streamOptions & StreamOption_Text && buffer[pos - 1] == '\r') + if (m_streamOptions & StreamOption::Text && buffer[pos - 1] == '\r') line.append(buffer, pos - 1); else line.append(buffer, pos); @@ -92,7 +92,7 @@ namespace Nz else { std::size_t length = readSize; - if (m_streamOptions & StreamOption_Text && buffer[length - 1] == '\r') + if (m_streamOptions & StreamOption::Text && buffer[length - 1] == '\r') { if (!SetCursorPos(GetCursorPos() - 1)) NazaraWarning("Failed to reset cursor pos"); @@ -112,7 +112,7 @@ namespace Nz std::size_t pos = line.find('\n'); if (pos <= readSize) // False only if the character is not available (npos being the biggest integer) { - if (m_streamOptions & StreamOption_Text && pos > 0 && line[pos - 1] == '\r') + if (m_streamOptions & StreamOption::Text && pos > 0 && line[pos - 1] == '\r') line.resize(pos); else line.resize(pos + 1); @@ -149,7 +149,7 @@ namespace Nz bool Stream::Write(const std::string_view& string) { - if (m_streamOptions & StreamOption_Text) + if (m_streamOptions & StreamOption::Text) { #if defined(NAZARA_PLATFORM_WINDOWS) std::string temp(string); diff --git a/src/Nazara/Core/UnicodeData.hpp b/src/Nazara/Core/UnicodeData.hpp index 7e8effc89..4486d4891 100644 --- a/src/Nazara/Core/UnicodeData.hpp +++ b/src/Nazara/Core/UnicodeData.hpp @@ -1,4 +1,4 @@ -UnicodeCharacter unicodeCharacters[32262] = { +UnicodeCharacter unicodeCharacters[33763] = { {0, Unicode::Category_Other_Control, Unicode::Direction_Boundary_Neutral}, {1, Unicode::Category_Other_Control, Unicode::Direction_Boundary_Neutral}, {2, Unicode::Category_Other_Control, Unicode::Direction_Boundary_Neutral}, @@ -2119,6 +2119,16 @@ UnicodeCharacter unicodeCharacters[32262] = { {2235, Unicode::Category_Letter_Other, Unicode::Direction_Arabic_Letter}, {2236, Unicode::Category_Letter_Other, Unicode::Direction_Arabic_Letter}, {2237, Unicode::Category_Letter_Other, Unicode::Direction_Arabic_Letter}, + {2238, Unicode::Category_Letter_Other, Unicode::Direction_Arabic_Letter}, + {2239, Unicode::Category_Letter_Other, Unicode::Direction_Arabic_Letter}, + {2240, Unicode::Category_Letter_Other, Unicode::Direction_Arabic_Letter}, + {2241, Unicode::Category_Letter_Other, Unicode::Direction_Arabic_Letter}, + {2242, Unicode::Category_Letter_Other, Unicode::Direction_Arabic_Letter}, + {2243, Unicode::Category_Letter_Other, Unicode::Direction_Arabic_Letter}, + {2244, Unicode::Category_Letter_Other, Unicode::Direction_Arabic_Letter}, + {2245, Unicode::Category_Letter_Other, Unicode::Direction_Arabic_Letter}, + {2246, Unicode::Category_Letter_Other, Unicode::Direction_Arabic_Letter}, + {2247, Unicode::Category_Letter_Other, Unicode::Direction_Arabic_Letter}, {2259, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {2260, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {2261, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, @@ -2622,6 +2632,7 @@ UnicodeCharacter unicodeCharacters[32262] = { {2891, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, {2892, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, {2893, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {2901, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {2902, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {2903, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, {2908, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, @@ -2810,6 +2821,7 @@ UnicodeCharacter unicodeCharacters[32262] = { {3181, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, {3182, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, {3183, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {3191, Unicode::Category_Punctuation_Other, Unicode::Direction_Left_To_Right}, {3192, Unicode::Category_Number_Other, Unicode::Direction_Other_Neutral}, {3193, Unicode::Category_Number_Other, Unicode::Direction_Other_Neutral}, {3194, Unicode::Category_Number_Other, Unicode::Direction_Other_Neutral}, @@ -2911,6 +2923,7 @@ UnicodeCharacter unicodeCharacters[32262] = { {3329, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {3330, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, {3331, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {3332, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3333, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3334, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3335, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, @@ -3024,6 +3037,7 @@ UnicodeCharacter unicodeCharacters[32262] = { {3453, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3454, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3455, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {3457, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {3458, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, {3459, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, {3461, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, @@ -3204,14 +3218,24 @@ UnicodeCharacter unicodeCharacters[32262] = { {3713, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3714, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3716, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {3718, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3719, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3720, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {3721, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3722, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {3724, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3725, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {3726, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {3727, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {3728, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {3729, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {3730, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {3731, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3732, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3733, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3734, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3735, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {3736, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3737, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3738, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3739, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, @@ -3219,13 +3243,17 @@ UnicodeCharacter unicodeCharacters[32262] = { {3741, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3742, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3743, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {3744, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3745, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3746, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3747, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3749, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3751, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {3752, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {3753, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3754, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3755, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {3756, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3757, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3758, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {3759, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, @@ -3239,6 +3267,7 @@ UnicodeCharacter unicodeCharacters[32262] = { {3767, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {3768, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {3769, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {3770, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {3771, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {3772, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {3773, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, @@ -5080,7 +5109,7 @@ UnicodeCharacter unicodeCharacters[32262] = { {5738, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {5739, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {5740, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, - {5741, Unicode::Category_Punctuation_Other, Unicode::Direction_Left_To_Right}, + {5741, Unicode::Category_Symbol_Other, Unicode::Direction_Left_To_Right}, {5742, Unicode::Category_Punctuation_Other, Unicode::Direction_Left_To_Right}, {5743, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {5744, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, @@ -6029,6 +6058,8 @@ UnicodeCharacter unicodeCharacters[32262] = { {6844, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {6845, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {6846, Unicode::Category_Mark_Enclosing, Unicode::Direction_Nonspacing_Mark}, + {6847, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {6848, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {6912, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {6913, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {6914, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, @@ -6489,14 +6520,15 @@ UnicodeCharacter unicodeCharacters[32262] = { {7407, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {7408, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {7409, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, - {7410, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, - {7411, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {7410, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {7411, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {7412, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {7413, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {7414, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {7415, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, {7416, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {7417, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {7418, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {7424, Unicode::Category_Letter_Lowercase, Unicode::Direction_Left_To_Right}, {7425, Unicode::Category_Letter_Lowercase, Unicode::Direction_Left_To_Right}, {7426, Unicode::Category_Letter_Lowercase, Unicode::Direction_Left_To_Right}, @@ -10117,6 +10149,7 @@ UnicodeCharacter unicodeCharacters[32262] = { {11155, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {11156, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {11157, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {11159, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {11160, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {11161, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {11162, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, @@ -10166,6 +10199,7 @@ UnicodeCharacter unicodeCharacters[32262] = { {11206, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {11207, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {11208, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {11209, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {11210, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {11211, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {11212, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, @@ -10219,6 +10253,7 @@ UnicodeCharacter unicodeCharacters[32262] = { {11260, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {11261, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {11262, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {11263, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {11264, Unicode::Category_Letter_Uppercase, Unicode::Direction_Left_To_Right}, {11265, Unicode::Category_Letter_Uppercase, Unicode::Direction_Left_To_Right}, {11266, Unicode::Category_Letter_Uppercase, Unicode::Direction_Left_To_Right}, @@ -10757,6 +10792,10 @@ UnicodeCharacter unicodeCharacters[32262] = { {11852, Unicode::Category_Punctuation_Other, Unicode::Direction_Other_Neutral}, {11853, Unicode::Category_Punctuation_Other, Unicode::Direction_Other_Neutral}, {11854, Unicode::Category_Punctuation_Other, Unicode::Direction_Other_Neutral}, + {11855, Unicode::Category_Punctuation_Other, Unicode::Direction_Other_Neutral}, + {11856, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {11857, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {11858, Unicode::Category_Punctuation_Other, Unicode::Direction_Other_Neutral}, {11904, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {11905, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {11906, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, @@ -11531,6 +11570,11 @@ UnicodeCharacter unicodeCharacters[32262] = { {12728, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {12729, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {12730, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {12731, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {12732, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {12733, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {12734, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {12735, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {12736, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {12737, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {12738, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, @@ -11837,6 +11881,7 @@ UnicodeCharacter unicodeCharacters[32262] = { {13052, Unicode::Category_Symbol_Other, Unicode::Direction_Left_To_Right}, {13053, Unicode::Category_Symbol_Other, Unicode::Direction_Left_To_Right}, {13054, Unicode::Category_Symbol_Other, Unicode::Direction_Left_To_Right}, + {13055, Unicode::Category_Symbol_Other, Unicode::Direction_Left_To_Right}, {13056, Unicode::Category_Symbol_Other, Unicode::Direction_Left_To_Right}, {13057, Unicode::Category_Symbol_Other, Unicode::Direction_Left_To_Right}, {13058, Unicode::Category_Symbol_Other, Unicode::Direction_Left_To_Right}, @@ -14095,6 +14140,23 @@ UnicodeCharacter unicodeCharacters[32262] = { {42935, Unicode::Category_Letter_Lowercase, Unicode::Direction_Left_To_Right}, {42936, Unicode::Category_Letter_Uppercase, Unicode::Direction_Left_To_Right}, {42937, Unicode::Category_Letter_Lowercase, Unicode::Direction_Left_To_Right}, + {42938, Unicode::Category_Letter_Uppercase, Unicode::Direction_Left_To_Right}, + {42939, Unicode::Category_Letter_Lowercase, Unicode::Direction_Left_To_Right}, + {42940, Unicode::Category_Letter_Uppercase, Unicode::Direction_Left_To_Right}, + {42941, Unicode::Category_Letter_Lowercase, Unicode::Direction_Left_To_Right}, + {42942, Unicode::Category_Letter_Uppercase, Unicode::Direction_Left_To_Right}, + {42943, Unicode::Category_Letter_Lowercase, Unicode::Direction_Left_To_Right}, + {42946, Unicode::Category_Letter_Uppercase, Unicode::Direction_Left_To_Right}, + {42947, Unicode::Category_Letter_Lowercase, Unicode::Direction_Left_To_Right}, + {42948, Unicode::Category_Letter_Uppercase, Unicode::Direction_Left_To_Right}, + {42949, Unicode::Category_Letter_Uppercase, Unicode::Direction_Left_To_Right}, + {42950, Unicode::Category_Letter_Uppercase, Unicode::Direction_Left_To_Right}, + {42951, Unicode::Category_Letter_Uppercase, Unicode::Direction_Left_To_Right}, + {42952, Unicode::Category_Letter_Lowercase, Unicode::Direction_Left_To_Right}, + {42953, Unicode::Category_Letter_Uppercase, Unicode::Direction_Left_To_Right}, + {42954, Unicode::Category_Letter_Lowercase, Unicode::Direction_Left_To_Right}, + {42997, Unicode::Category_Letter_Uppercase, Unicode::Direction_Left_To_Right}, + {42998, Unicode::Category_Letter_Lowercase, Unicode::Direction_Left_To_Right}, {42999, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {43000, Unicode::Category_Letter_Modifier, Unicode::Direction_Left_To_Right}, {43001, Unicode::Category_Letter_Modifier, Unicode::Direction_Left_To_Right}, @@ -14148,6 +14210,7 @@ UnicodeCharacter unicodeCharacters[32262] = { {43049, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {43050, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {43051, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {43052, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {43056, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, {43057, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, {43058, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, @@ -14503,7 +14566,7 @@ UnicodeCharacter unicodeCharacters[32262] = { {43450, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, {43451, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, {43452, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, - {43453, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {43453, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {43454, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, {43455, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, {43456, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, @@ -14860,6 +14923,12 @@ UnicodeCharacter unicodeCharacters[32262] = { {43875, Unicode::Category_Letter_Lowercase, Unicode::Direction_Left_To_Right}, {43876, Unicode::Category_Letter_Lowercase, Unicode::Direction_Left_To_Right}, {43877, Unicode::Category_Letter_Lowercase, Unicode::Direction_Left_To_Right}, + {43878, Unicode::Category_Letter_Lowercase, Unicode::Direction_Left_To_Right}, + {43879, Unicode::Category_Letter_Lowercase, Unicode::Direction_Left_To_Right}, + {43880, Unicode::Category_Letter_Lowercase, Unicode::Direction_Left_To_Right}, + {43881, Unicode::Category_Letter_Modifier, Unicode::Direction_Left_To_Right}, + {43882, Unicode::Category_Symbol_Modifier, Unicode::Direction_Other_Neutral}, + {43883, Unicode::Category_Symbol_Modifier, Unicode::Direction_Other_Neutral}, {43888, Unicode::Category_Letter_Lowercase, Unicode::Direction_Left_To_Right}, {43889, Unicode::Category_Letter_Lowercase, Unicode::Direction_Left_To_Right}, {43890, Unicode::Category_Letter_Lowercase, Unicode::Direction_Left_To_Right}, @@ -17039,6 +17108,7 @@ UnicodeCharacter unicodeCharacters[32262] = { {65945, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {65946, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {65947, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {65948, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {65952, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {66000, Unicode::Category_Symbol_Other, Unicode::Direction_Left_To_Right}, {66001, Unicode::Category_Symbol_Other, Unicode::Direction_Left_To_Right}, @@ -19010,6 +19080,53 @@ UnicodeCharacter unicodeCharacters[32262] = { {69244, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Number}, {69245, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Number}, {69246, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Number}, + {69248, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69249, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69250, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69251, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69252, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69253, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69254, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69255, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69256, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69257, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69258, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69259, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69260, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69261, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69262, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69263, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69264, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69265, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69266, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69267, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69268, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69269, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69270, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69271, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69272, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69273, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69274, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69275, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69276, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69277, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69278, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69279, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69280, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69281, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69282, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69283, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69284, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69285, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69286, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69287, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69288, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69289, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69291, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {69292, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {69293, Unicode::Category_Punctuation_Dash, Unicode::Direction_Right_To_Left}, + {69296, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69297, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, {69376, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, {69377, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, {69378, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, @@ -19092,6 +19209,57 @@ UnicodeCharacter unicodeCharacters[32262] = { {69463, Unicode::Category_Punctuation_Other, Unicode::Direction_Arabic_Letter}, {69464, Unicode::Category_Punctuation_Other, Unicode::Direction_Arabic_Letter}, {69465, Unicode::Category_Punctuation_Other, Unicode::Direction_Arabic_Letter}, + {69552, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69553, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69554, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69555, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69556, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69557, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69558, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69559, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69560, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69561, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69562, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69563, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69564, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69565, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69566, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69567, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69568, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69569, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69570, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69571, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69572, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69573, Unicode::Category_Number_Other, Unicode::Direction_Right_To_Left}, + {69574, Unicode::Category_Number_Other, Unicode::Direction_Right_To_Left}, + {69575, Unicode::Category_Number_Other, Unicode::Direction_Right_To_Left}, + {69576, Unicode::Category_Number_Other, Unicode::Direction_Right_To_Left}, + {69577, Unicode::Category_Number_Other, Unicode::Direction_Right_To_Left}, + {69578, Unicode::Category_Number_Other, Unicode::Direction_Right_To_Left}, + {69579, Unicode::Category_Number_Other, Unicode::Direction_Right_To_Left}, + {69600, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69601, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69602, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69603, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69604, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69605, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69606, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69607, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69608, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69609, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69610, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69611, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69612, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69613, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69614, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69615, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69616, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69617, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69618, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69619, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69620, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69621, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, + {69622, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, {69632, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, {69633, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {69634, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, @@ -19373,6 +19541,7 @@ UnicodeCharacter unicodeCharacters[32262] = { {69956, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {69957, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, {69958, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {69959, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {69968, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {69969, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {69970, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, @@ -19490,6 +19659,8 @@ UnicodeCharacter unicodeCharacters[32262] = { {70091, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {70092, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {70093, Unicode::Category_Punctuation_Other, Unicode::Direction_Left_To_Right}, + {70094, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {70095, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {70096, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, {70097, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, {70098, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, @@ -19871,9 +20042,13 @@ UnicodeCharacter unicodeCharacters[32262] = { {70743, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, {70744, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, {70745, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {70746, Unicode::Category_Punctuation_Other, Unicode::Direction_Left_To_Right}, {70747, Unicode::Category_Punctuation_Other, Unicode::Direction_Left_To_Right}, {70749, Unicode::Category_Punctuation_Other, Unicode::Direction_Left_To_Right}, {70750, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {70751, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {70752, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {70753, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {70784, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {70785, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {70786, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, @@ -20196,6 +20371,7 @@ UnicodeCharacter unicodeCharacters[32262] = { {71349, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {71350, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, {71351, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {71352, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {71360, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, {71361, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, {71362, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, @@ -20408,6 +20584,143 @@ UnicodeCharacter unicodeCharacters[32262] = { {71921, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, {71922, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, {71935, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71936, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71937, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71938, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71939, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71940, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71941, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71942, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71945, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71948, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71949, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71950, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71951, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71952, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71953, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71954, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71955, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71957, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71958, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71960, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71961, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71962, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71963, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71964, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71965, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71966, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71967, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71968, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71969, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71970, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71971, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71972, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71973, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71974, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71975, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71976, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71977, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71978, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71979, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71980, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71981, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71982, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71983, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {71984, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {71985, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {71986, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {71987, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {71988, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {71989, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {71991, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {71992, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {71995, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {71996, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {71997, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {71998, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {71999, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72000, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {72001, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72002, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {72003, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {72004, Unicode::Category_Punctuation_Other, Unicode::Direction_Left_To_Right}, + {72005, Unicode::Category_Punctuation_Other, Unicode::Direction_Left_To_Right}, + {72006, Unicode::Category_Punctuation_Other, Unicode::Direction_Left_To_Right}, + {72016, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {72017, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {72018, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {72019, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {72020, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {72021, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {72022, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {72023, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {72024, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {72025, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {72096, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72097, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72098, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72099, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72100, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72101, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72102, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72103, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72106, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72107, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72108, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72109, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72110, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72111, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72112, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72113, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72114, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72115, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72116, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72117, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72118, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72119, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72120, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72121, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72122, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72123, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72124, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72125, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72126, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72127, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72128, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72129, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72130, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72131, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72132, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72133, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72134, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72135, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72136, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72137, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72138, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72139, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72140, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72141, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72142, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72143, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72144, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72145, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {72146, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {72147, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {72148, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {72149, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {72150, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {72151, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {72154, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {72155, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {72156, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {72157, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {72158, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {72159, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {72160, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {72161, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72162, Unicode::Category_Punctuation_Other, Unicode::Direction_Left_To_Right}, + {72163, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72164, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, {72192, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {72193, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {72194, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, @@ -20532,6 +20845,8 @@ UnicodeCharacter unicodeCharacters[32262] = { {72321, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {72322, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {72323, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72324, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {72325, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {72326, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {72327, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {72328, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, @@ -20946,6 +21261,58 @@ UnicodeCharacter unicodeCharacters[32262] = { {73462, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, {73463, Unicode::Category_Punctuation_Other, Unicode::Direction_Left_To_Right}, {73464, Unicode::Category_Punctuation_Other, Unicode::Direction_Left_To_Right}, + {73648, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {73664, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, + {73665, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, + {73666, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, + {73667, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, + {73668, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, + {73669, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, + {73670, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, + {73671, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, + {73672, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, + {73673, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, + {73674, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, + {73675, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, + {73676, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, + {73677, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, + {73678, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, + {73679, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, + {73680, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, + {73681, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, + {73682, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, + {73683, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, + {73684, Unicode::Category_Number_Other, Unicode::Direction_Left_To_Right}, + {73685, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {73686, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {73687, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {73688, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {73689, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {73690, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {73691, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {73692, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {73693, Unicode::Category_Symbol_Currency, Unicode::Direction_European_Terminator}, + {73694, Unicode::Category_Symbol_Currency, Unicode::Direction_European_Terminator}, + {73695, Unicode::Category_Symbol_Currency, Unicode::Direction_European_Terminator}, + {73696, Unicode::Category_Symbol_Currency, Unicode::Direction_European_Terminator}, + {73697, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {73698, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {73699, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {73700, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {73701, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {73702, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {73703, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {73704, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {73705, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {73706, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {73707, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {73708, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {73709, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {73710, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {73711, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {73712, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {73713, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {73727, Unicode::Category_Punctuation_Other, Unicode::Direction_Left_To_Right}, {73728, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {73729, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {73730, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, @@ -23251,6 +23618,15 @@ UnicodeCharacter unicodeCharacters[32262] = { {78892, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {78893, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {78894, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {78896, Unicode::Category_Other_Format, Unicode::Direction_Left_To_Right}, + {78897, Unicode::Category_Other_Format, Unicode::Direction_Left_To_Right}, + {78898, Unicode::Category_Other_Format, Unicode::Direction_Left_To_Right}, + {78899, Unicode::Category_Other_Format, Unicode::Direction_Left_To_Right}, + {78900, Unicode::Category_Other_Format, Unicode::Direction_Left_To_Right}, + {78901, Unicode::Category_Other_Format, Unicode::Direction_Left_To_Right}, + {78902, Unicode::Category_Other_Format, Unicode::Direction_Left_To_Right}, + {78903, Unicode::Category_Other_Format, Unicode::Direction_Left_To_Right}, + {78904, Unicode::Category_Other_Format, Unicode::Direction_Left_To_Right}, {82944, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {82945, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {82946, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, @@ -24769,6 +25145,13 @@ UnicodeCharacter unicodeCharacters[32262] = { {94018, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {94019, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {94020, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {94021, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {94022, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {94023, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {94024, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {94025, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {94026, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {94031, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {94032, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {94033, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, {94034, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, @@ -24816,6 +25199,15 @@ UnicodeCharacter unicodeCharacters[32262] = { {94076, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, {94077, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, {94078, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {94079, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {94080, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {94081, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {94082, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {94083, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {94084, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {94085, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {94086, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {94087, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, {94095, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {94096, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {94097, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, @@ -24835,6 +25227,11 @@ UnicodeCharacter unicodeCharacters[32262] = { {94111, Unicode::Category_Letter_Modifier, Unicode::Direction_Left_To_Right}, {94176, Unicode::Category_Letter_Modifier, Unicode::Direction_Left_To_Right}, {94177, Unicode::Category_Letter_Modifier, Unicode::Direction_Left_To_Right}, + {94178, Unicode::Category_Punctuation_Other, Unicode::Direction_Other_Neutral}, + {94179, Unicode::Category_Letter_Modifier, Unicode::Direction_Left_To_Right}, + {94180, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {94192, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, + {94193, Unicode::Category_Mark_SpacingCombining, Unicode::Direction_Left_To_Right}, {100352, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {100353, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {100354, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, @@ -25590,6 +25987,489 @@ UnicodeCharacter unicodeCharacters[32262] = { {101104, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {101105, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {101106, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101107, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101108, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101109, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101110, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101111, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101112, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101113, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101114, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101115, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101116, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101117, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101118, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101119, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101120, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101121, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101122, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101123, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101124, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101125, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101126, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101127, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101128, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101129, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101130, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101131, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101132, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101133, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101134, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101135, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101136, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101137, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101138, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101139, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101140, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101141, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101142, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101143, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101144, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101145, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101146, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101147, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101148, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101149, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101150, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101151, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101152, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101153, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101154, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101155, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101156, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101157, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101158, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101159, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101160, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101161, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101162, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101163, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101164, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101165, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101166, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101167, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101168, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101169, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101170, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101171, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101172, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101173, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101174, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101175, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101176, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101177, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101178, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101179, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101180, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101181, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101182, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101183, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101184, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101185, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101186, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101187, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101188, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101189, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101190, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101191, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101192, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101193, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101194, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101195, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101196, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101197, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101198, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101199, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101200, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101201, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101202, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101203, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101204, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101205, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101206, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101207, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101208, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101209, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101210, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101211, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101212, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101213, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101214, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101215, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101216, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101217, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101218, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101219, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101220, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101221, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101222, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101223, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101224, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101225, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101226, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101227, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101228, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101229, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101230, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101231, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101232, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101233, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101234, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101235, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101236, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101237, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101238, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101239, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101240, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101241, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101242, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101243, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101244, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101245, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101246, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101247, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101248, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101249, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101250, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101251, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101252, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101253, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101254, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101255, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101256, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101257, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101258, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101259, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101260, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101261, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101262, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101263, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101264, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101265, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101266, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101267, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101268, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101269, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101270, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101271, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101272, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101273, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101274, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101275, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101276, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101277, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101278, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101279, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101280, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101281, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101282, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101283, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101284, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101285, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101286, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101287, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101288, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101289, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101290, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101291, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101292, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101293, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101294, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101295, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101296, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101297, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101298, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101299, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101300, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101301, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101302, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101303, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101304, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101305, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101306, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101307, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101308, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101309, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101310, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101311, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101312, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101313, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101314, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101315, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101316, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101317, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101318, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101319, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101320, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101321, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101322, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101323, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101324, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101325, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101326, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101327, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101328, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101329, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101330, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101331, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101332, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101333, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101334, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101335, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101336, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101337, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101338, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101339, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101340, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101341, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101342, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101343, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101344, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101345, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101346, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101347, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101348, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101349, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101350, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101351, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101352, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101353, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101354, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101355, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101356, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101357, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101358, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101359, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101360, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101361, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101362, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101363, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101364, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101365, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101366, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101367, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101368, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101369, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101370, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101371, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101372, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101373, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101374, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101375, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101376, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101377, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101378, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101379, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101380, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101381, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101382, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101383, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101384, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101385, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101386, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101387, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101388, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101389, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101390, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101391, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101392, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101393, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101394, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101395, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101396, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101397, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101398, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101399, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101400, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101401, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101402, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101403, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101404, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101405, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101406, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101407, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101408, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101409, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101410, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101411, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101412, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101413, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101414, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101415, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101416, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101417, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101418, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101419, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101420, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101421, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101422, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101423, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101424, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101425, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101426, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101427, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101428, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101429, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101430, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101431, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101432, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101433, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101434, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101435, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101436, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101437, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101438, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101439, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101440, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101441, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101442, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101443, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101444, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101445, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101446, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101447, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101448, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101449, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101450, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101451, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101452, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101453, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101454, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101455, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101456, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101457, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101458, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101459, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101460, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101461, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101462, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101463, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101464, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101465, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101466, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101467, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101468, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101469, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101470, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101471, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101472, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101473, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101474, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101475, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101476, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101477, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101478, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101479, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101480, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101481, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101482, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101483, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101484, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101485, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101486, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101487, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101488, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101489, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101490, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101491, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101492, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101493, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101494, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101495, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101496, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101497, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101498, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101499, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101500, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101501, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101502, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101503, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101504, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101505, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101506, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101507, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101508, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101509, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101510, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101511, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101512, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101513, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101514, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101515, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101516, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101517, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101518, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101519, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101520, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101521, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101522, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101523, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101524, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101525, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101526, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101527, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101528, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101529, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101530, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101531, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101532, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101533, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101534, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101535, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101536, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101537, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101538, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101539, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101540, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101541, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101542, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101543, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101544, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101545, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101546, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101547, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101548, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101549, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101550, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101551, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101552, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101553, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101554, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101555, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101556, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101557, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101558, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101559, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101560, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101561, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101562, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101563, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101564, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101565, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101566, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101567, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101568, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101569, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101570, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101571, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101572, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101573, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101574, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101575, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101576, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101577, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101578, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101579, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101580, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101581, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101582, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101583, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101584, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101585, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101586, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101587, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101588, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {101589, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {110592, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {110593, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {110594, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, @@ -25877,6 +26757,13 @@ UnicodeCharacter unicodeCharacters[32262] = { {110876, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {110877, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {110878, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {110928, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {110929, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {110930, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {110948, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {110949, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {110950, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {110951, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {110960, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {110961, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {110962, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, @@ -28805,6 +29692,136 @@ UnicodeCharacter unicodeCharacters[32262] = { {122920, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {122921, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {122922, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {123136, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123137, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123138, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123139, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123140, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123141, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123142, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123143, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123144, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123145, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123146, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123147, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123148, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123149, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123150, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123151, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123152, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123153, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123154, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123155, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123156, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123157, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123158, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123159, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123160, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123161, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123162, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123163, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123164, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123165, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123166, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123167, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123168, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123169, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123170, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123171, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123172, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123173, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123174, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123175, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123176, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123177, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123178, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123179, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123180, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123184, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {123185, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {123186, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {123187, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {123188, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {123189, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {123190, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {123191, Unicode::Category_Letter_Modifier, Unicode::Direction_Left_To_Right}, + {123192, Unicode::Category_Letter_Modifier, Unicode::Direction_Left_To_Right}, + {123193, Unicode::Category_Letter_Modifier, Unicode::Direction_Left_To_Right}, + {123194, Unicode::Category_Letter_Modifier, Unicode::Direction_Left_To_Right}, + {123195, Unicode::Category_Letter_Modifier, Unicode::Direction_Left_To_Right}, + {123196, Unicode::Category_Letter_Modifier, Unicode::Direction_Left_To_Right}, + {123197, Unicode::Category_Letter_Modifier, Unicode::Direction_Left_To_Right}, + {123200, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {123201, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {123202, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {123203, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {123204, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {123205, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {123206, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {123207, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {123208, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {123209, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {123214, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123215, Unicode::Category_Symbol_Other, Unicode::Direction_Left_To_Right}, + {123584, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123585, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123586, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123587, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123588, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123589, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123590, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123591, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123592, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123593, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123594, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123595, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123596, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123597, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123598, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123599, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123600, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123601, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123602, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123603, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123604, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123605, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123606, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123607, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123608, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123609, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123610, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123611, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123612, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123613, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123614, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123615, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123616, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123617, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123618, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123619, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123620, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123621, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123622, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123623, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123624, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123625, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123626, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123627, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, + {123628, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {123629, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {123630, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {123631, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {123632, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {123633, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {123634, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {123635, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {123636, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {123637, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {123638, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {123639, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {123640, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {123641, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Left_To_Right}, + {123647, Unicode::Category_Symbol_Currency, Unicode::Direction_European_Terminator}, {124928, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, {124929, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, {124930, Unicode::Category_Letter_Other, Unicode::Direction_Right_To_Left}, @@ -29093,6 +30110,7 @@ UnicodeCharacter unicodeCharacters[32262] = { {125256, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {125257, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, {125258, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, + {125259, Unicode::Category_Letter_Modifier, Unicode::Direction_Right_To_Left}, {125264, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Right_To_Left}, {125265, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Right_To_Left}, {125266, Unicode::Category_Number_DecimalDigit, Unicode::Direction_Right_To_Left}, @@ -29173,6 +30191,67 @@ UnicodeCharacter unicodeCharacters[32262] = { {126130, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, {126131, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, {126132, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126209, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126210, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126211, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126212, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126213, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126214, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126215, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126216, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126217, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126218, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126219, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126220, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126221, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126222, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126223, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126224, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126225, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126226, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126227, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126228, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126229, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126230, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126231, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126232, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126233, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126234, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126235, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126236, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126237, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126238, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126239, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126240, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126241, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126242, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126243, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126244, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126245, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126246, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126247, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126248, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126249, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126250, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126251, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126252, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126253, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126254, Unicode::Category_Symbol_Other, Unicode::Direction_Arabic_Letter}, + {126255, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126256, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126257, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126258, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126259, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126260, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126261, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126262, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126263, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126264, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126265, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126266, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126267, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126268, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, + {126269, Unicode::Category_Number_Other, Unicode::Direction_Arabic_Letter}, {126464, Unicode::Category_Letter_Other, Unicode::Direction_Arabic_Letter}, {126465, Unicode::Category_Letter_Other, Unicode::Direction_Arabic_Letter}, {126466, Unicode::Category_Letter_Other, Unicode::Direction_Arabic_Letter}, @@ -29555,6 +30634,9 @@ UnicodeCharacter unicodeCharacters[32262] = { {127242, Unicode::Category_Number_Other, Unicode::Direction_European_Number}, {127243, Unicode::Category_Number_Other, Unicode::Direction_Other_Neutral}, {127244, Unicode::Category_Number_Other, Unicode::Direction_Other_Neutral}, + {127245, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {127246, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {127247, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {127248, Unicode::Category_Symbol_Other, Unicode::Direction_Left_To_Right}, {127249, Unicode::Category_Symbol_Other, Unicode::Direction_Left_To_Right}, {127250, Unicode::Category_Symbol_Other, Unicode::Direction_Left_To_Right}, @@ -29647,6 +30729,10 @@ UnicodeCharacter unicodeCharacters[32262] = { {127337, Unicode::Category_Symbol_Other, Unicode::Direction_Left_To_Right}, {127338, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {127339, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {127340, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {127341, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {127342, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {127343, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {127344, Unicode::Category_Symbol_Other, Unicode::Direction_Left_To_Right}, {127345, Unicode::Category_Symbol_Other, Unicode::Direction_Left_To_Right}, {127346, Unicode::Category_Symbol_Other, Unicode::Direction_Left_To_Right}, @@ -29708,6 +30794,7 @@ UnicodeCharacter unicodeCharacters[32262] = { {127402, Unicode::Category_Symbol_Other, Unicode::Direction_Left_To_Right}, {127403, Unicode::Category_Symbol_Other, Unicode::Direction_Left_To_Right}, {127404, Unicode::Category_Symbol_Other, Unicode::Direction_Left_To_Right}, + {127405, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {127462, Unicode::Category_Symbol_Other, Unicode::Direction_Left_To_Right}, {127463, Unicode::Category_Symbol_Other, Unicode::Direction_Left_To_Right}, {127464, Unicode::Category_Symbol_Other, Unicode::Direction_Left_To_Right}, @@ -30779,6 +31866,9 @@ UnicodeCharacter unicodeCharacters[32262] = { {128722, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {128723, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {128724, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {128725, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {128726, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {128727, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {128736, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {128737, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {128738, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, @@ -30802,6 +31892,9 @@ UnicodeCharacter unicodeCharacters[32262] = { {128759, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {128760, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {128761, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {128762, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {128763, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {128764, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {128768, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {128769, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {128770, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, @@ -31007,6 +32100,18 @@ UnicodeCharacter unicodeCharacters[32262] = { {128982, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {128983, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {128984, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {128992, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {128993, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {128994, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {128995, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {128996, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {128997, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {128998, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {128999, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129000, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129001, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129002, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129003, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129024, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129025, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129026, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, @@ -31155,6 +32260,8 @@ UnicodeCharacter unicodeCharacters[32262] = { {129195, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129196, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129197, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129200, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129201, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129280, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129281, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129282, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, @@ -31167,6 +32274,10 @@ UnicodeCharacter unicodeCharacters[32262] = { {129289, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129290, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129291, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129292, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129293, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129294, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129295, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129296, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129297, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129298, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, @@ -31214,6 +32325,7 @@ UnicodeCharacter unicodeCharacters[32262] = { {129340, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129341, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129342, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129343, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129344, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129345, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129346, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, @@ -31263,11 +32375,16 @@ UnicodeCharacter unicodeCharacters[32262] = { {129390, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129391, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129392, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129393, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129394, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129395, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129396, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129397, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129398, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129399, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129400, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129402, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129403, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129404, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129405, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129406, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, @@ -31307,6 +32424,19 @@ UnicodeCharacter unicodeCharacters[32262] = { {129440, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129441, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129442, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129443, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129444, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129445, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129446, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129447, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129448, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129449, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129450, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129451, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129452, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129453, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129454, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129455, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129456, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129457, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129458, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, @@ -31317,9 +32447,27 @@ UnicodeCharacter unicodeCharacters[32262] = { {129463, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129464, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129465, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129466, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129467, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129468, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129469, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129470, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129471, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129472, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129473, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129474, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129475, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129476, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129477, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129478, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129479, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129480, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129481, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129482, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129483, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129485, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129486, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129487, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129488, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129489, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129490, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, @@ -31368,6 +32516,90 @@ UnicodeCharacter unicodeCharacters[32262] = { {129533, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129534, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129535, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129536, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129537, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129538, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129539, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129540, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129541, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129542, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129543, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129544, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129545, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129546, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129547, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129548, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129549, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129550, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129551, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129552, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129553, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129554, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129555, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129556, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129557, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129558, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129559, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129560, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129561, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129562, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129563, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129564, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129565, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129566, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129567, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129568, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129569, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129570, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129571, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129572, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129573, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129574, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129575, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129576, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129577, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129578, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129579, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129580, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129581, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129582, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129583, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129584, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129585, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129586, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129587, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129588, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129589, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129590, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129591, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129592, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129593, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129594, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129595, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129596, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129597, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129598, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129599, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129600, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129601, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129602, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129603, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129604, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129605, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129606, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129607, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129608, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129609, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129610, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129611, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129612, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129613, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129614, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129615, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129616, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129617, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129618, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129619, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129632, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129633, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129634, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, @@ -31382,6 +32614,275 @@ UnicodeCharacter unicodeCharacters[32262] = { {129643, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129644, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, {129645, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129648, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129649, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129650, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129651, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129652, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129656, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129657, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129658, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129664, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129665, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129666, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129667, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129668, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129669, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129670, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129680, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129681, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129682, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129683, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129684, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129685, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129686, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129687, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129688, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129689, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129690, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129691, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129692, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129693, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129694, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129695, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129696, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129697, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129698, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129699, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129700, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129701, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129702, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129703, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129704, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129712, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129713, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129714, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129715, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129716, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129717, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129718, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129728, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129729, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129730, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129744, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129745, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129746, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129747, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129748, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129749, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129750, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129792, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129793, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129794, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129795, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129796, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129797, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129798, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129799, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129800, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129801, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129802, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129803, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129804, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129805, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129806, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129807, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129808, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129809, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129810, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129811, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129812, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129813, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129814, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129815, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129816, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129817, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129818, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129819, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129820, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129821, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129822, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129823, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129824, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129825, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129826, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129827, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129828, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129829, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129830, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129831, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129832, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129833, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129834, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129835, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129836, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129837, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129838, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129839, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129840, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129841, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129842, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129843, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129844, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129845, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129846, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129847, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129848, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129849, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129850, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129851, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129852, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129853, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129854, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129855, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129856, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129857, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129858, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129859, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129860, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129861, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129862, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129863, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129864, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129865, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129866, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129867, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129868, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129869, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129870, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129871, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129872, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129873, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129874, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129875, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129876, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129877, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129878, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129879, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129880, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129881, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129882, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129883, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129884, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129885, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129886, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129887, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129888, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129889, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129890, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129891, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129892, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129893, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129894, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129895, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129896, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129897, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129898, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129899, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129900, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129901, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129902, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129903, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129904, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129905, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129906, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129907, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129908, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129909, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129910, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129911, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129912, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129913, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129914, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129915, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129916, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129917, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129918, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129919, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129920, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129921, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129922, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129923, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129924, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129925, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129926, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129927, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129928, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129929, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129930, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129931, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129932, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129933, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129934, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129935, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129936, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129937, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129938, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129940, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129941, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129942, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129943, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129944, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129945, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129946, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129947, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129948, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129949, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129950, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129951, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129952, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129953, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129954, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129955, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129956, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129957, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129958, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129959, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129960, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129961, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129962, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129963, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129964, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129965, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129966, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129967, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129968, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129969, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129970, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129971, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129972, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129973, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129974, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129975, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129976, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129977, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129978, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129979, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129980, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129981, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129982, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129983, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129984, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129985, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129986, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129987, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129988, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129989, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129990, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129991, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129992, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129993, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {129994, Unicode::Category_Symbol_Other, Unicode::Direction_Other_Neutral}, + {130032, Unicode::Category_Number_DecimalDigit, Unicode::Direction_European_Number}, + {130033, Unicode::Category_Number_DecimalDigit, Unicode::Direction_European_Number}, + {130034, Unicode::Category_Number_DecimalDigit, Unicode::Direction_European_Number}, + {130035, Unicode::Category_Number_DecimalDigit, Unicode::Direction_European_Number}, + {130036, Unicode::Category_Number_DecimalDigit, Unicode::Direction_European_Number}, + {130037, Unicode::Category_Number_DecimalDigit, Unicode::Direction_European_Number}, + {130038, Unicode::Category_Number_DecimalDigit, Unicode::Direction_European_Number}, + {130039, Unicode::Category_Number_DecimalDigit, Unicode::Direction_European_Number}, + {130040, Unicode::Category_Number_DecimalDigit, Unicode::Direction_European_Number}, + {130041, Unicode::Category_Number_DecimalDigit, Unicode::Direction_European_Number}, {194560, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {194561, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, {194562, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}, @@ -32263,25 +33764,27 @@ UnicodeCharacter unicodeCharacters[32262] = { {917999, Unicode::Category_Mark_NonSpacing, Unicode::Direction_Nonspacing_Mark}, }; -UnicodeSet unicodeSets[15] = { - {13312, 19893, {13312, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}}, - {19968, 40943, {19968, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}}, +UnicodeSet unicodeSets[17] = { + {13312, 19903, {13312, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}}, + {19968, 40956, {19968, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}}, {44032, 55203, {44032, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}}, {55296, 56191, {55296, Unicode::Category_Other_Surrogate, Unicode::Direction_Left_To_Right}}, {56192, 56319, {56192, Unicode::Category_Other_Surrogate, Unicode::Direction_Left_To_Right}}, {56320, 57343, {56320, Unicode::Category_Other_Surrogate, Unicode::Direction_Left_To_Right}}, {57344, 63743, {57344, Unicode::Category_Other_PrivateUse, Unicode::Direction_Left_To_Right}}, - {94208, 100337, {94208, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}}, - {131072, 173782, {131072, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}}, + {94208, 100343, {94208, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}}, + {101632, 101640, {101632, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}}, + {131072, 173789, {131072, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}}, {173824, 177972, {173824, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}}, {177984, 178205, {177984, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}}, {178208, 183969, {178208, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}}, {183984, 191456, {183984, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}}, + {196608, 201546, {196608, Unicode::Category_Letter_Other, Unicode::Direction_Left_To_Right}}, {983040, 1048573, {983040, Unicode::Category_Other_PrivateUse, Unicode::Direction_Left_To_Right}}, {1048576, 1114109, {1048576, Unicode::Category_Other_PrivateUse, Unicode::Direction_Left_To_Right}}, }; -UnicodeCharacterSimpleMapping unicodeLower[1383] = { +UnicodeCharacterSimpleMapping unicodeLower[1393] = { {65, 97}, {66, 98}, {67, 99}, @@ -33414,6 +34917,16 @@ UnicodeCharacterSimpleMapping unicodeLower[1383] = { {42932, 42933}, {42934, 42935}, {42936, 42937}, + {42938, 42939}, + {42940, 42941}, + {42942, 42943}, + {42946, 42947}, + {42948, 42900}, + {42949, 642}, + {42950, 7566}, + {42951, 42952}, + {42953, 42954}, + {42997, 42998}, {65313, 65345}, {65314, 65346}, {65315, 65347}, @@ -33667,7 +35180,7 @@ UnicodeCharacterSimpleMapping unicodeLower[1383] = { {125217, 125251}, }; -UnicodeCharacterSimpleMapping unicodeTitle[1404] = { +UnicodeCharacterSimpleMapping unicodeTitle[1414] = { {97, 65}, {98, 66}, {99, 67}, @@ -33905,6 +35418,7 @@ UnicodeCharacterSimpleMapping unicodeTitle[1404] = { {629, 415}, {637, 11364}, {640, 422}, + {642, 42949}, {643, 425}, {647, 42929}, {648, 430}, @@ -34229,6 +35743,7 @@ UnicodeCharacterSimpleMapping unicodeTitle[1404] = { {7304, 42570}, {7545, 42877}, {7549, 11363}, + {7566, 42950}, {7681, 7680}, {7683, 7682}, {7685, 7684}, @@ -34727,6 +36242,7 @@ UnicodeCharacterSimpleMapping unicodeTitle[1404] = { {42892, 42891}, {42897, 42896}, {42899, 42898}, + {42900, 42948}, {42903, 42902}, {42905, 42904}, {42907, 42906}, @@ -34740,6 +36256,13 @@ UnicodeCharacterSimpleMapping unicodeTitle[1404] = { {42933, 42932}, {42935, 42934}, {42937, 42936}, + {42939, 42938}, + {42941, 42940}, + {42943, 42942}, + {42947, 42946}, + {42952, 42951}, + {42954, 42953}, + {42998, 42997}, {43859, 42931}, {43888, 5024}, {43889, 5025}, @@ -35074,7 +36597,7 @@ UnicodeCharacterSimpleMapping unicodeTitle[1404] = { {125251, 125217}, }; -UnicodeCharacterSimpleMapping unicodeUpper[1400] = { +UnicodeCharacterSimpleMapping unicodeUpper[1410] = { {97, 65}, {98, 66}, {99, 67}, @@ -35308,6 +36831,7 @@ UnicodeCharacterSimpleMapping unicodeUpper[1400] = { {629, 415}, {637, 11364}, {640, 422}, + {642, 42949}, {643, 425}, {647, 42929}, {648, 430}, @@ -35632,6 +37156,7 @@ UnicodeCharacterSimpleMapping unicodeUpper[1400] = { {7304, 42570}, {7545, 42877}, {7549, 11363}, + {7566, 42950}, {7681, 7680}, {7683, 7682}, {7685, 7684}, @@ -36130,6 +37655,7 @@ UnicodeCharacterSimpleMapping unicodeUpper[1400] = { {42892, 42891}, {42897, 42896}, {42899, 42898}, + {42900, 42948}, {42903, 42902}, {42905, 42904}, {42907, 42906}, @@ -36143,6 +37669,13 @@ UnicodeCharacterSimpleMapping unicodeUpper[1400] = { {42933, 42932}, {42935, 42934}, {42937, 42936}, + {42939, 42938}, + {42941, 42940}, + {42943, 42942}, + {42947, 42946}, + {42952, 42951}, + {42954, 42953}, + {42998, 42997}, {43859, 42931}, {43888, 5024}, {43889, 5025}, diff --git a/src/Nazara/Core/Win32/FileImpl.cpp b/src/Nazara/Core/Win32/FileImpl.cpp index 71274fc47..69f38ff9f 100644 --- a/src/Nazara/Core/Win32/FileImpl.cpp +++ b/src/Nazara/Core/Win32/FileImpl.cpp @@ -63,30 +63,30 @@ namespace Nz DWORD shareMode = FILE_SHARE_READ; DWORD openMode = 0; - if (mode & OpenMode_ReadOnly) + if (mode & OpenMode::ReadOnly) { access |= GENERIC_READ; - if (mode & OpenMode_MustExist || (mode & OpenMode_WriteOnly) == 0) + if (mode & OpenMode::MustExist || (mode & OpenMode::WriteOnly) == 0) openMode |= OPEN_EXISTING; } - if (mode & OpenMode_WriteOnly) + if (mode & OpenMode::WriteOnly) { - if (mode & OpenMode_Append) + if (mode & OpenMode::Append) access |= FILE_APPEND_DATA; else access |= GENERIC_WRITE; - if (mode & OpenMode_Truncate) + if (mode & OpenMode::Truncate) openMode |= CREATE_ALWAYS; - else if (mode & OpenMode_MustExist) + else if (mode & OpenMode::MustExist) openMode |= OPEN_EXISTING; else openMode |= OPEN_ALWAYS; } - if ((mode & OpenMode_Lock) == 0) + if ((mode & OpenMode::Lock) == 0) shareMode |= FILE_SHARE_WRITE; m_handle = CreateFileW(ToWideString(filePath.generic_u8string()).data(), access, shareMode, nullptr, openMode, 0, nullptr); @@ -136,20 +136,20 @@ namespace Nz DWORD moveMethod; switch (pos) { - case CursorPosition_AtBegin: + case CursorPosition::AtBegin: moveMethod = FILE_BEGIN; break; - case CursorPosition_AtCurrent: + case CursorPosition::AtCurrent: moveMethod = FILE_CURRENT; break; - case CursorPosition_AtEnd: + case CursorPosition::AtEnd: moveMethod = FILE_END; break; default: - NazaraInternalError("Cursor position not handled (0x" + NumberToString(pos, 16) + ')'); + NazaraInternalError("Cursor position not handled (0x" + NumberToString(UnderlyingCast(pos), 16) + ')'); return false; } @@ -167,11 +167,11 @@ namespace Nz CallOnExit resetCursor([this, cursorPos] () { - if (!SetCursorPos(CursorPosition_AtBegin, cursorPos)) + if (!SetCursorPos(CursorPosition::AtBegin, cursorPos)) NazaraWarning("Failed to reset cursor position to previous position: " + Error::GetLastSystemError()); }); - if (!SetCursorPos(CursorPosition_AtBegin, size)) + if (!SetCursorPos(CursorPosition::AtBegin, size)) { NazaraError("Failed to set file size: failed to move cursor position: " + Error::GetLastSystemError()); return false; diff --git a/src/Nazara/Graphics/BakedFrameGraph.cpp b/src/Nazara/Graphics/BakedFrameGraph.cpp new file mode 100644 index 000000000..f88857cf2 --- /dev/null +++ b/src/Nazara/Graphics/BakedFrameGraph.cpp @@ -0,0 +1,166 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include + +namespace Nz +{ + BakedFrameGraph::BakedFrameGraph(std::vector passes, std::vector textures, AttachmentIdToTextureId attachmentIdToTextureMapping, PassIdToPhysicalPassIndex passIdToPhysicalPassMapping) : + m_passes(std::move(passes)), + m_textures(std::move(textures)), + m_attachmentToTextureMapping(std::move(attachmentIdToTextureMapping)), + m_passIdToPhysicalPassMapping(std::move(passIdToPhysicalPassMapping)) + { + const std::shared_ptr& renderDevice = Graphics::Instance()->GetRenderDevice(); + m_commandPool = renderDevice->InstantiateCommandPool(QueueType::Graphics); + } + + void BakedFrameGraph::Execute(RenderFrame& renderFrame) + { + for (auto& passData : m_passes) + { + bool regenerateCommandBuffer = (passData.commandBuffer == nullptr); + if (passData.executionCallback) + { + switch (passData.executionCallback()) + { + case FramePassExecution::Execute: + break; + + case FramePassExecution::Skip: + passData.commandBuffer.reset(); + continue; //< Skip the pass + + case FramePassExecution::UpdateAndExecute: + regenerateCommandBuffer = true; + break; + } + } + + if (!regenerateCommandBuffer) + continue; + + renderFrame.PushForRelease(std::move(passData.commandBuffer)); + passData.commandBuffer = m_commandPool->BuildCommandBuffer([&](CommandBufferBuilder& builder) + { + for (auto& textureTransition : passData.transitions) + { + const std::shared_ptr& texture = m_textures[textureTransition.textureId].texture; + builder.TextureBarrier(textureTransition.srcStageMask, textureTransition.dstStageMask, textureTransition.srcAccessMask, textureTransition.dstAccessMask, textureTransition.oldLayout, textureTransition.newLayout, *texture); + } + + if (!passData.name.empty()) + builder.BeginDebugRegion(passData.name, Nz::Color::Green); + + builder.BeginRenderPass(*passData.framebuffer, *passData.renderPass, passData.renderRect); + + bool first = true; + for (auto& subpass : passData.subpasses) + { + if (!first) + builder.NextSubpass(); + + first = false; + + subpass.commandCallback(builder); + } + + builder.EndRenderPass(); + + if (!passData.name.empty()) + builder.EndDebugRegion(); + }); + } + + //TODO: Submit all commands buffer at once + for (auto& passData : m_passes) + { + if (passData.commandBuffer) + renderFrame.SubmitCommandBuffer(passData.commandBuffer.get(), QueueType::Graphics); + } + } + + const std::shared_ptr& BakedFrameGraph::GetAttachmentTexture(std::size_t attachmentIndex) const + { + auto it = m_attachmentToTextureMapping.find(attachmentIndex); + if (it == m_attachmentToTextureMapping.end()) + { + static std::shared_ptr dummy; + return dummy; + } + + std::size_t textureIndex = it->second; + assert(textureIndex < m_textures.size()); + return m_textures[textureIndex].texture; + } + + const std::shared_ptr& BakedFrameGraph::GetRenderPass(std::size_t passIndex) const + { + auto it = m_attachmentToTextureMapping.find(passIndex); + if (it == m_attachmentToTextureMapping.end()) + { + static std::shared_ptr dummy; + return dummy; + } + + std::size_t physicalPassIndex = it->second; + assert(physicalPassIndex < m_passes.size()); + return m_passes[physicalPassIndex].renderPass; + } + + void BakedFrameGraph::Resize(unsigned int width, unsigned int height) + { + const std::shared_ptr& renderDevice = Graphics::Instance()->GetRenderDevice(); + + // Delete previous textures to make some room in VRAM + for (auto& passData : m_passes) + { + passData.commandBuffer.reset(); + passData.framebuffer.reset(); + } + + for (auto& textureData : m_textures) + textureData.texture.reset(); + + for (auto& textureData : m_textures) + { + TextureInfo textureCreationParams; + textureCreationParams.type = ImageType::E2D; + textureCreationParams.width = textureData.width * width / 100'000; + textureCreationParams.height = textureData.height * height / 100'000; + textureCreationParams.usageFlags = textureData.usage; + textureCreationParams.pixelFormat = textureData.format; + + textureData.texture = renderDevice->InstantiateTexture(textureCreationParams); + } + + std::vector> textures; + for (auto& passData : m_passes) + { + textures.clear(); + + unsigned int framebufferWidth = std::numeric_limits::max(); + unsigned int framebufferHeight = std::numeric_limits::max(); + for (std::size_t textureId : passData.outputTextureIndices) + { + auto& textureData = m_textures[textureId]; + textures.push_back(textureData.texture); + + framebufferWidth = std::min(framebufferWidth, textureData.width); + framebufferHeight = std::min(framebufferHeight, textureData.height); + } + + framebufferWidth = framebufferWidth * width / 100'000; + framebufferHeight = framebufferHeight * height / 100'000; + + passData.renderRect.Set(0, 0, int(framebufferWidth), int(framebufferHeight)); + + passData.framebuffer = renderDevice->InstantiateFramebuffer(framebufferWidth, framebufferHeight, passData.renderPass, textures); + } + } +} diff --git a/src/Nazara/Graphics/BasicMaterial.cpp b/src/Nazara/Graphics/BasicMaterial.cpp new file mode 100644 index 000000000..a721a0388 --- /dev/null +++ b/src/Nazara/Graphics/BasicMaterial.cpp @@ -0,0 +1,229 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + namespace + { + const UInt8 r_fragmentShader[] = { + #include + }; + + const UInt8 r_vertexShader[] = { + #include + }; + } + + BasicMaterial::BasicMaterial(Material& material) : + m_material(material) + { + // Most common case: don't fetch texture indexes as a little optimization + const std::shared_ptr& materialSettings = material.GetSettings(); + if (materialSettings == s_materialSettings) + { + m_conditionIndexes = s_conditionIndexes; + m_textureIndexes = s_textureIndexes; + m_uniformBlockIndex = s_uniformBlockIndex; + m_uniformOffsets = s_uniformOffsets; + } + else + { + m_conditionIndexes.alphaTest = materialSettings->GetConditionIndex("AlphaTest"); + m_conditionIndexes.hasAlphaMap = materialSettings->GetConditionIndex("HasAlphaMap"); + m_conditionIndexes.hasDiffuseMap = materialSettings->GetConditionIndex("HasDiffuseMap"); + + m_textureIndexes.alpha = materialSettings->GetTextureIndex("Alpha"); + m_textureIndexes.diffuse = materialSettings->GetTextureIndex("Diffuse"); + + m_uniformBlockIndex = materialSettings->GetUniformBlockIndex("BasicSettings"); + + m_uniformOffsets.alphaThreshold = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "AlphaThreshold"); + m_uniformOffsets.diffuseColor = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "DiffuseColor"); + } + } + + float BasicMaterial::GetAlphaTestThreshold() const + { + NazaraAssert(HasAlphaTestThreshold(), "Material has no alpha threshold uniform"); + + const std::vector& bufferData = m_material.GetUniformBufferConstData(m_uniformBlockIndex); + + return AccessByOffset(bufferData.data(), m_uniformOffsets.alphaThreshold); + } + + Color BasicMaterial::GetDiffuseColor() const + { + NazaraAssert(HasDiffuseColor(), "Material has no diffuse color uniform"); + + const std::vector& bufferData = m_material.GetUniformBufferConstData(m_uniformBlockIndex); + + const float* colorPtr = AccessByOffset(bufferData.data(), m_uniformOffsets.diffuseColor); + return Color(colorPtr[0] * 255, colorPtr[1] * 255, colorPtr[2] * 255, colorPtr[3] * 255); //< TODO: Make color able to use float + } + + void BasicMaterial::SetAlphaTestThreshold(float alphaThreshold) + { + NazaraAssert(HasAlphaTestThreshold(), "Material has no alpha threshold uniform"); + + std::vector& bufferData = m_material.GetUniformBufferData(m_uniformBlockIndex); + AccessByOffset(bufferData.data(), m_uniformOffsets.alphaThreshold) = alphaThreshold; + } + + void BasicMaterial::SetDiffuseColor(const Color& diffuse) + { + NazaraAssert(HasDiffuseColor(), "Material has no diffuse color uniform"); + + std::vector& bufferData = m_material.GetUniformBufferData(m_uniformBlockIndex); + + float* colorPtr = AccessByOffset(bufferData.data(), m_uniformOffsets.diffuseColor); + colorPtr[0] = diffuse.r / 255.f; + colorPtr[1] = diffuse.g / 255.f; + colorPtr[2] = diffuse.b / 255.f; + colorPtr[3] = diffuse.a / 255.f; + } + + bool BasicMaterial::Initialize() + { + FieldOffsets fieldOffsets(StructLayout::Std140); + + s_uniformOffsets.alphaThreshold = fieldOffsets.AddField(StructFieldType::Float1); + s_uniformOffsets.diffuseColor = fieldOffsets.AddField(StructFieldType::Float4); + s_uniformOffsets.totalSize = fieldOffsets.GetSize(); + + MaterialSettings::Builder settings; + settings.predefinedBinding.fill(MaterialSettings::InvalidIndex); + + std::vector variables; + variables.assign({ + { + "AlphaThreshold", + s_uniformOffsets.alphaThreshold + }, + { + "DiffuseColor", + s_uniformOffsets.diffuseColor + } + }); + + static_assert(sizeof(Vector4f) == 4 * sizeof(float), "Vector4f is expected to be exactly 4 floats wide"); + + std::vector defaultValues(fieldOffsets.GetSize()); + AccessByOffset(defaultValues.data(), s_uniformOffsets.diffuseColor) = Vector4f(1.f, 1.f, 1.f, 1.f); + AccessByOffset(defaultValues.data(), s_uniformOffsets.alphaThreshold) = 0.2f; + + s_textureIndexes.alpha = settings.textures.size(); + settings.textures.push_back({ + "MaterialAlphaMap", + "Alpha", + ImageType::E2D + }); + + s_textureIndexes.diffuse = settings.textures.size(); + settings.textures.push_back({ + "MaterialDiffuseMap", + "Diffuse", + ImageType::E2D + }); + + settings.predefinedBinding[UnderlyingCast(PredefinedShaderBinding::TexOverlay)] = settings.textures.size(); + settings.textures.push_back({ + "TextureOverlay", + "Overlay", + ImageType::E2D + }); + + s_uniformBlockIndex = settings.uniformBlocks.size(); + settings.uniformBlocks.assign({ + { + fieldOffsets.GetSize(), + "BasicSettings", + "MaterialBasicSettings", + std::move(variables), + std::move(defaultValues) + } + }); + + settings.predefinedBinding[UnderlyingCast(PredefinedShaderBinding::UboInstanceData)] = settings.textures.size() + settings.uniformBlocks.size() + settings.sharedUniformBlocks.size(); + settings.sharedUniformBlocks.push_back(PredefinedInstanceData::GetUniformBlock()); + + settings.predefinedBinding[UnderlyingCast(PredefinedShaderBinding::UboViewerData)] = settings.textures.size() + settings.uniformBlocks.size() + settings.sharedUniformBlocks.size(); + settings.sharedUniformBlocks.push_back(PredefinedViewerData::GetUniformBlock()); + + // Shaders + auto& fragmentShader = settings.shaders[UnderlyingCast(ShaderStageType::Fragment)]; + auto& vertexShader = settings.shaders[UnderlyingCast(ShaderStageType::Vertex)]; + + fragmentShader = std::make_shared(ShaderStageType::Fragment, ShaderAst::UnserializeShader(r_fragmentShader, sizeof(r_fragmentShader))); + vertexShader = std::make_shared(ShaderStageType::Vertex, ShaderAst::UnserializeShader(r_vertexShader, sizeof(r_vertexShader))); + + // Conditions + + // HasDiffuseMap + { + std::array shaderConditions; + shaderConditions.fill(0); + shaderConditions[UnderlyingCast(ShaderStageType::Fragment)] = fragmentShader->GetOptionFlagByName("HAS_DIFFUSE_TEXTURE"); + + s_conditionIndexes.hasDiffuseMap = settings.conditions.size(); + settings.conditions.push_back({ + "HasDiffuseMap", + shaderConditions + }); + } + + // HasAlphaMap + { + std::array shaderConditions; + shaderConditions.fill(0); + shaderConditions[UnderlyingCast(ShaderStageType::Fragment)] = fragmentShader->GetOptionFlagByName("HAS_ALPHA_TEXTURE"); + + s_conditionIndexes.hasAlphaMap = settings.conditions.size(); + settings.conditions.push_back({ + "HasAlphaMap", + shaderConditions + }); + } + + // AlphaTest + { + std::array shaderConditions; + shaderConditions.fill(0); + shaderConditions[UnderlyingCast(ShaderStageType::Fragment)] = fragmentShader->GetOptionFlagByName("ALPHA_TEST"); + + s_conditionIndexes.alphaTest = settings.conditions.size(); + settings.conditions.push_back({ + "AlphaTest", + shaderConditions + }); + } + + s_materialSettings = std::make_shared(std::move(settings)); + + return true; + } + + void BasicMaterial::Uninitialize() + { + s_materialSettings.reset(); + } + + std::shared_ptr BasicMaterial::s_materialSettings; + std::size_t BasicMaterial::s_uniformBlockIndex; + BasicMaterial::ConditionIndexes BasicMaterial::s_conditionIndexes; + BasicMaterial::TextureIndexes BasicMaterial::s_textureIndexes; + BasicMaterial::UniformOffsets BasicMaterial::s_uniformOffsets; +} diff --git a/src/Nazara/Graphics/FrameGraph.cpp b/src/Nazara/Graphics/FrameGraph.cpp new file mode 100644 index 000000000..cd9874e6c --- /dev/null +++ b/src/Nazara/Graphics/FrameGraph.cpp @@ -0,0 +1,930 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +// This class was written with a lot of help from themaister articles and Granite source code, check them out! +// https://themaister.net/blog/2017/08/15/render-graphs-and-vulkan-a-deep-dive/ + +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + namespace + { + template const T& Retrieve(const std::unordered_map& map, std::size_t id) + { + auto it = map.find(id); + assert(it != map.end()); + return it->second; + } + + template void UniquePushBack(std::vector& vec, const T& value) + { + auto it = std::find(vec.begin(), vec.end(), value); + if (it == vec.end()) + vec.push_back(value); + } + } + + BakedFrameGraph FrameGraph::Bake() + { + if (!m_backbufferOutput.has_value()) + throw std::runtime_error("no backbuffer output has been set"); + + m_pending.attachmentReadList.clear(); + m_pending.attachmentToTextures.clear(); + m_pending.attachmentWriteList.clear(); + m_pending.barrierList.clear(); + m_pending.passIdToPhysicalPassIndex.clear(); + m_pending.passList.clear(); + m_pending.physicalPasses.clear(); + m_pending.renderPasses.clear(); + m_pending.textures.clear(); + + m_pending.backbufferResourceIndex = m_backbufferOutput.value(); + + BuildReadWriteList(); + + auto it = m_pending.attachmentWriteList.find(m_pending.backbufferResourceIndex); + if (it == m_pending.attachmentWriteList.end()) + throw std::runtime_error("no pass writes to backbuffer"); + + const std::vector& backbufferPasses = it->second; + for (std::size_t passIndex : backbufferPasses) + TraverseGraph(passIndex); + + std::reverse(m_pending.passList.begin(), m_pending.passList.end()); + + RemoveDuplicatePasses(); + ReorderPasses(); + AssignPhysicalTextures(); + AssignPhysicalPasses(); + BuildPhysicalPasses(); + //BuildBarriers(); + //BuildPhysicalBarriers(); + + std::vector bakedPasses; + bakedPasses.reserve(m_pending.physicalPasses.size()); + + std::size_t renderPassIndex = 0; + for (auto& physicalPass : m_pending.physicalPasses) + { + auto& bakedPass = bakedPasses.emplace_back(); + bakedPass.name = std::move(physicalPass.name); + bakedPass.renderPass = std::move(m_pending.renderPasses[renderPassIndex++]); + bakedPass.transitions = std::move(physicalPass.textureTransitions); + + for (auto& subpass : physicalPass.passes) + { + const FramePass& framePass = m_framePasses[subpass.passIndex]; + bakedPass.executionCallback = framePass.GetExecutionCallback(); //< FIXME + + auto& bakedSubpass = bakedPass.subpasses.emplace_back(); + bakedSubpass.commandCallback = framePass.GetCommandCallback(); + + for (const auto& output : framePass.GetOutputs()) + bakedPass.outputTextureIndices.push_back(Retrieve(m_pending.attachmentToTextures, output.attachmentId)); + + if (std::size_t attachmentId = framePass.GetDepthStencilOutput(); attachmentId != FramePass::InvalidAttachmentId) + bakedPass.outputTextureIndices.push_back(Retrieve(m_pending.attachmentToTextures, attachmentId)); + else if (std::size_t attachmentId = framePass.GetDepthStencilInput(); attachmentId != FramePass::InvalidAttachmentId) + bakedPass.outputTextureIndices.push_back(Retrieve(m_pending.attachmentToTextures, attachmentId)); //< FIXME? + } + } + + std::vector bakedTextures; + bakedTextures.reserve(m_pending.textures.size()); + for (auto& texture : m_pending.textures) + { + auto& bakedTexture = bakedTextures.emplace_back(); + bakedTexture.format = texture.format; + bakedTexture.height = texture.height; + bakedTexture.usage = texture.usage; + bakedTexture.width = texture.width; + } + + return BakedFrameGraph(std::move(bakedPasses), std::move(bakedTextures), std::move(m_pending.attachmentToTextures), std::move(m_pending.passIdToPhysicalPassIndex)); + } + + void FrameGraph::AssignPhysicalPasses() + { + auto ShouldMerge = [&](const FramePass& prevPass, const FramePass& nextPass) + { + //TODO + return false; + }; + + for (std::size_t passIndex = 0; passIndex < m_pending.passList.size();) + { + std::size_t mergeEnd = passIndex + 1; + for (; mergeEnd < m_pending.passList.size(); ++mergeEnd) + { + bool merge = true; + for (std::size_t mergeStart = passIndex; mergeStart < mergeEnd; ++mergeStart) + { + if (!ShouldMerge(m_framePasses[m_pending.passList[mergeStart]], m_framePasses[m_pending.passList[mergeEnd]])) + { + merge = false; + break; + } + } + + if (!merge) + break; + } + + std::size_t physPassIndex = m_pending.physicalPasses.size(); + PhysicalPassData& currentPass = m_pending.physicalPasses.emplace_back(); + + auto it = m_pending.passList.begin() + passIndex; + auto end = m_pending.passList.begin() + mergeEnd; + + for (; it < end; ++it) + { + const FramePass& pass = m_framePasses[*it]; + if (currentPass.name.empty()) + currentPass.name = pass.GetName(); + else + currentPass.name += " + " + pass.GetName(); + + auto& subpass = currentPass.passes.emplace_back(); + subpass.passIndex = *it; + m_pending.passIdToPhysicalPassIndex.emplace(subpass.passIndex, physPassIndex); + } + + passIndex = mergeEnd; + } + } + + void FrameGraph::AssignPhysicalTextures() + { + auto RegisterTexture = [&](std::size_t attachmentIndex) + { + if (auto it = m_pending.attachmentToTextures.find(attachmentIndex); it == m_pending.attachmentToTextures.end()) + { + std::size_t textureId = m_pending.textures.size(); + m_pending.attachmentToTextures.emplace(attachmentIndex, textureId); + + TextureData& data = m_pending.textures.emplace_back(); + data.format = m_attachments[attachmentIndex].format; + data.width = m_attachments[attachmentIndex].width; + data.height = m_attachments[attachmentIndex].height; + + return textureId; + } + else + return it->second; + }; + + for (std::size_t passIndex : m_pending.passList) + { + const FramePass& framePass = m_framePasses[passIndex]; + + for (const auto& input : framePass.GetInputs()) + { + std::size_t textureId = RegisterTexture(input.attachmentId); + + TextureData& attachmentData = m_pending.textures[textureId]; + attachmentData.usage |= TextureUsage::ShaderSampling; + } + + for (const auto& output : framePass.GetOutputs()) + { + std::size_t textureId = RegisterTexture(output.attachmentId); + + TextureData& attachmentData = m_pending.textures[textureId]; + attachmentData.usage |= TextureUsage::ColorAttachment; + } + + if (std::size_t depthStencilInput = framePass.GetDepthStencilInput(); depthStencilInput != FramePass::InvalidAttachmentId) + { + std::size_t textureId = RegisterTexture(depthStencilInput); + + TextureData& attachmentData = m_pending.textures[textureId]; + attachmentData.usage |= TextureUsage::DepthStencilAttachment; + + if (std::size_t depthStencilOutput = framePass.GetDepthStencilOutput(); depthStencilOutput != FramePass::InvalidAttachmentId) + { + if (auto it = m_pending.attachmentToTextures.find(depthStencilOutput); it == m_pending.attachmentToTextures.end()) + m_pending.attachmentToTextures.emplace(depthStencilOutput, textureId); + else if (it->second != textureId) + throw std::runtime_error("depth-stencil output already assigned"); + } + } + + if (std::size_t depthStencilOutput = framePass.GetDepthStencilOutput(); depthStencilOutput != FramePass::InvalidAttachmentId) + { + std::size_t textureId = RegisterTexture(depthStencilOutput); + + TextureData& attachmentData = m_pending.textures[textureId]; + attachmentData.usage |= TextureUsage::DepthStencilAttachment; + } + } + + // Add TextureUsage::Sampled to backbuffer output + + auto it = m_pending.attachmentToTextures.find(m_pending.backbufferResourceIndex); + assert(it != m_pending.attachmentToTextures.end()); + + auto& backbufferTexture = m_pending.textures[it->second]; + backbufferTexture.usage |= TextureUsage::ShaderSampling; + } + + void FrameGraph::BuildBarriers() + { + assert(m_pending.barrierList.empty()); + m_pending.barrierList.reserve(m_pending.passList.size()); + + auto GetBarrier = [&](std::vector& barriers, std::size_t attachmentId) -> Barrier& + { + std::size_t textureId = Retrieve(m_pending.attachmentToTextures, attachmentId); + + auto it = std::find_if(barriers.begin(), barriers.end(), [&](const Barrier& barrier) { return barrier.textureId == textureId; }); + if (it != barriers.end()) + return *it; + else + { + // Insert a new barrier + auto& barrier = barriers.emplace_back(); + barrier.textureId = textureId; + barrier.layout = TextureLayout::Undefined; + + return barrier; + } + + }; + + for (std::size_t passId : m_pending.passList) + { + const FramePass& framePass = m_framePasses[passId]; + + auto& barriers = m_pending.barrierList.emplace_back(); + + auto GetInvalidationBarrier = [&](std::size_t attachmentId) -> Barrier& { return GetBarrier(barriers.invalidationBarriers, attachmentId); }; + auto GetFlushBarrier = [&](std::size_t attachmentId) -> Barrier& { return GetBarrier(barriers.flushBarriers, attachmentId); }; + + for (const auto& input : framePass.GetInputs()) + { + auto& barrier = GetInvalidationBarrier(input.attachmentId); + if (barrier.layout != TextureLayout::Undefined) + throw std::runtime_error("layout mismatch"); + + barrier.access |= MemoryAccess::ColorRead | MemoryAccess::ColorWrite; + barrier.stages |= PipelineStage::ColorOutput; + barrier.layout = TextureLayout::ColorInput; + } + + for (const auto& output : framePass.GetOutputs()) + { + auto& barrier = GetFlushBarrier(output.attachmentId); + if (barrier.layout != TextureLayout::Undefined) + throw std::runtime_error("layout mismatch"); + + barrier.access |= MemoryAccess::ColorRead | MemoryAccess::ColorWrite; + barrier.stages |= PipelineStage::ColorOutput; + barrier.layout = TextureLayout::ColorOutput; + } + + std::size_t dsInputAttachment = framePass.GetDepthStencilInput(); + std::size_t dsOutputAttachement = framePass.GetDepthStencilOutput(); + bool depthRead = false; + + if (dsInputAttachment != FramePass::InvalidAttachmentId && dsOutputAttachement != FramePass::InvalidAttachmentId) + { + // DS input/output + auto& invalidationBarrier = GetInvalidationBarrier(dsInputAttachment); + if (invalidationBarrier.layout != TextureLayout::Undefined) + throw std::runtime_error("layout mismatch"); + + invalidationBarrier.layout = TextureLayout::DepthStencilReadWrite; + invalidationBarrier.access = MemoryAccess::DepthStencilRead | MemoryAccess::DepthStencilWrite; + invalidationBarrier.stages = PipelineStage::FragmentTestsEarly | PipelineStage::FragmentTestsLate; + + auto& flushBarrier = GetInvalidationBarrier(dsOutputAttachement); + flushBarrier.layout = TextureLayout::DepthStencilReadWrite; + flushBarrier.access = MemoryAccess::DepthStencilWrite; + flushBarrier.stages = PipelineStage::FragmentTestsLate; + } + else if (dsInputAttachment != FramePass::InvalidAttachmentId) + { + // DS input-only + auto& invalidationBarrier = GetInvalidationBarrier(dsInputAttachment); + if (invalidationBarrier.layout != TextureLayout::Undefined) + throw std::runtime_error("layout mismatch"); + + invalidationBarrier.layout = TextureLayout::DepthStencilReadWrite; + invalidationBarrier.access = MemoryAccess::DepthStencilRead; + invalidationBarrier.stages = PipelineStage::FragmentTestsEarly | PipelineStage::FragmentTestsLate; + } + else if (dsOutputAttachement != FramePass::InvalidAttachmentId) + { + // DS output-only + auto& flushBarrier = GetInvalidationBarrier(dsOutputAttachement); + if (flushBarrier.layout != TextureLayout::Undefined) + throw std::runtime_error("layout mismatch"); + + flushBarrier.layout = TextureLayout::DepthStencilReadWrite; + flushBarrier.access = MemoryAccess::DepthStencilWrite; + flushBarrier.stages = PipelineStage::FragmentTestsLate; + } + } + } + + void FrameGraph::BuildPhysicalBarriers() + { + struct TextureStates + { + MemoryAccessFlags invalidatedAccesses; + MemoryAccessFlags flushedAccesses; + PipelineStageFlags invalidatedStages; + PipelineStageFlags flushedStages; + TextureLayout initialLayout = TextureLayout::Undefined; + TextureLayout finalLayout = TextureLayout::Undefined; + }; + + std::vector textureStates; + + auto barriersIt = m_pending.barrierList.begin(); + for (auto& physicalPass : m_pending.physicalPasses) + { + textureStates.clear(); + textureStates.resize(m_pending.textures.size()); + + for (auto& subpass : physicalPass.passes) + { + auto& barriers = *barriersIt++; + + for (auto& invalidation : barriers.invalidationBarriers) + { + auto& states = textureStates[invalidation.textureId]; + if (states.initialLayout == TextureLayout::Undefined) + { + states.invalidatedAccesses |= invalidation.access; + states.invalidatedStages |= invalidation.stages; + states.initialLayout = invalidation.layout; + } + + states.finalLayout = invalidation.layout; + states.flushedAccesses = 0; + states.flushedStages = 0; + } + + for (auto& flush : barriers.flushBarriers) + { + auto& states = textureStates[flush.textureId]; + states.flushedAccesses |= flush.access; + states.flushedStages |= flush.stages; + states.finalLayout = flush.layout; + + if (states.initialLayout == TextureLayout::Undefined) + { + // First flush in a render pass needs a matching invalidation + states.initialLayout = flush.layout; + states.invalidatedAccesses = flush.access; + states.invalidatedStages = flush.stages; + + if (states.invalidatedAccesses & MemoryAccess::ColorWrite) + states.invalidatedAccesses |= MemoryAccess::ColorRead; + + if (states.invalidatedAccesses & MemoryAccess::DepthStencilWrite) + states.invalidatedAccesses |= MemoryAccess::DepthStencilRead; + + if (states.invalidatedAccesses & MemoryAccess::ShaderWrite) + states.invalidatedAccesses |= MemoryAccess::ShaderRead; + + // TODO: Discard resource + } + } + } + + + for (std::size_t textureId = 0; textureId < textureStates.size(); ++textureId) + { + const auto& state = textureStates[textureId]; + + if (state.initialLayout == TextureLayout::Undefined && state.finalLayout == TextureLayout::Undefined) + continue; //< Texture wasn't touched in this pass + + assert(state.finalLayout != TextureLayout::Undefined); + + // TODO: Register invalidation + + if (state.flushedAccesses) + ; // TODO: Register flush + + if (state.invalidatedAccesses) + ; // TODO: Register flush + } + } + } + + void FrameGraph::BuildPhysicalPassDependencies(std::size_t colorAttachmentCount, bool hasDepthStencilAttachment, std::vector& renderPassAttachments, std::vector& subpasses, std::vector& dependencies) + { + if (hasDepthStencilAttachment) + { + auto& depthStencilAttachment = renderPassAttachments[colorAttachmentCount]; + + if (PixelFormatInfo::GetContent(depthStencilAttachment.format) == PixelFormatContent::DepthStencil) + { + depthStencilAttachment.stencilLoadOp = depthStencilAttachment.loadOp; + depthStencilAttachment.stencilStoreOp = depthStencilAttachment.storeOp; + } + else + { + depthStencilAttachment.stencilLoadOp = AttachmentLoadOp::Discard; + depthStencilAttachment.stencilStoreOp = AttachmentStoreOp::Discard; + } + } + + struct SubpassInfo + { + bool hasColorWrite = false; + bool hasDepthStencilRead = false; + bool hasDepthStencilWrite = false; + bool externalColorSynchronization = false; + bool externalDepthSynchronization = false; + }; + + StackArray subpassInfo = NazaraStackArray(SubpassInfo, subpasses.size()); + + for (std::size_t attachmentIndex = 0; attachmentIndex < renderPassAttachments.size(); ++attachmentIndex) + { + bool used = false; //< has the attachment already been used in a previous subpass + TextureLayout currentLayout = renderPassAttachments[attachmentIndex].initialLayout; + + auto FindColor = [&](std::size_t subpassIndex) -> RenderPass::AttachmentReference* + { + auto& subpassDesc = subpasses[subpassIndex]; + for (auto& colorReference : subpassDesc.colorAttachment) + { + if (colorReference.attachmentIndex == attachmentIndex) + return &colorReference; + } + + return nullptr; + }; + + auto FindDepthStencil = [&](std::size_t subpassIndex) -> RenderPass::AttachmentReference* + { + auto& subpassDesc = subpasses[subpassIndex]; + if (subpassDesc.depthStencilAttachment && subpassDesc.depthStencilAttachment->attachmentIndex == attachmentIndex) + return &subpassDesc.depthStencilAttachment.value(); + + return nullptr; + }; + + for (std::size_t subpassIndex = 0; subpassIndex < subpasses.size(); ++subpassIndex) + { + RenderPass::SubpassDescription& subpassDesc = subpasses[subpassIndex]; + + RenderPass::AttachmentReference* colorAttachment = FindColor(subpassIndex); + RenderPass::AttachmentReference* depthStencilAttachment = FindDepthStencil(subpassIndex); + + if (!colorAttachment && !depthStencilAttachment) + { + if (used) + subpassDesc.preserveAttachments.push_back(attachmentIndex); + + continue; + } + + if (colorAttachment) + { + subpassInfo[subpassIndex].hasColorWrite = true; + + currentLayout = colorAttachment->attachmentLayout; + + // If this subpass performs a layout change, color must be synchronized with external + if (!used && renderPassAttachments[attachmentIndex].initialLayout != currentLayout) + subpassInfo[subpassIndex].externalColorSynchronization = true; + } + else if (depthStencilAttachment) + { + if (depthStencilAttachment->attachmentLayout == TextureLayout::DepthStencilReadWrite) + subpassInfo[subpassIndex].hasDepthStencilWrite = true; + + subpassInfo[subpassIndex].hasDepthStencilRead = true; + + currentLayout = depthStencilAttachment->attachmentLayout; + + // If this subpass performs a layout change, depth must be synchronized with external + if (!used && renderPassAttachments[attachmentIndex].initialLayout != currentLayout) + subpassInfo[subpassIndex].externalDepthSynchronization = true; + } + + used = true; + } + } + + // Handle external subpass dependencies + for (std::size_t subpassIndex = 0; subpassIndex < subpasses.size(); ++subpassIndex) + { + const auto& sync = subpassInfo[subpassIndex]; + if (!sync.externalColorSynchronization && !sync.externalDepthSynchronization) + continue; + + auto& subpassDependency = dependencies.emplace_back(); + subpassDependency.fromSubpassIndex = RenderPass::ExternalSubpassIndex; + subpassDependency.toSubpassIndex = subpassIndex; + + // TODO: Handle bottom of pipe? + + if (sync.externalColorSynchronization) + { + subpassDependency.fromStages |= PipelineStage::ColorOutput; + subpassDependency.fromAccessFlags |= MemoryAccess::ColorWrite; + + subpassDependency.toStages |= PipelineStage::ColorOutput; + subpassDependency.toAccessFlags |= MemoryAccess::ColorRead | MemoryAccess::ColorWrite; + } + + if (sync.externalDepthSynchronization) + { + subpassDependency.fromStages |= PipelineStage::FragmentTestsLate; + subpassDependency.fromAccessFlags |= MemoryAccess::DepthStencilWrite; + + subpassDependency.toStages |= PipelineStage::FragmentTestsEarly | PipelineStage::FragmentTestsLate; + subpassDependency.toAccessFlags |= MemoryAccess::DepthStencilRead | MemoryAccess::DepthStencilWrite; + } + } + + // TODO: Handle self-dependencies + + // Handle pass to pass dependencies + for (std::size_t subpassIndex = 1; subpassIndex < subpasses.size(); ++subpassIndex) + { + auto& subpassDependency = dependencies.emplace_back(); + subpassDependency.fromSubpassIndex = subpassIndex - 1; + subpassDependency.toSubpassIndex = subpassIndex; + subpassDependency.tilable = true; + + const auto& prevSync = subpassInfo[subpassDependency.fromSubpassIndex]; + const auto& sync = subpassInfo[subpassDependency.toSubpassIndex]; + + // Previous pass flags + + if (prevSync.hasColorWrite) + { + subpassDependency.fromAccessFlags = MemoryAccess::ColorWrite; + subpassDependency.fromStages = PipelineStage::ColorOutput; + } + + if (prevSync.hasDepthStencilRead) + { + subpassDependency.fromStages |= PipelineStage::FragmentTestsEarly | PipelineStage::FragmentTestsLate; + subpassDependency.fromAccessFlags |= MemoryAccess::DepthStencilRead; + } + + if (prevSync.hasDepthStencilWrite) + { + subpassDependency.fromStages |= PipelineStage::FragmentTestsEarly | PipelineStage::FragmentTestsLate; + subpassDependency.fromAccessFlags |= MemoryAccess::DepthStencilWrite; + } + + // Current pass flags + + if (sync.hasColorWrite) + { + subpassDependency.toStages = PipelineStage::ColorOutput; + subpassDependency.toAccessFlags = MemoryAccess::ColorRead | MemoryAccess::ColorWrite; + } + + if (sync.hasDepthStencilRead) + { + subpassDependency.toStages |= PipelineStage::FragmentTestsEarly | PipelineStage::FragmentTestsLate; + subpassDependency.toAccessFlags |= MemoryAccess::DepthStencilRead; + } + + if (sync.hasDepthStencilWrite) + { + subpassDependency.toStages |= PipelineStage::FragmentTestsEarly | PipelineStage::FragmentTestsLate; + subpassDependency.toAccessFlags |= MemoryAccess::DepthStencilRead | MemoryAccess::DepthStencilWrite; + } + + // TODO: Handle InputAttachment + } + } + + void FrameGraph::BuildPhysicalPasses() + { + const std::shared_ptr& renderDevice = Graphics::Instance()->GetRenderDevice(); + + std::unordered_map textureLayouts; + + std::size_t physicalPassIndex = 0; + for (auto& physicalPass : m_pending.physicalPasses) + { + std::unordered_map usedTextureAttachments; + std::size_t depthStencilAttachmentId; + std::optional depthStencilAttachmentIndex; + + std::vector renderPassAttachments; + std::vector subpassesDesc; + std::vector subpassesDeps; + + auto RegisterColorInput = [&](const FramePass::Input& input, PhysicalPassData::Subpass& subpass) + { + std::size_t textureId = Retrieve(m_pending.attachmentToTextures, input.attachmentId); + + auto it = textureLayouts.find(textureId); + assert(it != textureLayouts.end()); + + TextureLayout& textureLayout = it->second; + if (textureLayout != TextureLayout::ColorInput) + { + auto& transition = physicalPass.textureTransitions.emplace_back(); + transition.textureId = textureId; + + transition.srcAccessMask = MemoryAccess::ColorWrite; + transition.srcStageMask = PipelineStage::ColorOutput; + + transition.dstStageMask = PipelineStage::ColorOutput; + transition.dstAccessMask = MemoryAccess::ColorRead | MemoryAccess::ColorWrite; + + transition.oldLayout = textureLayout; + transition.newLayout = TextureLayout::ColorInput; + } + + textureLayout = TextureLayout::ColorInput; + }; + + auto RegisterColorOutput = [&](const FramePass::Output& output, bool shouldLoad) + { + std::size_t textureId = Retrieve(m_pending.attachmentToTextures, output.attachmentId); + + TextureLayout initialLayout = TextureLayout::Undefined; + auto layoutIt = textureLayouts.find(textureId); + if (layoutIt != textureLayouts.end()) + { + initialLayout = layoutIt->second; + layoutIt->second = TextureLayout::ColorOutput; + } + else + textureLayouts.emplace(textureId, TextureLayout::ColorOutput); + + auto it = usedTextureAttachments.find(textureId); + if (it != usedTextureAttachments.end()) + return it->second; + + std::size_t attachmentIndex = renderPassAttachments.size(); + auto& attachment = renderPassAttachments.emplace_back(); + attachment.format = m_pending.textures[textureId].format; + attachment.initialLayout = initialLayout; + attachment.storeOp = AttachmentStoreOp::Store; + attachment.stencilLoadOp = AttachmentLoadOp::Discard; + attachment.stencilStoreOp = AttachmentStoreOp::Discard; + + if (output.clearColor) + attachment.loadOp = AttachmentLoadOp::Clear; + else if (shouldLoad) + attachment.loadOp = AttachmentLoadOp::Load; + else + attachment.loadOp = AttachmentLoadOp::Discard; + + usedTextureAttachments.emplace(textureId, attachmentIndex); + return attachmentIndex; + }; + + auto RegisterDepthStencil = [&](std::size_t attachmentId, TextureLayout textureLayout, bool* first) -> RenderPass::Attachment& + { + if (depthStencilAttachmentIndex) + { + assert(depthStencilAttachmentId == attachmentId); + *first = false; + + return renderPassAttachments[depthStencilAttachmentIndex.value()]; + } + + *first = true; + + std::size_t textureId = Retrieve(m_pending.attachmentToTextures, attachmentId); + + TextureLayout initialLayout = TextureLayout::Undefined; + auto layoutIt = textureLayouts.find(textureId); + if (layoutIt != textureLayouts.end()) + { + initialLayout = layoutIt->second; + layoutIt->second = textureLayout; + } + else + textureLayouts.emplace(textureId, textureLayout); + + depthStencilAttachmentId = attachmentId; + depthStencilAttachmentIndex = renderPassAttachments.size(); + + usedTextureAttachments.emplace(textureId, *depthStencilAttachmentIndex); + + auto& depthStencilAttachment = renderPassAttachments.emplace_back(); + depthStencilAttachment.format = m_pending.textures[textureId].format; + depthStencilAttachment.initialLayout = initialLayout; + + return depthStencilAttachment; + }; + + std::size_t subpassIndex = 0; + + std::vector colorAttachments; + for (auto& subpass : physicalPass.passes) + { + const FramePass& framePass = m_framePasses[subpass.passIndex]; + const auto& subpassInputs = framePass.GetInputs(); + const auto& subpassOutputs = framePass.GetOutputs(); + + colorAttachments.reserve(subpassOutputs.size()); + + for (const auto& input : subpassInputs) + RegisterColorInput(input, subpass); + + for (const auto& output : subpassOutputs) + { + auto inputIt = std::find_if(subpassInputs.begin(), subpassInputs.end(), [&](const auto& input) { return input.attachmentId == output.attachmentId; }); + + std::size_t attachmentIndex = RegisterColorOutput(output, inputIt != subpassInputs.end()); + + colorAttachments.push_back({ + attachmentIndex, + TextureLayout::ColorOutput + }); + } + } + + std::size_t colorAttachmentCount = renderPassAttachments.size(); + + std::optional depthStencilAttachment; + for (auto& subpass : physicalPass.passes) + { + const FramePass& framePass = m_framePasses[subpass.passIndex]; + std::size_t dsInputAttachment = framePass.GetDepthStencilInput(); + std::size_t dsOutputAttachement = framePass.GetDepthStencilOutput(); + bool depthRead = false; + + if (dsInputAttachment != FramePass::InvalidAttachmentId && dsOutputAttachement != FramePass::InvalidAttachmentId) + { + // DS input/output + bool first; + auto& dsAttachment = RegisterDepthStencil(dsInputAttachment, TextureLayout::DepthStencilReadWrite, &first); + + if (first) + { + dsAttachment.loadOp = AttachmentLoadOp::Load; + dsAttachment.storeOp = AttachmentStoreOp::Store; + } + + depthStencilAttachment = RenderPass::AttachmentReference{ + depthStencilAttachmentIndex.value(), + TextureLayout::DepthStencilReadWrite + }; + } + else if (dsInputAttachment != FramePass::InvalidAttachmentId) + { + // DS input-only + bool first; + auto& dsAttachment = RegisterDepthStencil(dsInputAttachment, TextureLayout::DepthStencilReadOnly, &first); + + if (first) + { + // Check if a future pass reads from the DS buffer or if we can discard it after this pass + if (auto readIt = m_pending.attachmentReadList.find(dsInputAttachment); readIt != m_pending.attachmentReadList.end()) + { + for (std::size_t passIndex : readIt->second) + { + std::size_t readPhysicalPassIndex = Retrieve(m_pending.passIdToPhysicalPassIndex, passIndex); + if (readPhysicalPassIndex > physicalPassIndex) //< Read in a future pass? + { + // Yes, store it + dsAttachment.storeOp = AttachmentStoreOp::Store; + break; + } + } + } + } + + depthStencilAttachment = RenderPass::AttachmentReference{ + depthStencilAttachmentIndex.value(), + TextureLayout::DepthStencilReadOnly + }; + } + else if (dsOutputAttachement != FramePass::InvalidAttachmentId) + { + // DS output-only + bool first; + auto& dsAttachment = RegisterDepthStencil(dsOutputAttachement, TextureLayout::DepthStencilReadWrite, &first); + + if (first) + { + dsAttachment.initialLayout = TextureLayout::Undefined; //< Don't care about initial layout + dsAttachment.loadOp = (framePass.GetDepthStencilClear()) ? AttachmentLoadOp::Clear : AttachmentLoadOp::Discard; + dsAttachment.storeOp = AttachmentStoreOp::Store; + } + + depthStencilAttachment = RenderPass::AttachmentReference{ + depthStencilAttachmentIndex.value(), + TextureLayout::DepthStencilReadWrite + }; + } + + subpassesDesc.push_back({ + std::move(colorAttachments), + {}, + {}, + std::move(depthStencilAttachment) + }); + + subpassIndex++; + } + + // Assign final layout (TODO: Use this to perform layouts useful for future passes?) + for (const auto& [textureId, attachmentIndex] : usedTextureAttachments) + { + auto layoutIt = textureLayouts.find(textureId); + assert(layoutIt != textureLayouts.end()); + + auto& attachment = renderPassAttachments[attachmentIndex]; + attachment.finalLayout = layoutIt->second; + } + + BuildPhysicalPassDependencies(colorAttachmentCount, depthStencilAttachmentIndex.has_value(), renderPassAttachments, subpassesDesc, subpassesDeps); + + m_pending.renderPasses.push_back(renderDevice->InstantiateRenderPass(std::move(renderPassAttachments), std::move(subpassesDesc), std::move(subpassesDeps))); + + physicalPassIndex++; + } + } + + void FrameGraph::BuildReadWriteList() + { + for (std::size_t passIndex = 0; passIndex < m_framePasses.size(); ++passIndex) + { + const FramePass& framePass = m_framePasses[passIndex]; + + for (const auto& input : framePass.GetInputs()) + UniquePushBack(m_pending.attachmentReadList[input.attachmentId], passIndex); + + if (std::size_t depthStencilId = framePass.GetDepthStencilInput(); depthStencilId != FramePass::InvalidAttachmentId) + UniquePushBack(m_pending.attachmentReadList[depthStencilId], passIndex); + + for (const auto& output : framePass.GetOutputs()) + UniquePushBack(m_pending.attachmentWriteList[output.attachmentId], passIndex); + + if (std::size_t depthStencilId = framePass.GetDepthStencilOutput(); depthStencilId != FramePass::InvalidAttachmentId) + UniquePushBack(m_pending.attachmentWriteList[depthStencilId], passIndex); + } + } + + void FrameGraph::ReorderPasses() + { + /* TODO */ + } + + void FrameGraph::TraverseGraph(std::size_t passIndex) + { + m_pending.passList.push_back(passIndex); + + const FramePass& framePass = m_framePasses[passIndex]; + for (const auto& input : framePass.GetInputs()) + { + auto it = m_pending.attachmentWriteList.find(input.attachmentId); + if (it != m_pending.attachmentWriteList.end()) + { + const PassList& dependencyPassList = it->second; + for (std::size_t dependencyPass : dependencyPassList) + { + if (dependencyPass != passIndex) + TraverseGraph(dependencyPass); + } + } + } + } + + void FrameGraph::RemoveDuplicatePasses() + { + // A way to remove duplicates from a std::vector without sorting it + std::unordered_set seen; + + auto itRead = m_pending.passList.begin(); + auto itWrite = m_pending.passList.begin(); + + while (itRead != m_pending.passList.end()) + { + std::size_t passIndex = *itRead; + if (seen.find(passIndex) == seen.end()) + { + seen.insert(passIndex); + + if (itRead != itWrite) + *itWrite++ = passIndex; + else + ++itWrite; + } + + ++itRead; + } + + m_pending.passList.erase(itWrite, m_pending.passList.end()); + } +} diff --git a/src/Nazara/Graphics/FramePass.cpp b/src/Nazara/Graphics/FramePass.cpp new file mode 100644 index 000000000..942a9e358 --- /dev/null +++ b/src/Nazara/Graphics/FramePass.cpp @@ -0,0 +1,10 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ +} diff --git a/src/Nazara/Graphics/FramePassAttachment.cpp b/src/Nazara/Graphics/FramePassAttachment.cpp new file mode 100644 index 000000000..9c8da8708 --- /dev/null +++ b/src/Nazara/Graphics/FramePassAttachment.cpp @@ -0,0 +1,10 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ +} diff --git a/src/Nazara/Graphics/GraphicalMesh.cpp b/src/Nazara/Graphics/GraphicalMesh.cpp new file mode 100644 index 000000000..278ab885a --- /dev/null +++ b/src/Nazara/Graphics/GraphicalMesh.cpp @@ -0,0 +1,56 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + GraphicalMesh::GraphicalMesh(const Mesh& mesh) + { + assert(mesh.GetAnimationType() == AnimationType::Static); + + const std::shared_ptr& renderDevice = Graphics::Instance()->GetRenderDevice(); + + m_subMeshes.reserve(mesh.GetSubMeshCount()); + for (std::size_t i = 0; i < mesh.GetSubMeshCount(); ++i) + { + const SubMesh& subMesh = *mesh.GetSubMesh(i); + + const StaticMesh& staticMesh = static_cast(subMesh); + + const std::shared_ptr& indexBuffer = staticMesh.GetIndexBuffer(); + const std::shared_ptr& vertexBuffer = staticMesh.GetVertexBuffer(); + + assert(indexBuffer->GetBuffer()->GetStorage() == DataStorage::Software); + const SoftwareBuffer* indexBufferContent = static_cast(indexBuffer->GetBuffer()->GetImpl()); + + assert(vertexBuffer->GetBuffer()->GetStorage() == DataStorage::Software); + const SoftwareBuffer* vertexBufferContent = static_cast(vertexBuffer->GetBuffer()->GetImpl()); + + auto& submeshData = m_subMeshes.emplace_back(); + submeshData.indexBuffer = renderDevice->InstantiateBuffer(BufferType::Index); + if (!submeshData.indexBuffer->Initialize(indexBuffer->GetStride() * indexBuffer->GetIndexCount(), BufferUsage::DeviceLocal)) + throw std::runtime_error("failed to create index buffer"); + + if (!submeshData.indexBuffer->Fill(indexBufferContent->GetData() + indexBuffer->GetStartOffset(), 0, indexBuffer->GetEndOffset() - indexBuffer->GetStartOffset())) + throw std::runtime_error("failed to fill index buffer"); + + submeshData.indexCount = indexBuffer->GetIndexCount(); + + submeshData.vertexBuffer = renderDevice->InstantiateBuffer(BufferType::Vertex); + if (!submeshData.vertexBuffer->Initialize(vertexBuffer->GetStride() * vertexBuffer->GetVertexCount(), BufferUsage::DeviceLocal)) + throw std::runtime_error("failed to create vertex buffer"); + + if (!submeshData.vertexBuffer->Fill(vertexBufferContent->GetData() + vertexBuffer->GetStartOffset(), 0, vertexBuffer->GetEndOffset() - vertexBuffer->GetStartOffset())) + throw std::runtime_error("failed to fill vertex buffer"); + + submeshData.vertexDeclaration = vertexBuffer->GetVertexDeclaration(); + } + } +} diff --git a/src/Nazara/Graphics/Graphics.cpp b/src/Nazara/Graphics/Graphics.cpp index b2ac1d928..433df28ef 100644 --- a/src/Nazara/Graphics/Graphics.cpp +++ b/src/Nazara/Graphics/Graphics.cpp @@ -3,6 +3,9 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include +#include +#include #include namespace Nz @@ -10,16 +13,51 @@ namespace Nz /*! * \ingroup graphics * \class Nz::Graphics - * \brief Audio class that represents the module initializer of Graphics + * \brief Graphics class that represents the module initializer of Graphics */ - - Graphics::Graphics(Config /*config*/) : + Graphics::Graphics(Config config) : ModuleBase("Graphics", this) { + Renderer* renderer = Renderer::Instance(); + + const std::vector& renderDeviceInfo = renderer->QueryRenderDevices(); + if (renderDeviceInfo.empty()) + throw std::runtime_error("no render device available"); + + std::size_t bestRenderDeviceIndex = 0; + for (std::size_t i = 0; i < renderDeviceInfo.size(); ++i) + { + const auto& deviceInfo = renderDeviceInfo[i]; + if (config.useDedicatedRenderDevice && deviceInfo.type == RenderDeviceType::Dedicated) + { + bestRenderDeviceIndex = i; + break; + } + else if (!config.useDedicatedRenderDevice && deviceInfo.type == RenderDeviceType::Integrated) + { + bestRenderDeviceIndex = i; + break; + } + } + + m_renderDevice = renderer->InstanciateRenderDevice(bestRenderDeviceIndex); + if (!m_renderDevice) + throw std::runtime_error("failed to instantiate render device"); + + m_samplerCache.emplace(m_renderDevice); + + MaterialPipeline::Initialize(); + + Nz::PredefinedViewerData viewerUboOffsets = Nz::PredefinedViewerData::GetOffsets(); + + m_viewerDataUBO = m_renderDevice->InstantiateBuffer(Nz::BufferType::Uniform); + if (!m_viewerDataUBO->Initialize(viewerUboOffsets.totalSize, Nz::BufferUsage::DeviceLocal | Nz::BufferUsage::Dynamic)) + throw std::runtime_error("failed to initialize viewer data UBO"); } Graphics::~Graphics() { + MaterialPipeline::Uninitialize(); } Graphics* Graphics::s_instance = nullptr; diff --git a/src/Nazara/Graphics/Material.cpp b/src/Nazara/Graphics/Material.cpp new file mode 100644 index 000000000..b2319269c --- /dev/null +++ b/src/Nazara/Graphics/Material.cpp @@ -0,0 +1,116 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + /*! + * \ingroup graphics + * \class Nz::Material + * \brief Graphics class that represents a material + */ + + /*! + * \brief Constructs a Material object with default states + * + * \see Reset + */ + Material::Material(std::shared_ptr settings) : + m_settings(std::move(settings)), + m_enabledConditions(0), + m_pipelineUpdated(false), + m_shadowCastingEnabled(true) + { + m_pipelineInfo.settings = m_settings; + + const auto& shaders = m_settings->GetShaders(); + for (std::size_t i = 0; i < ShaderStageTypeCount; ++i) + m_pipelineInfo.shaders[i].uberShader = shaders[i]; + + m_textures.resize(m_settings->GetTextures().size()); + + m_uniformBuffers.reserve(m_settings->GetUniformBlocks().size()); + for (const auto& uniformBufferInfo : m_settings->GetUniformBlocks()) + { + auto& uniformBuffer = m_uniformBuffers.emplace_back(); + + uniformBuffer.buffer = Graphics::Instance()->GetRenderDevice()->InstantiateBuffer(Nz::BufferType::Uniform); + if (!uniformBuffer.buffer->Initialize(uniformBufferInfo.blockSize, BufferUsage::Dynamic)) + throw std::runtime_error("failed to initialize UBO memory"); + + assert(uniformBufferInfo.defaultValues.size() <= uniformBufferInfo.blockSize); + + uniformBuffer.buffer->Fill(uniformBufferInfo.defaultValues.data(), 0, uniformBufferInfo.defaultValues.size()); + uniformBuffer.data.resize(uniformBufferInfo.blockSize); + std::memcpy(uniformBuffer.data.data(), uniformBufferInfo.defaultValues.data(), uniformBufferInfo.defaultValues.size()); + } + } + + void Material::UpdateBuffers(UploadPool& uploadPool, CommandBufferBuilder& builder) + { + for (auto& ubo : m_uniformBuffers) + { + if (ubo.dataInvalidated) + { + auto& allocation = uploadPool.Allocate(ubo.data.size()); + std::memcpy(allocation.mappedPtr, ubo.data.data(), ubo.data.size()); + + builder.CopyBuffer(allocation, ubo.buffer.get()); + + ubo.dataInvalidated = false; + } + } + } + + void Material::UpdateShaderBinding(ShaderBinding& shaderBinding) const + { + // TODO: Use StackVector + std::vector bindings; + + + std::size_t bindingIndex = 0; + + for (const auto& textureSlot : m_textures) + { + if (!textureSlot.sampler) + { + TextureSamplerCache& samplerCache = Graphics::Instance()->GetSamplerCache(); + textureSlot.sampler = samplerCache.Get(textureSlot.samplerInfo); + } + + //TODO: Use "missing" texture + if (textureSlot.texture) + { + bindings.push_back({ + bindingIndex, + ShaderBinding::TextureBinding { + textureSlot.texture.get(), textureSlot.sampler.get() + } + }); + } + + bindingIndex++; + } + + for (const auto& ubo : m_uniformBuffers) + { + bindings.push_back({ + bindingIndex++, + ShaderBinding::UniformBufferBinding { + ubo.buffer.get(), 0, ubo.buffer->GetSize() + } + }); + } + + shaderBinding.Update(bindings.data(), bindings.size()); + } +} diff --git a/src/Nazara/Graphics/MaterialPipeline.cpp b/src/Nazara/Graphics/MaterialPipeline.cpp new file mode 100644 index 000000000..a713ac4b5 --- /dev/null +++ b/src/Nazara/Graphics/MaterialPipeline.cpp @@ -0,0 +1,93 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + /*! + * \ingroup graphics + * \class Nz::MaterialPipeline + * + * \brief Graphics class used to contains all rendering states that are not allowed to change individually on rendering devices + */ + + /*! + * \brief Retrieve (and generate if required) a pipeline instance using shader flags without applying it + * + * \param flags Shader flags + * + * \return Pipeline instance + */ + const std::shared_ptr& MaterialPipeline::GetRenderPipeline(const std::vector& vertexBuffers) const + { + for (const auto& pipeline : m_renderPipelines) + { + const auto& pipelineInfo = pipeline->GetPipelineInfo(); + + bool isEqual = std::equal(pipelineInfo.vertexBuffers.begin(), pipelineInfo.vertexBuffers.end(), vertexBuffers.begin(), [](const auto& v1, const auto& v2) + { + return v1.binding == v2.binding && v1.declaration == v2.declaration; + }); + + if (isEqual) + return pipeline; + } + + RenderPipelineInfo renderPipelineInfo; + static_cast(renderPipelineInfo).operator=(m_pipelineInfo); // Not my proudest line + + renderPipelineInfo.pipelineLayout = m_pipelineInfo.settings->GetRenderPipelineLayout(); + + for (const auto& shaderEntry : m_pipelineInfo.shaders) + { + if (shaderEntry.uberShader) + renderPipelineInfo.shaderModules.push_back(shaderEntry.uberShader->Get(shaderEntry.enabledConditions)); + } + + renderPipelineInfo.vertexBuffers = vertexBuffers; + + return m_renderPipelines.emplace_back(Graphics::Instance()->GetRenderDevice()->InstantiateRenderPipeline(std::move(renderPipelineInfo))); + } + /*! + * \brief Returns a reference to a MaterialPipeline built with MaterialPipelineInfo + * + * This function is using a cache, calling it multiples times with the same MaterialPipelineInfo will returns references to a single MaterialPipeline + * + * \param pipelineInfo Pipeline informations used to build/retrieve a MaterialPipeline object + */ + const std::shared_ptr& MaterialPipeline::Get(const MaterialPipelineInfo& pipelineInfo) + { + auto it = s_pipelineCache.find(pipelineInfo); + if (it == s_pipelineCache.end()) + it = s_pipelineCache.insert(it, PipelineCache::value_type(pipelineInfo, std::make_shared(pipelineInfo, Token{}))); + + return it->second; + } + + bool MaterialPipeline::Initialize() + { + BasicMaterial::Initialize(); + PhongLightingMaterial::Initialize(); + + return true; + } + + void MaterialPipeline::Uninitialize() + { + s_pipelineCache.clear(); + PhongLightingMaterial::Uninitialize(); + BasicMaterial::Uninitialize(); + } + + MaterialPipeline::PipelineCache MaterialPipeline::s_pipelineCache; +} diff --git a/src/Nazara/Graphics/Model.cpp b/src/Nazara/Graphics/Model.cpp new file mode 100644 index 000000000..f921725e7 --- /dev/null +++ b/src/Nazara/Graphics/Model.cpp @@ -0,0 +1,51 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include + +namespace Nz +{ + Model::Model(std::shared_ptr graphicalMesh) : + m_graphicalMesh(std::move(graphicalMesh)) + { + m_subMeshes.reserve(m_graphicalMesh->GetSubMeshCount()); + for (std::size_t i = 0; i < m_graphicalMesh->GetSubMeshCount(); ++i) + { + auto& subMeshData = m_subMeshes.emplace_back(); + //subMeshData.material = DefaultMaterial; //< TODO + subMeshData.vertexBufferData = { + { + 0, + m_graphicalMesh->GetVertexDeclaration(i) + } + }; + } + } + + const std::shared_ptr& Model::GetIndexBuffer(std::size_t subMeshIndex) const + { + return m_graphicalMesh->GetIndexBuffer(subMeshIndex); + } + + std::size_t Model::GetIndexCount(std::size_t subMeshIndex) const + { + return m_graphicalMesh->GetIndexCount(subMeshIndex); + } + + const std::shared_ptr& Model::GetRenderPipeline(std::size_t subMeshIndex) const + { + assert(subMeshIndex < m_subMeshes.size()); + const auto& subMeshData = m_subMeshes[subMeshIndex]; + return subMeshData.material->GetPipeline()->GetRenderPipeline(subMeshData.vertexBufferData); + } + + const std::shared_ptr& Model::GetVertexBuffer(std::size_t subMeshIndex) const + { + return m_graphicalMesh->GetVertexBuffer(subMeshIndex); + } + +} diff --git a/src/Nazara/Graphics/ModelInstance.cpp b/src/Nazara/Graphics/ModelInstance.cpp new file mode 100644 index 000000000..33fa75bf4 --- /dev/null +++ b/src/Nazara/Graphics/ModelInstance.cpp @@ -0,0 +1,51 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + ModelInstance::ModelInstance(const std::shared_ptr& settings) + { + Nz::PredefinedInstanceData instanceUboOffsets = Nz::PredefinedInstanceData::GetOffsets(); + + m_instanceDataBuffer = Graphics::Instance()->GetRenderDevice()->InstantiateBuffer(BufferType::Uniform); + if (!m_instanceDataBuffer->Initialize(instanceUboOffsets.totalSize, Nz::BufferUsage::DeviceLocal | Nz::BufferUsage::Dynamic)) + throw std::runtime_error("failed to initialize viewer data UBO"); + + m_shaderBinding = settings->GetRenderPipelineLayout()->AllocateShaderBinding(); + + StackVector bindings = NazaraStackVector(ShaderBinding::Binding, 2); + + if (std::size_t bindingIndex = settings->GetPredefinedBindingIndex(PredefinedShaderBinding::UboInstanceData); bindingIndex != MaterialSettings::InvalidIndex) + { + bindings.push_back({ + bindingIndex, + ShaderBinding::UniformBufferBinding { + m_instanceDataBuffer.get(), 0, m_instanceDataBuffer->GetSize() + } + }); + } + + if (std::size_t bindingIndex = settings->GetPredefinedBindingIndex(PredefinedShaderBinding::UboViewerData); bindingIndex != MaterialSettings::InvalidIndex) + { + const std::shared_ptr& instanceDataUBO = Graphics::Instance()->GetViewerDataUBO(); + + bindings.push_back({ + bindingIndex, + ShaderBinding::UniformBufferBinding { + instanceDataUBO.get(), 0, instanceDataUBO->GetSize() + } + }); + } + + if (!bindings.empty()) + m_shaderBinding->Update(bindings.data(), bindings.size()); + } +} diff --git a/src/Nazara/Graphics/PhongLightingMaterial.cpp b/src/Nazara/Graphics/PhongLightingMaterial.cpp new file mode 100644 index 000000000..f5ac9bda4 --- /dev/null +++ b/src/Nazara/Graphics/PhongLightingMaterial.cpp @@ -0,0 +1,269 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + PhongLightingMaterial::PhongLightingMaterial(Material& material) : + m_material(material) + { + // Most common case: don't fetch texture indexes as a little optimization + const std::shared_ptr& materialSettings = m_material.GetSettings(); + if (materialSettings == s_materialSettings) + { + m_textureIndexes = s_textureIndexes; + m_phongUniformIndex = s_phongUniformBlockIndex; + m_phongUniformOffsets = s_phongUniformOffsets; + } + else + { + m_textureIndexes.alpha = materialSettings->GetTextureIndex("Alpha"); + m_textureIndexes.diffuse = materialSettings->GetTextureIndex("Diffuse"); + m_textureIndexes.emissive = materialSettings->GetTextureIndex("Emissive"); + m_textureIndexes.height = materialSettings->GetTextureIndex("Height"); + m_textureIndexes.normal = materialSettings->GetTextureIndex("Normal"); + m_textureIndexes.specular = materialSettings->GetTextureIndex("Specular"); + + m_phongUniformIndex = materialSettings->GetUniformBlockIndex("PhongSettings"); + + m_phongUniformOffsets.alphaThreshold = materialSettings->GetUniformBlockVariableOffset(m_phongUniformIndex, "AlphaThreshold"); + m_phongUniformOffsets.ambientColor = materialSettings->GetUniformBlockVariableOffset(m_phongUniformIndex, "AmbientColor"); + m_phongUniformOffsets.diffuseColor = materialSettings->GetUniformBlockVariableOffset(m_phongUniformIndex, "DiffuseColor"); + m_phongUniformOffsets.shininess = materialSettings->GetUniformBlockVariableOffset(m_phongUniformIndex, "Shininess"); + m_phongUniformOffsets.specularColor = materialSettings->GetUniformBlockVariableOffset(m_phongUniformIndex, "SpecularColor"); + } + } + + float PhongLightingMaterial::GetAlphaThreshold() const + { + NazaraAssert(HasAlphaThreshold(), "Material has no alpha threshold uniform"); + + const std::vector& bufferData = m_material.GetUniformBufferConstData(m_phongUniformIndex); + return AccessByOffset(bufferData.data(), m_phongUniformOffsets.alphaThreshold); + } + + Color PhongLightingMaterial::GetAmbientColor() const + { + NazaraAssert(HasAmbientColor(), "Material has no ambient color uniform"); + + const std::vector& bufferData = m_material.GetUniformBufferConstData(m_phongUniformIndex); + + const float* colorPtr = AccessByOffset(bufferData.data(), m_phongUniformOffsets.ambientColor); + return Color(colorPtr[0] * 255, colorPtr[1] * 255, colorPtr[2] * 255, colorPtr[3] * 255); //< TODO: Make color able to use float + } + + Color PhongLightingMaterial::GetDiffuseColor() const + { + NazaraAssert(HasDiffuseColor(), "Material has no diffuse color uniform"); + + const std::vector& bufferData = m_material.GetUniformBufferConstData(m_phongUniformIndex); + + const float* colorPtr = AccessByOffset(bufferData.data(), m_phongUniformOffsets.diffuseColor); + return Color(colorPtr[0] * 255, colorPtr[1] * 255, colorPtr[2] * 255, colorPtr[3] * 255); //< TODO: Make color able to use float + } + + float Nz::PhongLightingMaterial::GetShininess() const + { + NazaraAssert(HasShininess(), "Material has no shininess uniform"); + + const std::vector& bufferData = m_material.GetUniformBufferConstData(m_phongUniformIndex); + return AccessByOffset(bufferData.data(), m_phongUniformOffsets.shininess); + } + + Color PhongLightingMaterial::GetSpecularColor() const + { + NazaraAssert(HasSpecularColor(), "Material has no specular color uniform"); + + const std::vector& bufferData = m_material.GetUniformBufferConstData(m_phongUniformIndex); + + const float* colorPtr = AccessByOffset(bufferData.data(), m_phongUniformOffsets.specularColor); + return Color(colorPtr[0] * 255, colorPtr[1] * 255, colorPtr[2] * 255, colorPtr[3] * 255); //< TODO: Make color able to use float + } + + void PhongLightingMaterial::SetAlphaThreshold(float alphaThreshold) + { + NazaraAssert(HasAlphaThreshold(), "Material has no alpha threshold uniform"); + + std::vector& bufferData = m_material.GetUniformBufferData(m_phongUniformIndex); + AccessByOffset(bufferData.data(), m_phongUniformOffsets.alphaThreshold) = alphaThreshold; + } + + void PhongLightingMaterial::SetAmbientColor(const Color& ambient) + { + NazaraAssert(HasAmbientColor(), "Material has no ambient color uniform"); + + std::vector& bufferData = m_material.GetUniformBufferData(m_phongUniformIndex); + float* colorPtr = AccessByOffset(bufferData.data(), m_phongUniformOffsets.ambientColor); + colorPtr[0] = ambient.r / 255.f; + colorPtr[1] = ambient.g / 255.f; + colorPtr[2] = ambient.b / 255.f; + colorPtr[3] = ambient.a / 255.f; + } + + void PhongLightingMaterial::SetDiffuseColor(const Color& diffuse) + { + NazaraAssert(HasDiffuseColor(), "Material has no diffuse color uniform"); + + std::vector& bufferData = m_material.GetUniformBufferData(m_phongUniformIndex); + float* colorPtr = AccessByOffset(bufferData.data(), m_phongUniformOffsets.diffuseColor); + colorPtr[0] = diffuse.r / 255.f; + colorPtr[1] = diffuse.g / 255.f; + colorPtr[2] = diffuse.b / 255.f; + colorPtr[3] = diffuse.a / 255.f; + } + + void PhongLightingMaterial::SetSpecularColor(const Color& diffuse) + { + NazaraAssert(HasSpecularColor(), "Material has no specular color uniform"); + + std::vector& bufferData = m_material.GetUniformBufferData(m_phongUniformIndex); + float* colorPtr = AccessByOffset(bufferData.data(), m_phongUniformOffsets.specularColor); + colorPtr[0] = diffuse.r / 255.f; + colorPtr[1] = diffuse.g / 255.f; + colorPtr[2] = diffuse.b / 255.f; + colorPtr[3] = diffuse.a / 255.f; + } + + const std::shared_ptr& PhongLightingMaterial::GetSettings() + { + return s_materialSettings; + } + + bool PhongLightingMaterial::Initialize() + { + // MaterialPhongSettings + FieldOffsets phongUniformStruct(StructLayout::Std140); + + s_phongUniformOffsets.alphaThreshold = phongUniformStruct.AddField(StructFieldType::Float1); + s_phongUniformOffsets.shininess = phongUniformStruct.AddField(StructFieldType::Float1); + s_phongUniformOffsets.ambientColor = phongUniformStruct.AddField(StructFieldType::Float4); + s_phongUniformOffsets.diffuseColor = phongUniformStruct.AddField(StructFieldType::Float4); + s_phongUniformOffsets.specularColor = phongUniformStruct.AddField(StructFieldType::Float4); + + MaterialSettings::Builder settings; + settings.predefinedBinding.fill(MaterialSettings::InvalidIndex); + + std::vector phongVariables; + phongVariables.assign({ + { + "AlphaThreshold", + s_phongUniformOffsets.alphaThreshold + }, + { + "Shininess", + s_phongUniformOffsets.shininess + }, + { + "AmbientColor", + s_phongUniformOffsets.ambientColor + }, + { + "DiffuseColor", + s_phongUniformOffsets.diffuseColor + }, + { + "SpecularColor", + s_phongUniformOffsets.specularColor + } + }); + + static_assert(sizeof(Vector4f) == 4 * sizeof(float), "Vector4f is expected to be exactly 4 floats wide"); + + std::vector defaultValues(phongUniformStruct.GetSize()); + AccessByOffset(defaultValues.data(), s_phongUniformOffsets.ambientColor) = Vector4f(0.5f, 0.5f, 0.5f, 1.f); + AccessByOffset(defaultValues.data(), s_phongUniformOffsets.diffuseColor) = Vector4f(1.f, 1.f, 1.f, 1.f); + AccessByOffset(defaultValues.data(), s_phongUniformOffsets.specularColor) = Vector4f(1.f, 1.f, 1.f, 1.f); + AccessByOffset(defaultValues.data(), s_phongUniformOffsets.alphaThreshold) = 0.2f; + AccessByOffset(defaultValues.data(), s_phongUniformOffsets.shininess) = 50.f; + + s_phongUniformBlockIndex = settings.uniformBlocks.size(); + settings.uniformBlocks.push_back({ + phongUniformStruct.GetSize(), + "PhongSettings", + "MaterialPhongSettings", + std::move(phongVariables), + std::move(defaultValues) + }); + + settings.predefinedBinding[UnderlyingCast(PredefinedShaderBinding::UboInstanceData)] = settings.sharedUniformBlocks.size(); + settings.sharedUniformBlocks.push_back(PredefinedInstanceData::GetUniformBlock()); + settings.predefinedBinding[UnderlyingCast(PredefinedShaderBinding::UboLighData)] = settings.sharedUniformBlocks.size(); + settings.sharedUniformBlocks.push_back(PredefinedLightData::GetUniformBlock()); + settings.predefinedBinding[UnderlyingCast(PredefinedShaderBinding::UboViewerData)] = settings.sharedUniformBlocks.size(); + settings.sharedUniformBlocks.push_back(PredefinedViewerData::GetUniformBlock()); + + s_textureIndexes.alpha = settings.textures.size(); + settings.textures.push_back({ + "MaterialAlphaMap", + "Alpha", + ImageType::E2D + }); + + s_textureIndexes.diffuse = settings.textures.size(); + settings.textures.push_back({ + "MaterialDiffuseMap", + "Diffuse", + ImageType::E2D + }); + + s_textureIndexes.emissive = settings.textures.size(); + settings.textures.push_back({ + "MaterialEmissiveMap", + "Emissive", + ImageType::E2D + }); + + s_textureIndexes.height = settings.textures.size(); + settings.textures.push_back({ + "MaterialHeightMap", + "Height", + ImageType::E2D + }); + + s_textureIndexes.normal = settings.textures.size(); + settings.textures.push_back({ + "MaterialNormalMap", + "Normal", + ImageType::E2D + }); + + s_textureIndexes.specular = settings.textures.size(); + settings.textures.push_back({ + "MaterialSpecularMap", + "Specular", + ImageType::E2D + }); + + settings.predefinedBinding[UnderlyingCast(PredefinedShaderBinding::TexOverlay)] = settings.textures.size(); + settings.textures.push_back({ + "TextureOverlay", + "Overlay", + ImageType::E2D, + }); + + s_materialSettings = std::make_shared(std::move(settings)); + + return true; + } + + void PhongLightingMaterial::Uninitialize() + { + s_materialSettings.reset(); + } + + std::shared_ptr PhongLightingMaterial::s_materialSettings; + std::size_t PhongLightingMaterial::s_phongUniformBlockIndex; + PhongLightingMaterial::TextureIndexes PhongLightingMaterial::s_textureIndexes; + PhongLightingMaterial::PhongUniformOffsets PhongLightingMaterial::s_phongUniformOffsets; +} diff --git a/src/Nazara/Graphics/PredefinedShaderStructs.cpp b/src/Nazara/Graphics/PredefinedShaderStructs.cpp new file mode 100644 index 000000000..a781617b5 --- /dev/null +++ b/src/Nazara/Graphics/PredefinedShaderStructs.cpp @@ -0,0 +1,167 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + PredefinedLightData PredefinedLightData::GetOffset() + { + PredefinedLightData lightData; + + FieldOffsets lightStruct(StructLayout::Std140); + lightData.innerOffsets.type = lightStruct.AddField(StructFieldType::Int1); + lightData.innerOffsets.color = lightStruct.AddField(StructFieldType::Float4); + lightData.innerOffsets.factor = lightStruct.AddField(StructFieldType::Float2); + lightData.innerOffsets.parameter1 = lightStruct.AddField(StructFieldType::Float4); + lightData.innerOffsets.parameter2 = lightStruct.AddField(StructFieldType::Float4); + lightData.innerOffsets.parameter3 = lightStruct.AddField(StructFieldType::Float2); + lightData.innerOffsets.shadowMappingFlag = lightStruct.AddField(StructFieldType::Bool1); + + lightData.innerOffsets.totalSize = lightStruct.GetAlignedSize(); + + FieldOffsets lightDataStruct(StructLayout::Std140); + for (std::size_t& lightOffset : lightData.lightArray) + lightOffset = lightDataStruct.AddStruct(lightStruct); + + lightData.lightArraySize = lightDataStruct.GetAlignedSize(); + + return lightData; + } + + MaterialSettings::SharedUniformBlock PredefinedLightData::GetUniformBlock() + { + PredefinedLightData lightData = GetOffset(); + + std::vector lightDataVariables; + for (std::size_t i = 0; i < lightData.lightArray.size(); ++i) + { + lightDataVariables.push_back({ + "LightData[" + std::to_string(i) + "]", + lightData.lightArray[i] + }); + } + + MaterialSettings::SharedUniformBlock uniformBlock = { + "Light", + "LightData", + std::move(lightDataVariables) + }; + + return uniformBlock; + } + + PredefinedInstanceData PredefinedInstanceData::GetOffsets() + { + FieldOffsets viewerStruct(StructLayout::Std140); + + PredefinedInstanceData instanceData; + instanceData.worldMatrixOffset = viewerStruct.AddMatrix(StructFieldType::Float1, 4, 4, true); + instanceData.invWorldMatrixOffset = viewerStruct.AddMatrix(StructFieldType::Float1, 4, 4, true); + + instanceData.totalSize = viewerStruct.GetAlignedSize(); + + return instanceData; + } + + MaterialSettings::SharedUniformBlock PredefinedInstanceData::GetUniformBlock() + { + PredefinedInstanceData instanceData = GetOffsets(); + + std::vector instanceDataVariables; + instanceDataVariables.assign({ + { + "WorldMatrix", + instanceData.worldMatrixOffset + }, + { + "InvWorldMatrix", + instanceData.invWorldMatrixOffset + }, + }); + + MaterialSettings::SharedUniformBlock uniformBlock = { + "Instance", + "InstanceData", + std::move(instanceDataVariables) + }; + + return uniformBlock; + } + + PredefinedViewerData PredefinedViewerData::GetOffsets() + { + FieldOffsets viewerStruct(StructLayout::Std140); + + PredefinedViewerData viewerData; + viewerData.projMatrixOffset = viewerStruct.AddMatrix(StructFieldType::Float1, 4, 4, true); + viewerData.invProjMatrixOffset = viewerStruct.AddMatrix(StructFieldType::Float1, 4, 4, true); + viewerData.viewMatrixOffset = viewerStruct.AddMatrix(StructFieldType::Float1, 4, 4, true); + viewerData.invViewMatrixOffset = viewerStruct.AddMatrix(StructFieldType::Float1, 4, 4, true); + viewerData.viewProjMatrixOffset = viewerStruct.AddMatrix(StructFieldType::Float1, 4, 4, true); + viewerData.invViewProjMatrixOffset = viewerStruct.AddMatrix(StructFieldType::Float1, 4, 4, true); + viewerData.targetSizeOffset = viewerStruct.AddField(StructFieldType::Float2); + viewerData.invTargetSizeOffset = viewerStruct.AddField(StructFieldType::Float2); + viewerData.eyePositionOffset = viewerStruct.AddField(StructFieldType::Float3); + + viewerData.totalSize = viewerStruct.GetAlignedSize(); + + return viewerData; + } + + MaterialSettings::SharedUniformBlock PredefinedViewerData::GetUniformBlock() + { + PredefinedViewerData viewerData = GetOffsets(); + + std::vector viewerDataVariables; + viewerDataVariables.assign({ + { + "ProjMatrix", + viewerData.projMatrixOffset + }, + { + "InvProjMatrix", + viewerData.invProjMatrixOffset + }, + { + "ViewMatrix", + viewerData.viewMatrixOffset + }, + { + "InvViewMatrix", + viewerData.invViewMatrixOffset + }, + { + "ViewProjMatrix", + viewerData.viewProjMatrixOffset + }, + { + "InvViewProjMatrix", + viewerData.invViewProjMatrixOffset + }, + { + "TargetSize", + viewerData.targetSizeOffset + }, + { + "InvTargetSize", + viewerData.invTargetSizeOffset + }, + { + "EyePosition", + viewerData.eyePositionOffset + } + }); + + MaterialSettings::SharedUniformBlock uniformBlock = { + "Viewer", + "ViewerData", + std::move(viewerDataVariables) + }; + + return uniformBlock; + } +} diff --git a/src/Nazara/Graphics/Resources/Shaders/basicmaterial.frag.shader b/src/Nazara/Graphics/Resources/Shaders/basicmaterial.frag.shader new file mode 100644 index 000000000..59e9b08a9 Binary files /dev/null and b/src/Nazara/Graphics/Resources/Shaders/basicmaterial.frag.shader differ diff --git a/src/Nazara/Graphics/Resources/Shaders/basicmaterial.frag.shader.h b/src/Nazara/Graphics/Resources/Shaders/basicmaterial.frag.shader.h new file mode 100644 index 000000000..bd0422cad --- /dev/null +++ b/src/Nazara/Graphics/Resources/Shaders/basicmaterial.frag.shader.h @@ -0,0 +1 @@ +78,83,72,82,0,0,0,1,0,0,0,24,0,0,0,10,0,0,0,19,0,0,0,0,19,72,65,83,95,68,73,70,70,85,83,69,95,84,69,88,84,85,82,69,1,0,0,0,0,255,255,255,255,0,0,0,19,0,0,0,0,17,72,65,83,95,65,76,80,72,65,95,84,69,88,84,85,82,69,1,0,0,0,0,255,255,255,255,0,0,0,19,0,0,0,0,10,65,76,80,72,65,95,84,69,83,84,1,0,0,0,0,255,255,255,255,0,0,0,20,0,0,0,0,13,66,97,115,105,99,83,101,116,116,105,110,103,115,1,0,0,0,1,0,0,0,2,0,0,0,14,65,108,112,104,97,84,104,114,101,115,104,111,108,100,1,0,0,0,1,0,0,0,0,12,68,105,102,102,117,115,101,67,111,108,111,114,7,0,0,0,4,0,0,0,1,0,0,0,0,20,0,0,0,0,12,73,110,115,116,97,110,99,101,68,97,116,97,1,0,0,0,1,0,0,0,2,0,0,0,11,119,111,114,108,100,77,97,116,114,105,120,3,0,0,0,4,0,0,0,4,0,0,0,1,0,0,0,0,14,105,110,118,87,111,114,108,100,77,97,116,114,105,120,3,0,0,0,4,0,0,0,4,0,0,0,1,0,0,0,0,20,0,0,0,0,10,86,105,101,119,101,114,68,97,116,97,1,0,0,0,1,0,0,0,9,0,0,0,16,112,114,111,106,101,99,116,105,111,110,77,97,116,114,105,120,3,0,0,0,4,0,0,0,4,0,0,0,1,0,0,0,0,19,105,110,118,80,114,111,106,101,99,116,105,111,110,77,97,116,114,105,120,3,0,0,0,4,0,0,0,4,0,0,0,1,0,0,0,0,10,118,105,101,119,77,97,116,114,105,120,3,0,0,0,4,0,0,0,4,0,0,0,1,0,0,0,0,13,105,110,118,86,105,101,119,77,97,116,114,105,120,3,0,0,0,4,0,0,0,4,0,0,0,1,0,0,0,0,14,118,105,101,119,80,114,111,106,77,97,116,114,105,120,3,0,0,0,4,0,0,0,4,0,0,0,1,0,0,0,0,17,105,110,118,86,105,101,119,80,114,111,106,77,97,116,114,105,120,3,0,0,0,4,0,0,0,4,0,0,0,1,0,0,0,0,16,114,101,110,100,101,114,84,97,114,103,101,116,83,105,122,101,7,0,0,0,2,0,0,0,1,0,0,0,0,19,105,110,118,82,101,110,100,101,114,84,97,114,103,101,116,83,105,122,101,7,0,0,0,2,0,0,0,1,0,0,0,0,11,101,121,101,80,111,115,105,116,105,111,110,7,0,0,0,3,0,0,0,1,0,0,0,0,17,0,0,0,0,6,0,0,0,10,118,105,101,119,101,114,68,97,116,97,6,0,0,0,10,86,105,101,119,101,114,68,97,116,97,1,0,0,0,5,0,0,0,12,105,110,115,116,97,110,99,101,68,97,116,97,6,0,0,0,12,73,110,115,116,97,110,99,101,68,97,116,97,1,0,0,0,4,0,0,0,8,115,101,116,116,105,110,103,115,6,0,0,0,13,66,97,115,105,99,83,101,116,116,105,110,103,115,1,0,0,0,3,0,0,0,16,77,97,116,101,114,105,97,108,65,108,112,104,97,77,97,112,4,0,0,0,2,0,0,0,1,1,0,0,0,0,0,0,0,18,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,77,97,112,4,0,0,0,2,0,0,0,1,1,0,0,0,1,0,0,0,14,84,101,120,116,117,114,101,79,118,101,114,108,97,121,4,0,0,0,2,0,0,0,1,1,0,0,0,2,0,0,0,20,0,0,0,0,9,73,110,112,117,116,68,97,116,97,0,0,0,0,2,0,0,0,10,118,101,114,116,78,111,114,109,97,108,7,0,0,0,3,0,0,0,1,2,0,0,0,0,0,0,0,6,118,101,114,116,85,86,7,0,0,0,2,0,0,0,1,2,0,0,0,1,0,0,0,20,0,0,0,0,10,79,117,116,112,117,116,68,97,116,97,0,0,0,0,1,0,0,0,13,82,101,110,100,101,114,84,97,114,103,101,116,48,7,0,0,0,4,0,0,0,1,2,0,0,0,0,0,0,0,18,0,0,0,4,109,97,105,110,2,0,0,0,10,79,117,116,112,117,116,68,97,116,97,4,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,5,105,110,112,117,116,2,0,0,0,9,73,110,112,117,116,68,97,116,97,0,0,0,8,0,0,0,21,0,0,0,0,6,111,117,116,112,117,116,2,0,0,0,10,79,117,116,112,117,116,68,97,116,97,255,255,255,255,0,0,0,21,0,0,0,0,8,108,105,103,104,116,68,105,114,0,0,0,0,8,0,0,0,5,0,0,0,0,191,52,253,244,63,52,253,244,0,0,0,21,0,0,0,0,11,108,105,103,104,116,70,97,99,116,111,114,0,0,0,0,10,0,0,0,1,0,0,0,2,0,0,0,0,0,0,0,9,0,0,0,5,105,110,112,117,116,0,0,0,1,0,0,0,10,118,101,114,116,78,111,114,109,97,108,0,0,0,9,0,0,0,8,108,105,103,104,116,68,105,114,0,0,0,21,0,0,0,0,12,116,101,120,116,117,114,101,67,111,108,111,114,0,0,0,0,3,0,0,0,2,0,0,0,9,0,0,0,11,108,105,103,104,116,70,97,99,116,111,114,0,0,0,11,0,0,0,19,72,65,83,95,68,73,70,70,85,83,69,95,84,69,88,84,85,82,69,0,0,0,3,0,0,0,2,0,0,0,10,0,0,0,2,0,0,0,2,0,0,0,9,0,0,0,18,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,77,97,112,0,0,0,0,0,0,0,9,0,0,0,5,105,110,112,117,116,0,0,0,1,0,0,0,6,118,101,114,116,85,86,0,0,0,0,0,0,0,9,0,0,0,8,115,101,116,116,105,110,103,115,0,0,0,1,0,0,0,12,68,105,102,102,117,115,101,67,111,108,111,114,0,0,0,0,0,0,0,9,0,0,0,8,115,101,116,116,105,110,103,115,0,0,0,1,0,0,0,12,68,105,102,102,117,115,101,67,111,108,111,114,0,0,0,21,0,0,0,0,4,118,97,114,48,0,0,0,0,11,0,0,0,17,72,65,83,95,65,76,80,72,65,95,84,69,88,84,85,82,69,0,0,0,6,7,0,0,0,4,0,0,0,1,0,0,0,12,0,0,0,1,0,0,0,9,0,0,0,12,116,101,120,116,117,114,101,67,111,108,111,114,0,0,0,0,0,0,0,12,0,0,0,1,0,0,0,9,0,0,0,12,116,101,120,116,117,114,101,67,111,108,111,114,0,0,0,1,0,0,0,12,0,0,0,1,0,0,0,9,0,0,0,12,116,101,120,116,117,114,101,67,111,108,111,114,0,0,0,2,0,0,0,3,0,0,0,2,0,0,0,12,0,0,0,1,0,0,0,10,0,0,0,2,0,0,0,2,0,0,0,9,0,0,0,16,77,97,116,101,114,105,97,108,65,108,112,104,97,77,97,112,0,0,0,0,0,0,0,9,0,0,0,5,105,110,112,117,116,0,0,0,1,0,0,0,6,118,101,114,116,85,86,0,0,0,0,0,0,0,12,0,0,0,1,0,0,0,9,0,0,0,12,116,101,120,116,117,114,101,67,111,108,111,114,0,0,0,3,0,0,0,9,0,0,0,12,116,101,120,116,117,114,101,67,111,108,111,114,0,0,0,15,0,0,0,1,0,0,0,3,0,0,0,4,0,0,0,11,0,0,0,10,65,76,80,72,65,95,84,69,83,84,0,0,0,3,0,0,0,8,0,0,0,12,0,0,0,1,0,0,0,9,0,0,0,4,118,97,114,48,0,0,0,3,0,0,0,0,0,0,0,9,0,0,0,8,115,101,116,116,105,110,103,115,0,0,0,1,0,0,0,14,65,108,112,104,97,84,104,114,101,115,104,111,108,100,0,0,0,8,0,0,0,0,0,0,0,0,8,0,0,0,0,1,0,0,0,22,255,255,255,255,0,0,0,23,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,6,111,117,116,112,117,116,0,0,0,1,0,0,0,13,82,101,110,100,101,114,84,97,114,103,101,116,48,0,0,0,9,0,0,0,4,118,97,114,48,0,0,0,26,0,0,0,9,0,0,0,6,111,117,116,112,117,116, \ No newline at end of file diff --git a/src/Nazara/Graphics/Resources/Shaders/basicmaterial.vert.shader b/src/Nazara/Graphics/Resources/Shaders/basicmaterial.vert.shader new file mode 100644 index 000000000..2b19a5a6f Binary files /dev/null and b/src/Nazara/Graphics/Resources/Shaders/basicmaterial.vert.shader differ diff --git a/src/Nazara/Graphics/Resources/Shaders/basicmaterial.vert.shader.h b/src/Nazara/Graphics/Resources/Shaders/basicmaterial.vert.shader.h new file mode 100644 index 000000000..9382c97dd --- /dev/null +++ b/src/Nazara/Graphics/Resources/Shaders/basicmaterial.vert.shader.h @@ -0,0 +1 @@ +78,83,72,82,0,0,0,1,0,0,0,24,0,0,0,7,0,0,0,20,0,0,0,0,13,66,97,115,105,99,83,101,116,116,105,110,103,115,1,0,0,0,1,0,0,0,2,0,0,0,14,65,108,112,104,97,84,104,114,101,115,104,111,108,100,1,0,0,0,1,0,0,0,0,12,68,105,102,102,117,115,101,67,111,108,111,114,7,0,0,0,4,0,0,0,1,0,0,0,0,20,0,0,0,0,12,73,110,115,116,97,110,99,101,68,97,116,97,1,0,0,0,1,0,0,0,2,0,0,0,11,119,111,114,108,100,77,97,116,114,105,120,3,0,0,0,4,0,0,0,4,0,0,0,1,0,0,0,0,14,105,110,118,87,111,114,108,100,77,97,116,114,105,120,3,0,0,0,4,0,0,0,4,0,0,0,1,0,0,0,0,20,0,0,0,0,10,86,105,101,119,101,114,68,97,116,97,1,0,0,0,1,0,0,0,9,0,0,0,16,112,114,111,106,101,99,116,105,111,110,77,97,116,114,105,120,3,0,0,0,4,0,0,0,4,0,0,0,1,0,0,0,0,19,105,110,118,80,114,111,106,101,99,116,105,111,110,77,97,116,114,105,120,3,0,0,0,4,0,0,0,4,0,0,0,1,0,0,0,0,10,118,105,101,119,77,97,116,114,105,120,3,0,0,0,4,0,0,0,4,0,0,0,1,0,0,0,0,13,105,110,118,86,105,101,119,77,97,116,114,105,120,3,0,0,0,4,0,0,0,4,0,0,0,1,0,0,0,0,14,118,105,101,119,80,114,111,106,77,97,116,114,105,120,3,0,0,0,4,0,0,0,4,0,0,0,1,0,0,0,0,17,105,110,118,86,105,101,119,80,114,111,106,77,97,116,114,105,120,3,0,0,0,4,0,0,0,4,0,0,0,1,0,0,0,0,16,114,101,110,100,101,114,84,97,114,103,101,116,83,105,122,101,7,0,0,0,2,0,0,0,1,0,0,0,0,19,105,110,118,82,101,110,100,101,114,84,97,114,103,101,116,83,105,122,101,7,0,0,0,2,0,0,0,1,0,0,0,0,11,101,121,101,80,111,115,105,116,105,111,110,7,0,0,0,3,0,0,0,1,0,0,0,0,17,0,0,0,0,3,0,0,0,10,118,105,101,119,101,114,68,97,116,97,6,0,0,0,10,86,105,101,119,101,114,68,97,116,97,1,0,0,0,5,0,0,0,12,105,110,115,116,97,110,99,101,68,97,116,97,6,0,0,0,12,73,110,115,116,97,110,99,101,68,97,116,97,1,0,0,0,4,0,0,0,8,115,101,116,116,105,110,103,115,6,0,0,0,13,66,97,115,105,99,83,101,116,116,105,110,103,115,1,0,0,0,3,0,0,0,20,0,0,0,0,9,73,110,112,117,116,68,97,116,97,0,0,0,0,3,0,0,0,5,105,110,80,111,115,7,0,0,0,3,0,0,0,1,2,0,0,0,0,0,0,0,9,105,110,78,111,114,109,97,108,115,7,0,0,0,3,0,0,0,1,2,0,0,0,1,0,0,0,10,105,110,84,101,120,67,111,111,114,100,7,0,0,0,2,0,0,0,1,2,0,0,0,2,0,0,0,20,0,0,0,0,10,79,117,116,112,117,116,68,97,116,97,0,0,0,0,3,0,0,0,10,118,101,114,116,78,111,114,109,97,108,7,0,0,0,3,0,0,0,1,2,0,0,0,0,0,0,0,6,118,101,114,116,85,86,7,0,0,0,2,0,0,0,1,2,0,0,0,1,0,0,0,8,112,111,115,105,116,105,111,110,7,0,0,0,4,0,0,0,1,1,0,0,0,0,0,0,0,0,18,0,0,0,4,109,97,105,110,2,0,0,0,10,79,117,116,112,117,116,68,97,116,97,4,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,5,105,110,112,117,116,2,0,0,0,9,73,110,112,117,116,68,97,116,97,0,0,0,5,0,0,0,21,0,0,0,0,6,111,117,116,112,117,116,2,0,0,0,10,79,117,116,112,117,116,68,97,116,97,255,255,255,255,0,0,0,23,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,6,111,117,116,112,117,116,0,0,0,1,0,0,0,6,118,101,114,116,85,86,0,0,0,0,0,0,0,9,0,0,0,5,105,110,112,117,116,0,0,0,1,0,0,0,10,105,110,84,101,120,67,111,111,114,100,0,0,0,23,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,6,111,117,116,112,117,116,0,0,0,1,0,0,0,10,118,101,114,116,78,111,114,109,97,108,0,0,0,0,0,0,0,9,0,0,0,5,105,110,112,117,116,0,0,0,1,0,0,0,9,105,110,78,111,114,109,97,108,115,0,0,0,23,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,6,111,117,116,112,117,116,0,0,0,1,0,0,0,8,112,111,115,105,116,105,111,110,0,0,0,3,0,0,0,2,0,0,0,3,0,0,0,2,0,0,0,3,0,0,0,2,0,0,0,0,0,0,0,9,0,0,0,10,118,105,101,119,101,114,68,97,116,97,0,0,0,1,0,0,0,16,112,114,111,106,101,99,116,105,111,110,77,97,116,114,105,120,0,0,0,0,0,0,0,9,0,0,0,10,118,105,101,119,101,114,68,97,116,97,0,0,0,1,0,0,0,10,118,105,101,119,77,97,116,114,105,120,0,0,0,0,0,0,0,9,0,0,0,12,105,110,115,116,97,110,99,101,68,97,116,97,0,0,0,1,0,0,0,11,119,111,114,108,100,77,97,116,114,105,120,0,0,0,6,7,0,0,0,4,0,0,0,1,0,0,0,0,0,0,0,9,0,0,0,5,105,110,112,117,116,0,0,0,1,0,0,0,5,105,110,80,111,115,0,0,0,8,0,0,0,1,63,128,0,0,255,255,255,255,255,255,255,255,0,0,0,26,0,0,0,9,0,0,0,6,111,117,116,112,117,116, \ No newline at end of file diff --git a/src/Nazara/Graphics/TextureSamplerCache.cpp b/src/Nazara/Graphics/TextureSamplerCache.cpp new file mode 100644 index 000000000..d211a9a36 --- /dev/null +++ b/src/Nazara/Graphics/TextureSamplerCache.cpp @@ -0,0 +1,19 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + const std::shared_ptr& TextureSamplerCache::Get(const TextureSamplerInfo& info) + { + auto it = m_samplers.find(info); + if (it == m_samplers.end()) + it = m_samplers.emplace(info, m_device->InstantiateTextureSampler(info)).first; + + return it->second; + } +} diff --git a/src/Nazara/Graphics/UberShader.cpp b/src/Nazara/Graphics/UberShader.cpp new file mode 100644 index 000000000..ff2d07d1d --- /dev/null +++ b/src/Nazara/Graphics/UberShader.cpp @@ -0,0 +1,71 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + UberShader::UberShader(ShaderStageType shaderStage, const ShaderAst::StatementPtr& shaderAst) : + m_shaderStage(shaderStage) + { + ShaderAst::SanitizeVisitor::Options options; + options.removeOptionDeclaration = false; + + m_shaderAst = ShaderAst::Sanitize(shaderAst, options); + + std::size_t optionCount = 0; + + ShaderAst::AstReflect::Callbacks callbacks; + callbacks.onOptionDeclaration = [&](const std::string& optionName, const ShaderAst::ExpressionType& optionType) + { + m_optionIndexByName[optionName] = optionCount; + optionCount++; + }; + + ShaderAst::AstReflect reflect; + reflect.Reflect(m_shaderAst, callbacks); + + if (optionCount >= 64) + throw std::runtime_error("Too many conditions"); + + m_combinationMask = std::numeric_limits::max(); + m_combinationMask <<= optionCount; + m_combinationMask = ~m_combinationMask; + } + + UInt64 UberShader::GetOptionFlagByName(const std::string& optionName) const + { + auto it = m_optionIndexByName.find(optionName); + if (it == m_optionIndexByName.end()) + return 0; + + return SetBit(0, it->second); + } + + const std::shared_ptr& UberShader::Get(UInt64 combination) + { + combination &= m_combinationMask; + + auto it = m_combinations.find(combination); + if (it == m_combinations.end()) + { + ShaderWriter::States states; + states.enabledOptions = combination; + states.sanitized = true; + + std::shared_ptr stage = Graphics::Instance()->GetRenderDevice()->InstantiateShaderModule(m_shaderStage, m_shaderAst, std::move(states)); + + it = m_combinations.emplace(combination, std::move(stage)).first; + } + + return it->second; + } +} diff --git a/src/Nazara/Network/AbstractSocket.cpp b/src/Nazara/Network/AbstractSocket.cpp index 205ead63e..af7ed396c 100644 --- a/src/Nazara/Network/AbstractSocket.cpp +++ b/src/Nazara/Network/AbstractSocket.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include #include @@ -32,9 +33,9 @@ namespace Nz */ AbstractSocket::AbstractSocket(SocketType type) : - m_lastError(SocketError_NoError), + m_lastError(SocketError::NoError), m_handle(SocketImpl::InvalidHandle), - m_state(SocketState_NotConnected), + m_state(SocketState::NotConnected), m_type(type), m_isBlockingEnabled(true) { @@ -165,7 +166,7 @@ namespace Nz void AbstractSocket::OnClose() { - UpdateState(SocketState_NotConnected); + UpdateState(SocketState::NotConnected); } /*! @@ -178,7 +179,7 @@ namespace Nz { SocketError errorCode; if (!SocketImpl::SetBlocking(m_handle, m_isBlockingEnabled, &errorCode)) - NazaraWarning("Failed to set socket blocking mode (0x" + NumberToString(errorCode, 16) + ')'); + NazaraWarning("Failed to set socket blocking mode (0x" + NumberToString(UnderlyingCast(errorCode), 16) + ')'); } /*! @@ -190,11 +191,11 @@ namespace Nz { if (m_handle == SocketImpl::InvalidHandle || m_protocol != protocol) { - SocketHandle handle = SocketImpl::Create((protocol == NetProtocol_Any) ? NetProtocol_IPv6 : protocol, m_type, &m_lastError); + SocketHandle handle = SocketImpl::Create((protocol == NetProtocol::Any) ? NetProtocol::IPv6 : protocol, m_type, &m_lastError); if (handle == SocketImpl::InvalidHandle) return false; - if (protocol == NetProtocol_Any) + if (protocol == NetProtocol::Any) { if (!SocketImpl::SetIPv6Only(handle, false, &m_lastError)) { @@ -204,7 +205,7 @@ namespace Nz return false; } - protocol = NetProtocol_IPv6; + protocol = NetProtocol::IPv6; } m_protocol = protocol; diff --git a/src/Nazara/Network/AlgorithmNetwork.cpp b/src/Nazara/Network/AlgorithmNetwork.cpp index bc9bbb811..4b3972aac 100644 --- a/src/Nazara/Network/AlgorithmNetwork.cpp +++ b/src/Nazara/Network/AlgorithmNetwork.cpp @@ -88,31 +88,31 @@ namespace Nz { switch (resolveError) { - case ResolveError_NoError: + case ResolveError::NoError: return "No error"; - case ResolveError_Internal: + case ResolveError::Internal: return "An internal error occurred"; - case ResolveError_ResourceError: + case ResolveError::ResourceError: return "The operating system lacks the resources to proceed"; - case ResolveError_NonRecoverable: + case ResolveError::NonRecoverable: return "A nonrecoverable error occurred"; - case ResolveError_NotFound: + case ResolveError::NotFound: return "No such host is known"; - case ResolveError_NotInitialized: + case ResolveError::NotInitialized: return "Nazara Network has not been initialized"; - case ResolveError_ProtocolNotSupported: + case ResolveError::ProtocolNotSupported: return "A specified protocol is not supported by the server"; - case ResolveError_TemporaryFailure: + case ResolveError::TemporaryFailure: return "A temporary failure occurred, try again"; - case ResolveError_Unknown: + case ResolveError::Unknown: return "An unknown error occurred"; default: @@ -131,52 +131,52 @@ namespace Nz { switch (socketError) { - case SocketError_NoError: + case SocketError::NoError: return "No error"; - case SocketError_AddressNotAvailable: + case SocketError::AddressNotAvailable: return "The address is already in use"; - case SocketError_ConnectionClosed: + case SocketError::ConnectionClosed: return "The connection has been closed"; - case SocketError_ConnectionRefused: + case SocketError::ConnectionRefused: return "The connection attempt was refused"; - case SocketError_DatagramSize: + case SocketError::DatagramSize: return "The datagram size is over the system limit"; - case SocketError_Internal: + case SocketError::Internal: return "An internal error occurred"; - case SocketError_Interrupted: + case SocketError::Interrupted: return "The operation was interrupted by a signal"; - case SocketError_Packet: + case SocketError::Packet: return "Packet encoding or decoding failed"; - case SocketError_NetworkError: + case SocketError::NetworkError: return "Networking subsystem failed"; - case SocketError_NotInitialized: + case SocketError::NotInitialized: return "Network module has not been initialized"; - case SocketError_NotSupported: + case SocketError::NotSupported: return "This operation is not supported"; - case SocketError_ResolveError: + case SocketError::ResolveError: return "The hostname couldn't be resolved"; - case SocketError_ResourceError: + case SocketError::ResourceError: return "The operating system lacks the resources to proceed"; - case SocketError_TimedOut: + case SocketError::TimedOut: return "The operation timed out"; - case SocketError_Unknown: + case SocketError::Unknown: return "An unknown error occurred"; - case SocketError_UnreachableHost: + case SocketError::UnreachableHost: return "The host is not reachable"; default: diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 778fcdac0..92ddcdd49 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -89,9 +89,9 @@ namespace Nz UInt32 windowSize; if (m_outgoingBandwidth == 0) - windowSize = ENetProtocol_MaximumWindowSize; + windowSize = ENetConstants::ENetProtocol_MaximumWindowSize; else - windowSize = (m_outgoingBandwidth / ENetConstants::ENetPeer_WindowSizeScale) * ENetProtocol_MinimumWindowSize; + windowSize = (m_outgoingBandwidth / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; ENetPeer& peer = m_peers[peerId]; peer.InitOutgoing(channelCount, remoteAddress, ++m_randomSeed, windowSize); @@ -134,7 +134,7 @@ namespace Nz if (!hostnameAddress.IsValid()) { if (error) - *error = ResolveError_NotFound; + *error = ResolveError::NotFound; return nullptr; } @@ -320,7 +320,7 @@ namespace Nz bool ENetHost::InitSocket(const IpAddress& address) { - if (!m_socket.Create((m_isUsingDualStack) ? NetProtocol_Any : address.GetProtocol())) + if (!m_socket.Create((m_isUsingDualStack) ? NetProtocol::Any : address.GetProtocol())) return false; m_socket.EnableBlocking(false); @@ -330,14 +330,14 @@ namespace Nz if (address.IsValid() && !address.IsLoopback()) { - if (m_socket.Bind(address) != SocketState_Bound) + if (m_socket.Bind(address) != SocketState::Bound) { NazaraError("Failed to bind address " + address.ToString()); return false; } } - m_poller.RegisterSocket(m_socket, SocketPollEvent_Read); + m_poller.RegisterSocket(m_socket, SocketPollEvent::Read); return true; } @@ -417,7 +417,7 @@ namespace Nz UInt32 channelCount = NetToHost(command->connect.channelCount); - if (channelCount < ENetProtocol_MinimumChannelCount || channelCount > ENetProtocol_MaximumChannelCount) + if (channelCount < ENetConstants::ENetProtocol_MinimumChannelCount || channelCount > ENetConstants::ENetProtocol_MaximumChannelCount) return nullptr; std::size_t duplicatePeers = 0; diff --git a/src/Nazara/Network/IpAddress.cpp b/src/Nazara/Network/IpAddress.cpp index fbb528488..e38584f51 100644 --- a/src/Nazara/Network/IpAddress.cpp +++ b/src/Nazara/Network/IpAddress.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include #include @@ -47,14 +48,14 @@ namespace Nz m_isValid = true; if (isIPv6) { - m_protocol = NetProtocol_IPv6; + m_protocol = NetProtocol::IPv6; for (unsigned int i = 0; i < 8; ++i) m_ipv6[i] = UInt32(result[i*2]) << 8 | result[i*2 + 1]; } else { - m_protocol = NetProtocol_IPv4; + m_protocol = NetProtocol::IPv4; for (unsigned int i = 0; i < 4; ++i) m_ipv4[i] = result[i]; @@ -75,21 +76,21 @@ namespace Nz if (!m_isValid) return false; - NazaraAssert(m_protocol <= NetProtocol_Max, "Protocol has value out of enum"); + NazaraAssert(m_protocol <= NetProtocol::Max, "Protocol has value out of enum"); switch (m_protocol) { - case NetProtocol_Any: - case NetProtocol_Unknown: + case NetProtocol::Any: + case NetProtocol::Unknown: break; - case NetProtocol_IPv4: + case NetProtocol::IPv4: return m_ipv4[0] == 127; - case NetProtocol_IPv6: + case NetProtocol::IPv6: return m_ipv6 == LoopbackIpV6.m_ipv6; // Only compare the ip value } - NazaraInternalError("Invalid protocol for IpAddress (0x" + NumberToString(m_protocol) + ')'); + NazaraInternalError("Invalid protocol for IpAddress (0x" + NumberToString(UnderlyingCast(m_protocol), 16) + ')'); return false; } @@ -106,14 +107,14 @@ namespace Nz if (m_isValid) { - NazaraAssert(m_protocol <= NetProtocol_Max, "Protocol has value out of enum"); + NazaraAssert(m_protocol <= NetProtocol::Max, "Protocol has value out of enum"); switch (m_protocol) { - case NetProtocol_Any: - case NetProtocol_Unknown: + case NetProtocol::Any: + case NetProtocol::Unknown: break; - case NetProtocol_IPv4: + case NetProtocol::IPv4: for (unsigned int i = 0; i < 4; ++i) { stream << int(m_ipv4[i]); @@ -122,7 +123,7 @@ namespace Nz } break; - case NetProtocol_IPv6: + case NetProtocol::IPv6: // Canonical representation of an IPv6 // https://tools.ietf.org/html/rfc5952 @@ -213,7 +214,7 @@ namespace Nz */ std::vector IpAddress::ResolveHostname(NetProtocol protocol, const std::string& hostname, const std::string& service, ResolveError* error) { - NazaraAssert(protocol != NetProtocol_Unknown, "Invalid protocol"); + NazaraAssert(protocol != NetProtocol::Unknown, "Invalid protocol"); return IpAddressImpl::ResolveHostname(protocol, hostname, service, error); } diff --git a/src/Nazara/Network/Linux/SocketPollerImpl.cpp b/src/Nazara/Network/Linux/SocketPollerImpl.cpp index be848deb1..fa1b39b16 100644 --- a/src/Nazara/Network/Linux/SocketPollerImpl.cpp +++ b/src/Nazara/Network/Linux/SocketPollerImpl.cpp @@ -53,10 +53,10 @@ namespace Nz entry.data.fd = socket; - if (eventFlags & SocketPollEvent_Read) + if (eventFlags & SocketPollEvent::Read) entry.events |= EPOLLIN; - if (eventFlags & SocketPollEvent_Write) + if (eventFlags & SocketPollEvent::Write) entry.events |= EPOLLOUT; if (epoll_ctl(m_handle, EPOLL_CTL_ADD, socket, &entry) != 0) @@ -123,7 +123,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return activeSockets; } diff --git a/src/Nazara/Network/NetPacket.cpp b/src/Nazara/Network/NetPacket.cpp index 24db7be0c..dafeac959 100644 --- a/src/Nazara/Network/NetPacket.cpp +++ b/src/Nazara/Network/NetPacket.cpp @@ -41,7 +41,7 @@ namespace Nz const void* NetPacket::OnSend(std::size_t* newSize) const { NazaraAssert(newSize, "Invalid size pointer"); - NazaraAssert(m_netCode != NetCode_Invalid, "Invalid NetCode"); + NazaraAssert(m_netCode != 0, "Invalid NetCode"); std::size_t size = m_buffer->GetSize(); if (!EncodeHeader(m_buffer->GetBuffer(), static_cast(size), m_netCode)) diff --git a/src/Nazara/Network/Network.cpp b/src/Nazara/Network/Network.cpp index 6d5b6b076..78b28cd9b 100644 --- a/src/Nazara/Network/Network.cpp +++ b/src/Nazara/Network/Network.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #if defined(NAZARA_PLATFORM_WINDOWS) #include @@ -40,15 +39,11 @@ namespace Nz if (!NetPacket::Initialize()) throw std::runtime_error("failed to initialize packets"); - - if (!RUdpConnection::Initialize()) - throw std::runtime_error("failed to initialize RUDP protocol"); } Network::~Network() { // Uninitialize module here - RUdpConnection::Uninitialize(); NetPacket::Uninitialize(); SocketImpl::Uninitialize(); } diff --git a/src/Nazara/Network/Posix/IpAddressImpl.cpp b/src/Nazara/Network/Posix/IpAddressImpl.cpp index ac643896c..8a8cc87f9 100644 --- a/src/Nazara/Network/Posix/IpAddressImpl.cpp +++ b/src/Nazara/Network/Posix/IpAddressImpl.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include #include @@ -132,7 +133,7 @@ namespace Nz } if (error) - *error = ResolveError_NoError; + *error = ResolveError::NoError; return true; } @@ -174,7 +175,7 @@ namespace Nz } if (error) - *error = ResolveError_NoError; + *error = ResolveError::NoError; return results; } @@ -185,7 +186,7 @@ namespace Nz { switch (ipAddress.GetProtocol()) { - case NetProtocol_IPv4: + case NetProtocol::IPv4: { sockaddr_in* socketAddress = reinterpret_cast(buffer); @@ -197,7 +198,7 @@ namespace Nz return sizeof(sockaddr_in); } - case NetProtocol_IPv6: + case NetProtocol::IPv6: { sockaddr_in6* socketAddress = reinterpret_cast(buffer); @@ -217,7 +218,7 @@ namespace Nz } default: - NazaraInternalError("Unhandled ip protocol (0x" + NumberToString(ipAddress.GetProtocol(), 16) + ')'); + NazaraInternalError("Unhandled ip protocol (0x" + NumberToString(UnderlyingCast(ipAddress.GetProtocol()), 16) + ')'); break; } } @@ -231,13 +232,13 @@ namespace Nz switch (family) { case PF_INET: - return NetProtocol_IPv4; + return NetProtocol::IPv4; case PF_INET6: - return NetProtocol_IPv6; + return NetProtocol::IPv6; default: - return NetProtocol_Unknown; + return NetProtocol::Unknown; } } @@ -246,16 +247,16 @@ namespace Nz switch (socketType) { case SOCK_STREAM: - return SocketType_TCP; + return SocketType::TCP; case SOCK_DGRAM: - return SocketType_UDP; + return SocketType::UDP; case SOCK_RAW: - return SocketType_Raw; + return SocketType::Raw; default: - return SocketType_Unknown; + return SocketType::Unknown; } } @@ -265,35 +266,35 @@ namespace Nz switch (error) { case 0: - return ResolveError_NoError; + return ResolveError::NoError; // Engine error case EAI_BADFLAGS: case EAI_SYSTEM: - return ResolveError_Internal; + return ResolveError::Internal; case EAI_FAMILY: case EAI_SERVICE: case EAI_SOCKTYPE: - return ResolveError_ProtocolNotSupported; + return ResolveError::ProtocolNotSupported; case EAI_NONAME: - return ResolveError_NotFound; + return ResolveError::NotFound; case EAI_FAIL: - return ResolveError_NonRecoverable; + return ResolveError::NonRecoverable; case EAI_NODATA: - return ResolveError_NotInitialized; + return ResolveError::NotInitialized; case EAI_MEMORY: - return ResolveError_ResourceError; + return ResolveError::ResourceError; case EAI_AGAIN: - return ResolveError_TemporaryFailure; + return ResolveError::TemporaryFailure; } NazaraWarning("Unhandled EAI error: " + Error::GetLastSystemError(error) + " (" + NumberToString(error) + ") as " + gai_strerror(error)); - return ResolveError_Unknown; + return ResolveError::Unknown; } } diff --git a/src/Nazara/Network/Posix/SocketImpl.cpp b/src/Nazara/Network/Posix/SocketImpl.cpp index fbe762ff1..efb08ea0c 100644 --- a/src/Nazara/Network/Posix/SocketImpl.cpp +++ b/src/Nazara/Network/Posix/SocketImpl.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include #include @@ -41,7 +42,7 @@ namespace Nz *address = IpAddressImpl::FromSockAddr(reinterpret_cast(&nameBuffer)); if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; } else { @@ -65,19 +66,19 @@ namespace Nz if (error) *error = TranslateErrnoToSocketError(GetLastErrorCode()); - return SocketState_NotConnected; + return SocketState::NotConnected; } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; - return SocketState_Bound; + return SocketState::Bound; } SocketHandle SocketImpl::Create(NetProtocol protocol, SocketType type, SocketError* error) { - NazaraAssert(protocol != NetProtocol_Any, "Any protocol is not supported for socket creation"); - NazaraAssert(type <= SocketType_Max, "Type has value out of enum"); + NazaraAssert(protocol != NetProtocol::Any, "Any protocol is not supported for socket creation"); + NazaraAssert(type <= SocketType::Max, "Type has value out of enum"); SocketHandle handle = socket(TranslateNetProtocolToAF(protocol), TranslateSocketTypeToSock(type), 0); if (handle == InvalidHandle && error != nullptr) @@ -98,7 +99,7 @@ namespace Nz { NazaraAssert(handle != InvalidHandle, "Invalid handle"); - if (GetLastError(handle, nullptr) < 0) + if (GetLastError(handle, nullptr) != SocketError::Internal) NazaraWarning("Failed to clear socket error code: " + Error::GetLastSystemError(GetLastErrorCode())); } @@ -111,7 +112,7 @@ namespace Nz int bufferLength = IpAddressImpl::ToSockAddr(address, nameBuffer.data()); if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; // Clear socket error status ClearErrorCode(handle); @@ -123,24 +124,24 @@ namespace Nz { case EALREADY: case EINPROGRESS: - return SocketState_Connecting; + return SocketState::Connecting; case EISCONN: - return SocketState_Connected; + return SocketState::Connected; } if (error) { if (errorCode == EADDRNOTAVAIL) - *error = SocketError_ConnectionRefused; //< ConnectionRefused seems more legit than AddressNotAvailable in connect case + *error = SocketError::ConnectionRefused; //< ConnectionRefused seems more legit than AddressNotAvailable in connect case else *error = TranslateErrnoToSocketError(errorCode); } - return SocketState_NotConnected; + return SocketState::NotConnected; } - return SocketState_Connected; + return SocketState::Connected; } bool SocketImpl::Initialize() @@ -152,7 +153,7 @@ namespace Nz { int code = GetLastErrorCode(handle, error); if (code < 0) - return SocketError_Internal; + return SocketError::Internal; return TranslateErrnoToSocketError(code); } @@ -176,7 +177,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return code; } @@ -194,7 +195,7 @@ namespace Nz if (error) *error = TranslateErrnoToSocketError(GetLastErrorCode()); - return SocketState_NotConnected; + return SocketState::NotConnected; } if (listen(handle, queueSize) == SOCKET_ERROR) @@ -202,13 +203,13 @@ namespace Nz if (error) *error = TranslateErrnoToSocketError(GetLastErrorCode()); - return SocketState_NotConnected; + return SocketState::NotConnected; } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; - return SocketState_Bound; + return SocketState::Bound; } std::size_t SocketImpl::QueryAvailableBytes(SocketHandle handle, SocketError* error) @@ -225,7 +226,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return availableBytes; } @@ -244,7 +245,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return code; } @@ -263,7 +264,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return code; } @@ -286,7 +287,7 @@ namespace Nz #endif if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return code; } @@ -305,7 +306,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return code; } @@ -324,7 +325,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return code; } @@ -347,7 +348,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return IpAddressImpl::FromSockAddr(reinterpret_cast(nameBuffer.data())); } @@ -366,7 +367,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return code; } @@ -386,7 +387,7 @@ namespace Nz { int errorCode = GetLastErrorCode(); if (errorCode == EINVAL) - *error = SocketError_NoError; + *error = SocketError::NoError; else *error = TranslateErrnoToSocketError(errorCode); } @@ -395,7 +396,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return IpAddressImpl::FromSockAddr(reinterpret_cast(nameBuffer.data())); } @@ -420,54 +421,50 @@ namespace Nz SocketState SocketImpl::PollConnection(SocketHandle handle, const IpAddress& address, UInt64 msTimeout, SocketError* error) { - // http://developerweb.net/viewtopic.php?id=3196 - fd_set localSet; - FD_ZERO(&localSet); - FD_SET(handle, &localSet); + // Wait until socket is available for writing or an error occurs (ie when connection succeeds or fails) + pollfd descriptor; + descriptor.events = POLLOUT; + descriptor.fd = handle; + descriptor.revents = 0; - timeval tv; - tv.tv_sec = static_cast(msTimeout / 1000ULL); - tv.tv_usec = static_cast((msTimeout % 1000ULL) * 1000ULL); - - int ret = ::select(0, nullptr, &localSet, &localSet, (msTimeout != std::numeric_limits::max()) ? &tv : nullptr); - if (ret > 0) - { - int code = GetLastErrorCode(handle, error); - if (code < 0) //< GetLastErrorCode() failed - return SocketState_NotConnected; - - if (code) - { - if (error) - *error = TranslateErrnoToSocketError(code); - - return SocketState_NotConnected; - } - } - else if (ret == 0) - { - if (error) - { - if (msTimeout > 0) - *error = SocketError_TimedOut; - else - *error = SocketError_NoError; - } - - return SocketState_Connecting; - } - else + int ret = ::poll(&descriptor, 1, (msTimeout != std::numeric_limits::max()) ? int(msTimeout) : -1); + if (ret == SOCKET_ERROR) { if (error) *error = TranslateErrnoToSocketError(GetLastErrorCode()); - return SocketState_NotConnected; + return SocketState::NotConnected; } + else if (ret > 0) + { + if (descriptor.revents & (POLLERR | POLLHUP)) + { + if (error) + *error = GetLastError(handle); - if (error) - *error = SocketError_NoError; + return SocketState::NotConnected; + } + else if (descriptor.revents & POLLOUT) + return SocketState::Connected; + else + { + NazaraWarning("Socket " + std::to_string(handle) + " was returned by poll without POLLOUT nor error events (events: 0x" + NumberToString(descriptor.revents, 16) + ')'); + return SocketState::NotConnected; + } + } + else + { + // Still connecting + if (error) + { + if (msTimeout > 0) + *error = SocketError::TimedOut; + else + *error = SocketError::NoError; + } - return SocketState_Connected; + return SocketState::Connecting; + } } bool SocketImpl::Receive(SocketHandle handle, void* buffer, int length, int* read, SocketError* error) @@ -503,7 +500,7 @@ namespace Nz else if (byteRead == 0) { if (error) - *error = SocketError_ConnectionClosed; + *error = SocketError::ConnectionClosed; return false; //< Connection has been closed } @@ -512,7 +509,7 @@ namespace Nz *read = byteRead; if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return true; } @@ -558,7 +555,7 @@ namespace Nz else if (byteRead == 0) { if (error) - *error = SocketError_ConnectionClosed; + *error = SocketError::ConnectionClosed; return false; //< Connection closed } @@ -572,7 +569,7 @@ namespace Nz *read = byteRead; if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return true; } @@ -638,7 +635,7 @@ namespace Nz else if (byteRead == 0) { if (error) - *error = SocketError_ConnectionClosed; + *error = SocketError::ConnectionClosed; return false; //< Connection closed } @@ -649,7 +646,7 @@ namespace Nz if (msgHdr.msg_flags & MSG_TRUNC) { if (error) - *error = SocketError_DatagramSize; + *error = SocketError::DatagramSize; return false; } @@ -662,7 +659,7 @@ namespace Nz *read = byteRead; if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return true; } @@ -699,7 +696,7 @@ namespace Nz *sent = byteSent; if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return true; } @@ -757,7 +754,7 @@ namespace Nz *sent = static_cast(byteSent); if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return true; } @@ -797,7 +794,7 @@ namespace Nz *sent = byteSent; if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return true; } @@ -816,7 +813,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return true; } @@ -835,7 +832,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return true; } @@ -854,7 +851,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return true; } @@ -892,7 +889,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return true; } @@ -911,7 +908,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; #if not defined(MSG_NOSIGNAL) // -> https://github.com/intel/parameter-framework/pull/133/files //There is no MSG_NOSIGNAL on macos @@ -942,7 +939,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return true; } @@ -961,7 +958,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return true; } @@ -971,7 +968,7 @@ namespace Nz switch (error) { case 0: - return SocketError_NoError; + return SocketError::NoError; // Engine error case EACCES: @@ -985,83 +982,83 @@ namespace Nz case EISCONN: case EWOULDBLOCK: NazaraWarning("Internal error occurred: " + Error::GetLastSystemError(error) + " (" + NumberToString(error)+')'); - return SocketError_Internal; + return SocketError::Internal; case EADDRNOTAVAIL: case EADDRINUSE: - return SocketError_AddressNotAvailable; + return SocketError::AddressNotAvailable; case EAFNOSUPPORT: case EPFNOSUPPORT: case EOPNOTSUPP: case EPROTONOSUPPORT: case ESOCKTNOSUPPORT: - return SocketError_NotSupported; + return SocketError::NotSupported; case ECONNREFUSED: - return SocketError_ConnectionRefused; + return SocketError::ConnectionRefused; case EINTR: - return SocketError_Interrupted; + return SocketError::Interrupted; case EMSGSIZE: - return SocketError_DatagramSize; + return SocketError::DatagramSize; case EMFILE: case ENOBUFS: case ENOMEM: - return SocketError_ResourceError; + return SocketError::ResourceError; case ENOTCONN: case ESHUTDOWN: - return SocketError_ConnectionClosed; + return SocketError::ConnectionClosed; case EHOSTUNREACH: - return SocketError_UnreachableHost; + return SocketError::UnreachableHost; case ENETDOWN: case ENETUNREACH: - return SocketError_NetworkError; + return SocketError::NetworkError; case ENODATA: - return SocketError_NotInitialized; + return SocketError::NotInitialized; case ETIMEDOUT: - return SocketError_TimedOut; + return SocketError::TimedOut; } NazaraWarning("Unhandled POSIX error: " + Error::GetLastSystemError(error) + " (" + NumberToString(error) + ')'); - return SocketError_Unknown; + return SocketError::Unknown; } int SocketImpl::TranslateNetProtocolToAF(NetProtocol protocol) { - NazaraAssert(protocol <= NetProtocol_Max, "Protocol has value out of enum"); + NazaraAssert(protocol <= NetProtocol::Max, "Protocol has value out of enum"); static int addressFamily[] = { - AF_UNSPEC, //< NetProtocol_Any - AF_INET, //< NetProtocol_IPv4 - AF_INET6, //< NetProtocol_IPv6 - -1 //< NetProtocol_Unknown + AF_UNSPEC, //< NetProtocol::Any + AF_INET, //< NetProtocol::IPv4 + AF_INET6, //< NetProtocol::IPv6 + -1 //< NetProtocol::Unknown }; - static_assert(sizeof(addressFamily) / sizeof(int) == NetProtocol_Max + 1, "Address family array is incomplete"); + static_assert(sizeof(addressFamily) / sizeof(int) == NetProtocolCount, "Address family array is incomplete"); - return addressFamily[protocol]; + return addressFamily[UnderlyingCast(protocol)]; } int SocketImpl::TranslateSocketTypeToSock(SocketType type) { - NazaraAssert(type <= SocketType_Max, "Socket type has value out of enum"); + NazaraAssert(type <= SocketType::Max, "Socket type has value out of enum"); static int socketType[] = { - SOCK_RAW, //< SocketType_Raw - SOCK_STREAM, //< SocketType_TCP - SOCK_DGRAM, //< SocketType_UDP - -1 //< SocketType_Unknown + SOCK_RAW, //< SocketType::Raw + SOCK_STREAM, //< SocketType::TCP + SOCK_DGRAM, //< SocketType::UDP + -1 //< SocketType::Unknown }; - static_assert(sizeof(socketType) / sizeof(int) == SocketType_Max + 1, "Socket type array is incomplete"); + static_assert(sizeof(socketType) / sizeof(int) == SocketTypeCount, "Socket type array is incomplete"); - return socketType[type]; + return socketType[UnderlyingCast(type)]; } void SocketImpl::Uninitialize() diff --git a/src/Nazara/Network/Posix/SocketPollerImpl.cpp b/src/Nazara/Network/Posix/SocketPollerImpl.cpp index 2e1b03a44..39da759ee 100644 --- a/src/Nazara/Network/Posix/SocketPollerImpl.cpp +++ b/src/Nazara/Network/Posix/SocketPollerImpl.cpp @@ -42,10 +42,10 @@ namespace Nz 0 }; - if (eventFlags & SocketPollEvent_Read) + if (eventFlags & SocketPollEvent::Read) entry.events |= POLLRDNORM; - if (eventFlags & SocketPollEvent_Write) + if (eventFlags & SocketPollEvent::Write) entry.events |= POLLWRNORM; m_allSockets[socket] = m_sockets.size(); diff --git a/src/Nazara/Network/RUdpConnection.cpp b/src/Nazara/Network/RUdpConnection.cpp deleted file mode 100644 index 2211c0705..000000000 --- a/src/Nazara/Network/RUdpConnection.cpp +++ /dev/null @@ -1,640 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include -#include -#include -#include - -namespace Nz -{ - /*! - * \ingroup network - * \class Nz::RUdpConnection - * \brief Network class that represents a reliable UDP connection - */ - - /*! - * \brief Constructs a RUdpConnection object by default - */ - - RUdpConnection::RUdpConnection() : - m_peerIterator(0), - m_forceAckSendTime(10'000), //< 10ms - m_pingInterval(1'000'000), //< 1s - m_protocol(0x4E4E6574), //< "NNet" - m_timeBeforePing(500'000), //< 0.5s - m_timeBeforeTimeOut(10'000'000), //< 10s - m_currentTime(0), - m_isSimulationEnabled(false), - m_shouldAcceptConnections(true) - { - } - - /*! - * \brief Connects to the IpAddress - * \return true - * - * \param remoteAddress Address to connect to - * - * \remark Produces a NazaraAssert if socket is not bound - * \remark Produces a NazaraAssert if remote is invalid - * \remark Produces a NazaraAssert if port is not specified - */ - - bool RUdpConnection::Connect(const IpAddress& remoteAddress) - { - NazaraAssert(m_socket.GetState() == SocketState_Bound, "Socket must be bound first"); - NazaraAssert(remoteAddress.IsValid(), "Invalid remote address"); - NazaraAssert(remoteAddress.GetPort() != 0, "Remote address has no port"); - - PeerData& client = RegisterPeer(remoteAddress, PeerState_Connecting); - client.stateData1 = s_randomGenerator(); - - NetPacket connectionRequestPacket(NetCode_RequestConnection); - connectionRequestPacket << client.stateData1; - - EnqueuePacket(client, PacketPriority_Immediate, PacketReliability_Reliable, connectionRequestPacket); - return true; - } - - /*! - * \brief Connects to the hostname - * \return true If successful - * - * \param hostName Hostname of the remote - * \param protocol Net protocol to use - * \param service Specify the protocol used - * \param error Optional argument to get the error - */ - - bool RUdpConnection::Connect(const std::string& hostName, NetProtocol protocol, const std::string& service, ResolveError* error) - { - std::vector results = IpAddress::ResolveHostname(protocol, hostName, service, error); - if (results.empty()) - { - m_lastError = SocketError_ResolveError; - return false; - } - - IpAddress hostnameAddress; - for (const HostnameInfo& result : results) - { - if (!result.address) - continue; - - if (result.socketType != SocketType_UDP) - continue; - - hostnameAddress = result.address; - break; //< Take first valid address - } - - return Connect(hostnameAddress); - } - - /*! - * \brief Listens to a socket - * \return true If successfully bound - * - * \param remoteAddress Address to listen to - */ - - bool RUdpConnection::Listen(const IpAddress& address) - { - if (!InitSocket(address.GetProtocol())) - return false; - - return m_socket.Bind(address) == SocketState_Bound; - } - - /*! - * \brief Polls the message - * \return true If there is a message - * - * \param message Message to poll - * - * \remark Produces a NazaraAssert if message is invalid - */ - - bool RUdpConnection::PollMessage(RUdpMessage* message) - { - NazaraAssert(message, "Invalid message"); - - if (m_receivedMessages.empty()) - return false; - - *message = std::move(m_receivedMessages.front()); - m_receivedMessages.pop(); - return true; - } - - /*! - * \brief Sends the packet to a peer - * \return true If peer exists (false may result from disconnected client) - * - * \param peerIp IpAddress of the peer - * \param priority Priority of the packet - * \param reliability Policy of reliability of the packet - * \param packet Packet to send - */ - - bool RUdpConnection::Send(const IpAddress& peerIp, PacketPriority priority, PacketReliability reliability, const NetPacket& packet) - { - auto it = m_peerByIP.find(peerIp); - if (it == m_peerByIP.end()) - return false; /// Silently fail (probably a disconnected client) - - EnqueuePacket(m_peers[it->second], priority, reliability, packet); - return true; - } - - /*! - * \brief Updates the reliable connection - */ - - void RUdpConnection::Update() - { - m_currentTime = m_clock.GetMicroseconds(); - - NetPacket receivedPacket; - IpAddress senderIp; - while (m_socket.ReceivePacket(&receivedPacket, &senderIp)) - OnPacketReceived(senderIp, std::move(receivedPacket)); - - //for (unsigned int i = m_activeClients.FindFirst(); i != m_activeClients.npos; i = m_activeClients.FindNext(i)) - //{ - // PeerData& clientData = m_peers[i]; - - CallOnExit resetIterator([this] () { m_peerIterator = m_peers.size(); }); - - for (m_peerIterator = 0; m_peerIterator < m_peers.size(); ++m_peerIterator) - { - PeerData& peer = m_peers[m_peerIterator]; - - UInt32 timeSinceLastPacket = static_cast(m_currentTime - peer.lastPacketTime); - if (timeSinceLastPacket > m_timeBeforeTimeOut) - { - DisconnectPeer(peer.index); - continue; - } - else if (timeSinceLastPacket > m_timeBeforePing) - { - if (m_currentTime - peer.lastPingTime > m_pingInterval) - { - NetPacket pingPacket(NetCode_Ping); - EnqueuePacket(peer, PacketPriority_Low, PacketReliability_Unreliable, pingPacket); - } - } - - if (peer.state == PeerState_WillAck && m_currentTime - peer.stateData1 > m_forceAckSendTime) - { - NetPacket acknowledgePacket(NetCode_Acknowledge); - EnqueuePacket(peer, PacketPriority_Low, PacketReliability_Reliable, acknowledgePacket); - } - - for (unsigned int priority = PacketPriority_Highest; priority <= PacketPriority_Lowest; ++priority) - { - std::vector& pendingPackets = peer.pendingPackets[priority]; - for (PendingPacket& packetData : pendingPackets) - SendPacket(peer, std::move(packetData)); - - pendingPackets.clear(); - } - - auto it = peer.pendingAckQueue.begin(); - while (it != peer.pendingAckQueue.end()) - { - if (m_currentTime - it->timeSent > 2 * peer.roundTripTime) - { - OnPacketLost(peer, std::move(*it)); - it = peer.pendingAckQueue.erase(it); - } - else - ++it; - } - } - //m_activeClients.Reset(); - } - - /*! - * \brief Disconnects a peer - * - * \param peerIndex Index of the peer - * - * \remark Produces a NazaraNotice - */ - - void RUdpConnection::DisconnectPeer(std::size_t peerIndex) - { - PeerData& peer = m_peers[peerIndex]; - NazaraNotice(m_socket.GetBoundAddress().ToString() + ": " + peer.address.ToString() + " has been disconnected due to time-out"); - - OnPeerDisconnected(this, peer.address); - - // Remove from IP lookup table - m_peerByIP.erase(peer.address); - - // Can we safely "remove" this slot? - if (m_peerIterator >= m_peers.size() - 1 || peerIndex > m_peerIterator) - { - // Yes we can - PeerData& newSlot = m_peers[peerIndex]; - newSlot = std::move(m_peers.back()); - newSlot.index = peerIndex; //< Update the moved slot index before resizing (in case it's the last one) - } - else - { - // Nope, let's be tricky - PeerData& current = m_peers[m_peerIterator]; - PeerData& newSlot = m_peers[peerIndex]; - - newSlot = std::move(current); - newSlot.index = peerIndex; //< Update the moved slot index - - current = std::move(m_peers.back()); - current.index = m_peerIterator; //< Update the moved slot index - - --m_peerIterator; - } - - // Pop the last entry (from where we moved our slot) - m_peers.pop_back(); - } - - /*! - * \brief Enqueues a packet in the sending list - * - * \param peer Data relative to the peer - * \param priority Priority of the packet - * \param reliability Policy of reliability of the packet - * \param packet Packet to send - */ - - void RUdpConnection::EnqueuePacket(PeerData& peer, PacketPriority priority, PacketReliability reliability, const NetPacket& packet) - { - UInt16 protocolBegin = static_cast(m_protocol & 0xFFFF); - UInt16 protocolEnd = static_cast((m_protocol & 0xFFFF0000) >> 16); - - NetPacket data(packet.GetNetCode(), MessageHeader + packet.GetDataSize() + MessageFooter); - data << protocolBegin; - - data.GetStream()->SetCursorPos(NetPacket::HeaderSize + MessageHeader); - data.Write(packet.GetConstData() + NetPacket::HeaderSize, packet.GetDataSize()); - - data << protocolEnd; - EnqueuePacketInternal(peer, priority, reliability, std::move(data)); - } - - /*! - * \brief Enqueues internally a packet in the sending list - * - * \param peer Data relative to the peer - * \param priority Priority of the packet - * \param reliability Policy of reliability of the packet - * \param packet Packet to send - */ - - void RUdpConnection::EnqueuePacketInternal(PeerData& peer, PacketPriority priority, PacketReliability reliability, NetPacket&& data) - { - PendingPacket pendingPacket; - pendingPacket.data = std::move(data); - pendingPacket.priority = priority; - pendingPacket.reliability = reliability; - - peer.pendingPackets[priority].emplace_back(std::move(pendingPacket)); - m_activeClients.UnboundedSet(peer.index); - } - - /*! - * \brief Inits the internal socket - * \return true If successful - * - * \param protocol Net protocol to use - */ - - bool RUdpConnection::InitSocket(NetProtocol protocol) - { - CallOnExit updateLastError([this] - { - m_lastError = m_socket.GetLastError(); - }); - - if (!m_socket.Create(protocol)) - return false; - - m_socket.EnableBlocking(false); - return true; - } - - /*! - * \brief Processes the acks - * - * \param peer Data relative to the peer - * \param lastAck Last index of the ack - * \param ackBits Bits for acking - */ - - void RUdpConnection::ProcessAcks(PeerData& peer, SequenceIndex lastAck, UInt32 ackBits) - { - auto it = peer.pendingAckQueue.begin(); - while (it != peer.pendingAckQueue.end()) - { - bool acked = false; - if (lastAck == it->sequenceId) - acked = true; - else if (!IsAckMoreRecent(it->sequenceId, lastAck)) - { - unsigned int difference = ComputeSequenceDifference(lastAck, it->sequenceId); - if (difference <= 32) - acked = (ackBits >> (difference - 1)) & 1; - } - - if (acked) - { - it = peer.pendingAckQueue.erase(it); - } - else - ++it; - } - } - - /*! - * \brief Registers a peer - * \return Data relative to the peer - * - * \param address Address of the peer - * \param state Status of the peer - */ - - RUdpConnection::PeerData& RUdpConnection::RegisterPeer(const IpAddress& address, PeerState state) - { - PeerData data; - data.address = address; - data.localSequence = 0; - data.remoteSequence = 0; - data.index = m_peers.size(); - data.lastPacketTime = m_currentTime; - data.lastPingTime = m_currentTime; - data.roundTripTime = 1'000'000; ///< Okay that's quite a lot - data.state = state; - - m_activeClients.UnboundedSet(data.index); - m_peerByIP[address] = data.index; - - m_peers.emplace_back(std::move(data)); - return m_peers.back(); - } - - /*! - * \brief Operation to do when client requests a connection - * - * \param address Address of the peer - * \param sequenceId Sequence index for the ack - * \param token Token for connection - */ - - void RUdpConnection::OnClientRequestingConnection(const IpAddress& address, SequenceIndex sequenceId, UInt64 token) - { - // Call hook to check if client should be accepted or not - OnPeerConnection(this, address); - - PeerData& client = RegisterPeer(address, PeerState_Aknowledged); - client.remoteSequence = sequenceId; - - /// Acknowledge connection - NetPacket connectionAcceptedPacket(NetCode_AcknowledgeConnection); - //connectionAcceptedPacket << address; - connectionAcceptedPacket << ~token; - - EnqueuePacket(client, PacketPriority_Immediate, PacketReliability_Reliable, connectionAcceptedPacket); - } - - /*! - * \brief Operation to do when a packet is lost - * - * \param peer Data relative to the peer - * \param packet Pending packet - */ - - void RUdpConnection::OnPacketLost(PeerData& peer, PendingAckPacket&& packet) - { - //NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Lost packet " + NumberToString(packet.sequenceId)); - - if (IsReliable(packet.reliability)) - EnqueuePacketInternal(peer, packet.priority, packet.reliability, std::move(packet.data)); - } - - /*! - * \brief Operation to do when receiving a packet - * - * \param peerIndex Index of the peer - * - * \remark Produces a NazaraNotice - */ - - void RUdpConnection::OnPacketReceived(const IpAddress& peerIp, NetPacket&& packet) - { - UInt16 protocolBegin; - UInt16 protocolEnd; - SequenceIndex sequenceId; - SequenceIndex lastAck; - UInt32 ackBits; - - packet.GetStream()->SetCursorPos(packet.GetSize() - MessageFooter); - packet >> protocolEnd; - - packet.GetStream()->SetCursorPos(NetPacket::HeaderSize); - packet >> protocolBegin; - - UInt32 protocolId = static_cast(protocolEnd) << 16 | protocolBegin; - if (protocolId != m_protocol) - return; ///< Ignore - - packet >> sequenceId >> lastAck >> ackBits; - - auto it = m_peerByIP.find(peerIp); - if (it == m_peerByIP.end()) - { - switch (packet.GetNetCode()) - { - case NetCode_RequestConnection: - { - UInt64 token; - packet >> token; - - NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Received NetCode_RequestConnection from " + peerIp.ToString() + ": " + NumberToString(token)); - if (!m_shouldAcceptConnections) - return; //< Ignore - - OnClientRequestingConnection(peerIp, sequenceId, token); - break; - } - - default: - return; //< Ignore - } - } - else - { - PeerData& peer = m_peers[it->second]; - peer.lastPacketTime = m_currentTime; - - if (peer.receivedQueue.find(sequenceId) != peer.receivedQueue.end()) - return; //< Ignore - - if (m_isSimulationEnabled && m_packetLossProbability(s_randomGenerator)) - { - NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Lost packet " + NumberToString(sequenceId) + " from " + peerIp.ToString() + " for simulation purpose"); - return; - } - - ///< Receiving a packet from an acknowledged client means the connection works in both ways - if (peer.state == PeerState_Aknowledged && packet.GetNetCode() != NetCode_RequestConnection) - { - peer.state = PeerState_Connected; - OnPeerAcknowledged(this, peerIp); - } - - if (IsAckMoreRecent(sequenceId, peer.remoteSequence)) - peer.remoteSequence = sequenceId; - - ProcessAcks(peer, lastAck, ackBits); - - peer.receivedQueue.insert(sequenceId); - - switch (packet.GetNetCode()) - { - case NetCode_Acknowledge: - return; //< Do not switch to will ack mode (to prevent infinite replies, just let's ping/pong do that) - - case NetCode_AcknowledgeConnection: - { - if (peer.state == PeerState_Connected) - break; - - IpAddress externalAddress; - UInt64 token; - packet /*>> externalAddress*/ >> token; - - NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Received NetCode_AcknowledgeConnection from " + peerIp.ToString() + ": " + NumberToString(token)); - if (token == ~peer.stateData1) - { - peer.state = PeerState_Connected; - OnConnectedToPeer(this); - } - else - { - NazaraNotice("Received wrong token (" + NumberToString(token) + " instead of " + NumberToString(~peer.stateData1) + ") from client " + peer.address.ToString()); - return; //< Ignore - } - - break; - } - - case NetCode_RequestConnection: - NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Received NetCode_RequestConnection from " + peerIp.ToString()); - return; //< Ignore - - case NetCode_Ping: - { - NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Received NetCode_Ping from " + peerIp.ToString()); - - NetPacket pongPacket(NetCode_Pong); - EnqueuePacket(peer, PacketPriority_Low, PacketReliability_Unreliable, pongPacket); - break; - } - - case NetCode_Pong: - NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Received NetCode_Pong from " + peerIp.ToString()); - break; - - default: - { - NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Received 0x" + NumberToString(packet.GetNetCode(), 16) + " from " + peerIp.ToString()); - RUdpMessage receivedMessage; - receivedMessage.from = peerIp; - receivedMessage.data = std::move(packet); - - m_receivedMessages.emplace(std::move(receivedMessage)); - break; - } - } - - if (!HasPendingPackets(peer)) - { - peer.state = PeerState_WillAck; - peer.stateData1 = m_currentTime; - } - } - } - - /*! - * \brief Sends a packet to a peer - * - * \param peer Data relative to the peer - * \param packet Pending packet - */ - - void RUdpConnection::SendPacket(PeerData& peer, PendingPacket&& packet) - { - if (peer.state == PeerState_WillAck) - peer.state = PeerState_Connected; - - SequenceIndex remoteSequence = peer.remoteSequence; - - UInt32 previousAcks = 0; - for (SequenceIndex ack : peer.receivedQueue) - { - if (ack == remoteSequence) - continue; - - unsigned int difference = ComputeSequenceDifference(remoteSequence, ack); - if (difference <= 32U) - previousAcks |= (1U << (difference - 1)); - } - - SequenceIndex sequenceId = ++peer.localSequence; - - packet.data.GetStream()->SetCursorPos(NetPacket::HeaderSize + sizeof(UInt16)); ///< Protocol begin has already been filled - packet.data << sequenceId; - packet.data << remoteSequence; - packet.data << previousAcks; - - m_socket.SendPacket(peer.address, packet.data); - - PendingAckPacket pendingAckPacket; - pendingAckPacket.data = std::move(packet.data); - pendingAckPacket.priority = packet.priority; - pendingAckPacket.reliability = packet.reliability; - pendingAckPacket.sequenceId = sequenceId; - pendingAckPacket.timeSent = m_currentTime; - - peer.pendingAckQueue.emplace_back(std::move(pendingAckPacket)); - } - - /*! - * \brief Initializes the RUdpConnection class - * \return true - */ - - bool RUdpConnection::Initialize() - { - std::random_device device; - s_randomGenerator.seed(device()); - - return true; - } - - /*! - * \brief Uninitializes the RUdpConnection class - */ - - void RUdpConnection::Uninitialize() - { - } - - std::mt19937_64 RUdpConnection::s_randomGenerator; -} diff --git a/src/Nazara/Network/SocketPoller.cpp b/src/Nazara/Network/SocketPoller.cpp index 93c6d21a1..4ff4235b2 100644 --- a/src/Nazara/Network/SocketPoller.cpp +++ b/src/Nazara/Network/SocketPoller.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include #include @@ -24,7 +25,7 @@ namespace Nz /*! * \ingroup network * \class Nz::SocketPoller - * \brief Network class allowing an application to wait on multiples sockets for them to become active (readable) + * \brief Network class allowing an application to wait on multiples sockets for them to become active (readable/writeable) */ /*! @@ -194,10 +195,10 @@ namespace Nz if (error) *error = waitError; - if (waitError != SocketError_NoError) + if (waitError != SocketError::NoError) { - if (waitError != SocketError_Interrupted) //< Do not log interrupted error - NazaraError("SocketPoller encountered an error (code: 0x" + NumberToString(waitError, 16) + "): " + ErrorToString(waitError)); + if (waitError != SocketError::Interrupted) //< Do not log interrupted error + NazaraError("SocketPoller encountered an error (code: 0x" + NumberToString(UnderlyingCast(waitError), 16) + "): " + ErrorToString(waitError)); return 0; } diff --git a/src/Nazara/Network/TcpClient.cpp b/src/Nazara/Network/TcpClient.cpp index ecff0e6e4..d14a3a332 100644 --- a/src/Nazara/Network/TcpClient.cpp +++ b/src/Nazara/Network/TcpClient.cpp @@ -56,7 +56,7 @@ namespace Nz } SocketState state = SocketImpl::Connect(m_handle, remoteAddress, &m_lastError); - m_peerAddress = (state != SocketState_NotConnected) ? remoteAddress : IpAddress::Invalid; + m_peerAddress = (state != SocketState::NotConnected) ? remoteAddress : IpAddress::Invalid; UpdateState(state); return state; @@ -75,13 +75,13 @@ namespace Nz SocketState TcpClient::Connect(const std::string& hostName, NetProtocol protocol, const std::string& service, ResolveError* error) { - UpdateState(SocketState_Resolving); + UpdateState(SocketState::Resolving); std::vector results = IpAddress::ResolveHostname(protocol, hostName, service, error); if (results.empty()) { - m_lastError = SocketError_ResolveError; + m_lastError = SocketError::ResolveError; - UpdateState(SocketState_NotConnected); + UpdateState(SocketState::NotConnected); return m_state; } @@ -91,7 +91,7 @@ namespace Nz if (!result.address) continue; - if (result.socketType != SocketType_TCP) + if (result.socketType != SocketType::TCP) continue; hostnameAddress = result.address; @@ -176,7 +176,7 @@ namespace Nz /*! * \brief Polls the connection status of the currently connecting socket - * \return New socket state, which maybe unchanged (if connecting is still pending), SocketState_Connected if connection is successful or SocketState_NotConnected if connection failed + * \return New socket state, which maybe unchanged (if connecting is still pending), SocketState::Connected if connection is successful or SocketState::NotConnected if connection failed * * This functions checks if the pending connection has either succeeded, failed or is still processing at the time of the call. * @@ -188,16 +188,16 @@ namespace Nz { switch (m_state) { - case SocketState_Connecting: + case SocketState::Connecting: { NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Invalid handle"); SocketState newState = SocketImpl::PollConnection(m_handle, m_peerAddress, waitDuration, &m_lastError); // Prevent valid peer address in non-connected state - if (newState == SocketState_NotConnected) + if (newState == SocketState::NotConnected) { - m_openMode = OpenMode_NotOpen; + m_openMode = OpenMode::NotOpen; m_peerAddress = IpAddress::Invalid; } @@ -205,16 +205,16 @@ namespace Nz return newState; } - case SocketState_Connected: - case SocketState_NotConnected: + case SocketState::Connected: + case SocketState::NotConnected: return m_state; - case SocketState_Bound: - case SocketState_Resolving: + case SocketState::Bound: + case SocketState::Resolving: break; } - NazaraInternalError("Unexpected socket state (0x" + NumberToString(m_state, 16) + ')'); + NazaraInternalError("Unexpected socket state (0x" + NumberToString(UnderlyingCast(m_state), 16) + ')'); return m_state; } @@ -240,9 +240,9 @@ namespace Nz { switch (m_lastError) { - case SocketError_ConnectionClosed: - case SocketError_ConnectionRefused: - UpdateState(SocketState_NotConnected); + case SocketError::ConnectionClosed: + case SocketError::ConnectionRefused: + UpdateState(SocketState::NotConnected); break; default: @@ -255,7 +255,7 @@ namespace Nz if (received) *received = read; - UpdateState(SocketState_Connected); + UpdateState(SocketState::Connected); return true; } @@ -292,7 +292,7 @@ namespace Nz UInt32 size; if (!NetPacket::DecodeHeader(m_pendingPacket.data.GetConstBuffer(), &size, &m_pendingPacket.netcode)) { - m_lastError = SocketError_Packet; + m_lastError = SocketError::Packet; NazaraWarning("Invalid header data"); return false; } @@ -361,8 +361,9 @@ namespace Nz NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Invalid handle"); NazaraAssert(buffer && size > 0, "Invalid buffer"); - CallOnExit updateSent; std::size_t totalByteSent = 0; + + CallOnExit updateSent; if (sent) { updateSent.Reset([sent, &totalByteSent] () @@ -379,9 +380,9 @@ namespace Nz { switch (m_lastError) { - case SocketError_ConnectionClosed: - case SocketError_ConnectionRefused: - UpdateState(SocketState_NotConnected); + case SocketError::ConnectionClosed: + case SocketError::ConnectionRefused: + UpdateState(SocketState::NotConnected); break; default: @@ -394,7 +395,7 @@ namespace Nz totalByteSent += sentSize; } - UpdateState(SocketState_Connected); + UpdateState(SocketState::Connected); return true; } @@ -415,9 +416,9 @@ namespace Nz { switch (m_lastError) { - case SocketError_ConnectionClosed: - case SocketError_ConnectionRefused: - UpdateState(SocketState_NotConnected); + case SocketError::ConnectionClosed: + case SocketError::ConnectionRefused: + UpdateState(SocketState::NotConnected); break; default: @@ -433,7 +434,7 @@ namespace Nz if (sent) *sent = byteSent; - UpdateState(SocketState_Connected); + UpdateState(SocketState::Connected); return true; } @@ -452,7 +453,7 @@ namespace Nz const UInt8* ptr = static_cast(packet.OnSend(&size)); if (!ptr) { - m_lastError = SocketError_Packet; + m_lastError = SocketError::Packet; NazaraError("Failed to prepare packet"); return false; } @@ -491,20 +492,20 @@ namespace Nz { switch (m_state) { - case SocketState_Connecting: + case SocketState::Connecting: { NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Invalid handle"); SocketState newState = SocketImpl::PollConnection(m_handle, m_peerAddress, (msTimeout > 0) ? msTimeout : std::numeric_limits::max(), &m_lastError); // If connection is still pending after waiting, cancel it - if (newState == SocketState_Connecting) - newState = SocketState_NotConnected; + if (newState == SocketState::Connecting) + newState = SocketState::NotConnected; // Prevent valid stats in non-connected state - if (newState == SocketState_NotConnected) + if (newState == SocketState::NotConnected) { - m_openMode = OpenMode_NotOpen; + m_openMode = OpenMode::NotOpen; m_peerAddress = IpAddress::Invalid; } @@ -512,16 +513,16 @@ namespace Nz return newState; } - case SocketState_Connected: - case SocketState_NotConnected: + case SocketState::Connected: + case SocketState::NotConnected: return m_state; - case SocketState_Bound: - case SocketState_Resolving: + case SocketState::Bound: + case SocketState::Resolving: break; } - NazaraInternalError("Unhandled socket state (0x" + NumberToString(m_state, 16) + ')'); + NazaraInternalError("Unhandled socket state (0x" + NumberToString(UnderlyingCast(m_state), 16) + ')'); return m_state; } @@ -541,7 +542,7 @@ namespace Nz { AbstractSocket::OnClose(); - m_openMode = OpenMode_NotOpen; + m_openMode = OpenMode::NotOpen; m_peerAddress = IpAddress::Invalid; } @@ -558,10 +559,10 @@ namespace Nz SocketError errorCode; if (!SocketImpl::SetNoDelay(m_handle, m_isLowDelayEnabled, &errorCode)) - NazaraWarning("Failed to set socket no delay mode (0x" + NumberToString(errorCode, 16) + ')'); + NazaraWarning("Failed to set socket no delay mode (0x" + NumberToString(UnderlyingCast(errorCode), 16) + ')'); if (!SocketImpl::SetKeepAlive(m_handle, m_isKeepAliveEnabled, m_keepAliveTime, m_keepAliveInterval, &errorCode)) - NazaraWarning("Failed to set socket keep alive mode (0x" + NumberToString(errorCode, 16) + ')'); + NazaraWarning("Failed to set socket keep alive mode (0x" + NumberToString(UnderlyingCast(errorCode), 16) + ')'); m_peerAddress = IpAddress::Invalid; m_openMode = OpenMode_ReadWrite; @@ -610,7 +611,7 @@ namespace Nz Open(handle); m_peerAddress = peerAddress; m_openMode = OpenMode_ReadWrite; - UpdateState(SocketState_Connected); + UpdateState(SocketState::Connected); } /*! diff --git a/src/Nazara/Network/TcpServer.cpp b/src/Nazara/Network/TcpServer.cpp index e062d082a..7ff29b91b 100644 --- a/src/Nazara/Network/TcpServer.cpp +++ b/src/Nazara/Network/TcpServer.cpp @@ -66,7 +66,7 @@ namespace Nz Open(address.GetProtocol()); SocketState state = SocketImpl::Listen(m_handle, address, queueSize, &m_lastError); - if (state == SocketState_Bound) + if (state == SocketState::Bound) m_boundAddress = SocketImpl::QuerySocketAddress(m_handle); UpdateState(state); diff --git a/src/Nazara/Network/UdpSocket.cpp b/src/Nazara/Network/UdpSocket.cpp index e0209c427..0e521f879 100644 --- a/src/Nazara/Network/UdpSocket.cpp +++ b/src/Nazara/Network/UdpSocket.cpp @@ -41,7 +41,7 @@ namespace Nz NazaraAssert(address.IsValid(), "Invalid address"); SocketState state = SocketImpl::Bind(m_handle, address, &m_lastError); - if (state == SocketState_Bound) + if (state == SocketState::Bound) m_boundAddress = SocketImpl::QuerySocketAddress(m_handle); UpdateState(state); @@ -104,8 +104,8 @@ namespace Nz { switch (m_lastError) { - case SocketError_ConnectionClosed: - m_lastError = SocketError_NoError; + case SocketError::ConnectionClosed: + m_lastError = SocketError::NoError; read = 0; break; @@ -140,8 +140,8 @@ namespace Nz { switch (m_lastError) { - case SocketError_ConnectionClosed: - m_lastError = SocketError_NoError; + case SocketError::ConnectionClosed: + m_lastError = SocketError::NoError; read = 0; break; @@ -166,14 +166,13 @@ namespace Nz * \remark Produces a NazaraAssert if packet is invalid * \remark Produces a NazaraWarning if packet's header is invalid */ - bool UdpSocket::ReceivePacket(NetPacket* packet, IpAddress* from) { NazaraAssert(packet, "Invalid packet"); // I'm not sure what's the best between having a 65k bytes buffer ready for any datagram size // or querying the next datagram size every time, for now I'll leave it as is - packet->Reset(NetCode_Invalid, std::numeric_limits::max()); + packet->Reset(0, std::numeric_limits::max()); packet->Resize(std::numeric_limits::max()); std::size_t received; @@ -187,14 +186,14 @@ namespace Nz Nz::UInt32 packetSize; if (!NetPacket::DecodeHeader(packet->GetConstData(), &packetSize, &netCode)) { - m_lastError = SocketError_Packet; + m_lastError = SocketError::Packet; NazaraWarning("Invalid header data"); return false; } if (packetSize != received) { - m_lastError = SocketError_Packet; + m_lastError = SocketError::Packet; NazaraWarning("Invalid packet size (packet size is " + NumberToString(packetSize) + " bytes, received " + NumberToString(received) + " bytes)"); return false; } @@ -275,7 +274,7 @@ namespace Nz const UInt8* ptr = static_cast(packet.OnSend(&size)); if (!ptr) { - m_lastError = SocketError_Packet; + m_lastError = SocketError::Packet; NazaraError("Failed to prepare packet"); return false; } diff --git a/src/Nazara/Network/Win32/IpAddressImpl.cpp b/src/Nazara/Network/Win32/IpAddressImpl.cpp index 570cf8fe2..3f2913f69 100644 --- a/src/Nazara/Network/Win32/IpAddressImpl.cpp +++ b/src/Nazara/Network/Win32/IpAddressImpl.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include #include @@ -187,7 +188,7 @@ namespace Nz } if (error) - *error = ResolveError_NoError; + *error = ResolveError::NoError; return true; } @@ -228,7 +229,7 @@ namespace Nz } if (error) - *error = ResolveError_NoError; + *error = ResolveError::NoError; return results; } @@ -239,7 +240,7 @@ namespace Nz { switch (ipAddress.GetProtocol()) { - case NetProtocol_IPv4: + case NetProtocol::IPv4: { sockaddr_in* socketAddress = reinterpret_cast(buffer); @@ -251,7 +252,7 @@ namespace Nz return sizeof(sockaddr_in); } - case NetProtocol_IPv6: + case NetProtocol::IPv6: { sockaddr_in6* socketAddress = reinterpret_cast(buffer); @@ -271,7 +272,7 @@ namespace Nz } default: - NazaraInternalError("Unhandled ip protocol (0x" + NumberToString(ipAddress.GetProtocol()) + ')'); + NazaraInternalError("Unhandled ip protocol (0x" + NumberToString(UnderlyingCast(ipAddress.GetProtocol())) + ')'); break; } } @@ -285,13 +286,13 @@ namespace Nz switch (family) { case PF_INET: - return NetProtocol_IPv4; + return NetProtocol::IPv4; case PF_INET6: - return NetProtocol_IPv6; + return NetProtocol::IPv6; default: - return NetProtocol_Unknown; + return NetProtocol::Unknown; } } @@ -300,16 +301,16 @@ namespace Nz switch (socketType) { case SOCK_STREAM: - return SocketType_TCP; + return SocketType::TCP; case SOCK_DGRAM: - return SocketType_UDP; + return SocketType::UDP; case SOCK_RAW: - return SocketType_Raw; + return SocketType::Raw; default: - return SocketType_Unknown; + return SocketType::Unknown; } } @@ -318,35 +319,35 @@ namespace Nz switch (error) { case 0: - return ResolveError_NoError; + return ResolveError::NoError; // Engine error case WSAEFAULT: case WSAEINVAL: - return ResolveError_Internal; + return ResolveError::Internal; case WSAEAFNOSUPPORT: case WSAESOCKTNOSUPPORT: case WSASERVICE_NOT_FOUND: - return ResolveError_ProtocolNotSupported; + return ResolveError::ProtocolNotSupported; case WSAHOST_NOT_FOUND: - return ResolveError_NotFound; + return ResolveError::NotFound; case WSANO_RECOVERY: - return ResolveError_NonRecoverable; + return ResolveError::NonRecoverable; case WSANOTINITIALISED: - return ResolveError_NotInitialized; + return ResolveError::NotInitialized; case WSA_NOT_ENOUGH_MEMORY: - return ResolveError_ResourceError; + return ResolveError::ResourceError; case WSATRY_AGAIN: - return ResolveError_TemporaryFailure; + return ResolveError::TemporaryFailure; } NazaraWarning("Unhandled WinSock error: " + Error::GetLastSystemError(error) + " (" + NumberToString(error) + ')'); - return ResolveError_Unknown; + return ResolveError::Unknown; } } diff --git a/src/Nazara/Network/Win32/SocketImpl.cpp b/src/Nazara/Network/Win32/SocketImpl.cpp index 349dfea0a..27f9b9ca2 100644 --- a/src/Nazara/Network/Win32/SocketImpl.cpp +++ b/src/Nazara/Network/Win32/SocketImpl.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include #include @@ -52,7 +53,7 @@ namespace Nz *address = IpAddressImpl::FromSockAddr(reinterpret_cast(&nameBuffer)); if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; } else { @@ -76,19 +77,19 @@ namespace Nz if (error) *error = TranslateWSAErrorToSocketError(WSAGetLastError()); - return SocketState_NotConnected; + return SocketState::NotConnected; } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; - return SocketState_Bound; + return SocketState::Bound; } SocketHandle SocketImpl::Create(NetProtocol protocol, SocketType type, SocketError* error) { - NazaraAssert(protocol != NetProtocol_Any, "Any protocol is not supported for socket creation"); - NazaraAssert(type <= SocketType_Max, "Type has value out of enum"); + NazaraAssert(protocol != NetProtocol::Any, "Any protocol is not supported for socket creation"); + NazaraAssert(type <= SocketType::Max, "Type has value out of enum"); SocketHandle handle = socket(TranslateNetProtocolToAF(protocol), TranslateSocketTypeToSock(type), 0); if (handle == InvalidHandle && error != nullptr) @@ -109,7 +110,7 @@ namespace Nz { NazaraAssert(handle != InvalidHandle, "Invalid handle"); - if (GetLastError(handle, nullptr) < 0) + if (GetLastError(handle, nullptr) == SocketError::Internal) NazaraWarning("Failed to clear socket error code: " + Error::GetLastSystemError(WSAGetLastError())); } @@ -122,7 +123,7 @@ namespace Nz int bufferLength = IpAddressImpl::ToSockAddr(address, nameBuffer.data()); if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; // Clear socket error status ClearErrorCode(handle); @@ -135,24 +136,24 @@ namespace Nz case WSAEALREADY: case WSAEINVAL: //< In case of connect, WSAEINVAL may be returned instead of WSAEALREADY case WSAEWOULDBLOCK: - return SocketState_Connecting; + return SocketState::Connecting; case WSAEISCONN: - return SocketState_Connected; + return SocketState::Connected; } if (error) { if (errorCode == WSAEADDRNOTAVAIL) - *error = SocketError_ConnectionRefused; //< ConnectionRefused seems more legit than AddressNotAvailable in connect case + *error = SocketError::ConnectionRefused; //< ConnectionRefused seems more legit than AddressNotAvailable in connect case else *error = TranslateWSAErrorToSocketError(errorCode); } - return SocketState_NotConnected; + return SocketState::NotConnected; } - return SocketState_Connected; + return SocketState::Connected; } bool SocketImpl::Initialize() @@ -172,7 +173,7 @@ namespace Nz { int code = GetLastErrorCode(handle, error); if (code < 0) - return SocketError_Internal; + return SocketError::Internal; return TranslateWSAErrorToSocketError(code); } @@ -196,7 +197,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return code; } @@ -214,7 +215,7 @@ namespace Nz if (error) *error = TranslateWSAErrorToSocketError(WSAGetLastError()); - return SocketState_NotConnected; + return SocketState::NotConnected; } if (listen(handle, queueSize) == SOCKET_ERROR) @@ -222,13 +223,13 @@ namespace Nz if (error) *error = TranslateWSAErrorToSocketError(WSAGetLastError()); - return SocketState_NotConnected; + return SocketState::NotConnected; } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; - return SocketState_Bound; + return SocketState::Bound; } std::size_t SocketImpl::QueryAvailableBytes(SocketHandle handle, SocketError* error) @@ -245,7 +246,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return availableBytes; } @@ -264,7 +265,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return code == TRUE; } @@ -283,7 +284,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return code == TRUE; } @@ -302,7 +303,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return code; } @@ -321,7 +322,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return code == TRUE; } @@ -340,7 +341,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return code; } @@ -363,7 +364,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return IpAddressImpl::FromSockAddr(reinterpret_cast(nameBuffer.data())); } @@ -383,7 +384,7 @@ namespace Nz { int errorCode = WSAGetLastError(); if (errorCode == WSAEINVAL) - *error = SocketError_NoError; + *error = SocketError::NoError; else *error = TranslateWSAErrorToSocketError(errorCode); } @@ -392,7 +393,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return IpAddressImpl::FromSockAddr(reinterpret_cast(nameBuffer.data())); } @@ -411,7 +412,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return code; } @@ -436,7 +437,7 @@ namespace Nz assert(result >= 0); if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return static_cast(result); #else @@ -445,7 +446,7 @@ namespace Nz NazaraUnused(timeout); if (error) - *error = SocketError_NotSupported; + *error = SocketError::NotSupported; return 0; #endif @@ -453,54 +454,50 @@ namespace Nz SocketState SocketImpl::PollConnection(SocketHandle handle, const IpAddress& address, UInt64 msTimeout, SocketError* error) { - // http://developerweb.net/viewtopic.php?id=3196 - fd_set localSet; - FD_ZERO(&localSet); - FD_SET(handle, &localSet); + // Wait until socket is available for writing or an error occurs (ie when connection succeeds or fails) + WSAPOLLFD descriptor; + descriptor.events = POLLWRNORM; + descriptor.fd = handle; + descriptor.revents = 0; - timeval tv; - tv.tv_sec = static_cast(msTimeout / 1000ULL); - tv.tv_usec = static_cast((msTimeout % 1000ULL) * 1000ULL); - - int ret = ::select(0, nullptr, &localSet, &localSet, (msTimeout != std::numeric_limits::max()) ? &tv : nullptr); - if (ret > 0) - { - int code = GetLastErrorCode(handle, error); - if (code < 0) //< GetLastErrorCode() failed - return SocketState_NotConnected; - - if (code) - { - if (error) - *error = TranslateWSAErrorToSocketError(code); - - return SocketState_NotConnected; - } - } - else if (ret == 0) - { - if (error) - { - if (msTimeout > 0) - *error = SocketError_TimedOut; - else - *error = SocketError_NoError; - } - - return SocketState_Connecting; - } - else + int ret = WSAPoll(&descriptor, 1, (msTimeout != std::numeric_limits::max()) ? INT(msTimeout) : INT(-1)); + if (ret == SOCKET_ERROR) { if (error) *error = TranslateWSAErrorToSocketError(WSAGetLastError()); - return SocketState_NotConnected; + return SocketState::NotConnected; } + else if (ret > 0) + { + if (descriptor.revents & (POLLERR | POLLHUP)) + { + if (error) + *error = GetLastError(handle); - if (error) - *error = SocketError_NoError; + return SocketState::NotConnected; + } + else if (descriptor.revents & POLLWRNORM) + return SocketState::Connected; + else + { + NazaraWarning("Socket " + std::to_string(handle) + " was returned by poll without POLLOUT nor error events (events: 0x" + NumberToString(descriptor.revents, 16) + ')'); + return SocketState::NotConnected; + } + } + else + { + // Still connecting + if (error) + { + if (msTimeout > 0) + *error = SocketError::TimedOut; + else + *error = SocketError::NoError; + } - return SocketState_Connected; + return SocketState::Connecting; + } } bool SocketImpl::Receive(SocketHandle handle, void* buffer, int length, int* read, SocketError* error) @@ -533,7 +530,7 @@ namespace Nz else if (byteRead == 0) { if (error) - *error = SocketError_ConnectionClosed; + *error = SocketError::ConnectionClosed; return false; //< Connection has been closed } @@ -542,7 +539,7 @@ namespace Nz *read = byteRead; if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return true; } @@ -585,7 +582,7 @@ namespace Nz else if (byteRead == 0) { if (error) - *error = SocketError_ConnectionClosed; + *error = SocketError::ConnectionClosed; return false; //< Connection closed } @@ -599,7 +596,7 @@ namespace Nz *read = byteRead; if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return true; } @@ -654,7 +651,7 @@ namespace Nz if (flags & MSG_PARTIAL) { if (error) - *error = SocketError_DatagramSize; + *error = SocketError::DatagramSize; return false; } @@ -666,7 +663,7 @@ namespace Nz *read = byteRead; if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return true; } @@ -702,7 +699,7 @@ namespace Nz *sent = byteSent; if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return true; } @@ -748,7 +745,7 @@ namespace Nz *sent = static_cast(byteSent); if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return true; } @@ -787,7 +784,7 @@ namespace Nz *sent = byteSent; if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return true; } @@ -806,7 +803,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return true; } @@ -825,7 +822,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return true; } @@ -845,12 +842,12 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return true; #else if (error) - *error = SocketError_NotSupported; + *error = SocketError::NotSupported; return false; #endif @@ -875,7 +872,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return true; } @@ -894,7 +891,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return true; } @@ -913,7 +910,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return true; } @@ -932,7 +929,7 @@ namespace Nz } if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; return true; } @@ -942,7 +939,7 @@ namespace Nz switch (error) { case 0: - return SocketError_NoError; + return SocketError::NoError; // Engine error case WSAEACCES: @@ -957,82 +954,82 @@ namespace Nz case WSAEISCONN: case WSAEWOULDBLOCK: NazaraWarning("Internal error occurred: " + Error::GetLastSystemError(error) + " (" + NumberToString(error) + ')'); - return SocketError_Internal; + return SocketError::Internal; case WSAEADDRNOTAVAIL: case WSAEADDRINUSE: - return SocketError_AddressNotAvailable; + return SocketError::AddressNotAvailable; case WSAEAFNOSUPPORT: case WSAEPFNOSUPPORT: case WSAEOPNOTSUPP: case WSAEPROTONOSUPPORT: case WSAESOCKTNOSUPPORT: - return SocketError_NotSupported; + return SocketError::NotSupported; case WSAECONNREFUSED: - return SocketError_ConnectionRefused; + return SocketError::ConnectionRefused; case WSAECONNABORTED: case WSAECONNRESET: case WSAENOTCONN: case WSAESHUTDOWN: - return SocketError_ConnectionClosed; + return SocketError::ConnectionClosed; case WSAEMSGSIZE: - return SocketError_DatagramSize; + return SocketError::DatagramSize; case WSAEMFILE: case WSAENOBUFS: case WSA_NOT_ENOUGH_MEMORY: - return SocketError_ResourceError; + return SocketError::ResourceError; case WSAEHOSTUNREACH: - return SocketError_UnreachableHost; + return SocketError::UnreachableHost; case WSAENETDOWN: case WSAENETUNREACH: - return SocketError_NetworkError; + return SocketError::NetworkError; case WSANOTINITIALISED: - return SocketError_NotInitialized; + return SocketError::NotInitialized; case WSAETIMEDOUT: - return SocketError_TimedOut; + return SocketError::TimedOut; } NazaraWarning("Unhandled WinSock error: " + Error::GetLastSystemError(error) + " (" + NumberToString(error) + ')'); - return SocketError_Unknown; + return SocketError::Unknown; } int SocketImpl::TranslateNetProtocolToAF(NetProtocol protocol) { - NazaraAssert(protocol <= NetProtocol_Max, "Protocol has value out of enum"); + NazaraAssert(protocol <= NetProtocol::Max, "Protocol has value out of enum"); static int addressFamily[] = { - AF_UNSPEC, //< NetProtocol_Any - AF_INET, //< NetProtocol_IPv4 - AF_INET6, //< NetProtocol_IPv6 - -1 //< NetProtocol_Unknown + AF_UNSPEC, //< NetProtocol::Any + AF_INET, //< NetProtocol::IPv4 + AF_INET6, //< NetProtocol::IPv6 + -1 //< NetProtocol::Unknown }; - static_assert(sizeof(addressFamily) / sizeof(int) == NetProtocol_Max + 1, "Address family array is incomplete"); + static_assert(sizeof(addressFamily) / sizeof(int) == NetProtocolCount, "Address family array is incomplete"); - return addressFamily[protocol]; + return addressFamily[UnderlyingCast(protocol)]; } int SocketImpl::TranslateSocketTypeToSock(SocketType type) { - NazaraAssert(type <= SocketType_Max, "Socket type has value out of enum"); + NazaraAssert(type <= SocketType::Max, "Socket type has value out of enum"); static int socketType[] = { - SOCK_RAW, //< SocketType_Raw - SOCK_STREAM, //< SocketType_TCP - SOCK_DGRAM, //< SocketType_UDP - -1 //< SocketType_Unknown + SOCK_RAW, //< SocketType::Raw + SOCK_STREAM, //< SocketType::TCP + SOCK_DGRAM, //< SocketType::UDP + -1 //< SocketType::Unknown }; - static_assert(sizeof(socketType) / sizeof(int) == SocketType_Max + 1, "Socket type array is incomplete"); + static_assert(sizeof(socketType) / sizeof(int) == SocketTypeCount, "Socket type array is incomplete"); - return socketType[type]; + return socketType[UnderlyingCast(type)]; } void SocketImpl::Uninitialize() diff --git a/src/Nazara/Network/Win32/SocketPollerImpl.cpp b/src/Nazara/Network/Win32/SocketPollerImpl.cpp index 927d0b447..6d56129dd 100644 --- a/src/Nazara/Network/Win32/SocketPollerImpl.cpp +++ b/src/Nazara/Network/Win32/SocketPollerImpl.cpp @@ -74,10 +74,10 @@ namespace Nz 0 }; - if (eventFlags & SocketPollEvent_Read) + if (eventFlags & SocketPollEvent::Read) entry.events |= POLLRDNORM; - if (eventFlags & SocketPollEvent_Write) + if (eventFlags & SocketPollEvent::Write) entry.events |= POLLWRNORM; m_allSockets[socket] = m_sockets.size(); @@ -85,7 +85,7 @@ namespace Nz #else for (std::size_t i = 0; i < 2; ++i) { - if ((eventFlags & ((i == 0) ? SocketPollEvent_Read : SocketPollEvent_Write)) == 0) + if ((eventFlags & ((i == 0) ? SocketPollEvent::Read : SocketPollEvent::Write)) == 0) continue; fd_set& targetSet = (i == 0) ? m_readSockets : m_writeSockets; @@ -202,7 +202,7 @@ namespace Nz activeSockets = static_cast(selectValue); if (error) - *error = SocketError_NoError; + *error = SocketError::NoError; #endif return activeSockets; diff --git a/src/Nazara/OpenGLRenderer/OpenGLBuffer.cpp b/src/Nazara/OpenGLRenderer/OpenGLBuffer.cpp index 236380511..61ae3f075 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLBuffer.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLBuffer.cpp @@ -19,7 +19,7 @@ namespace Nz bool OpenGLBuffer::Fill(const void* data, UInt64 offset, UInt64 size) { - m_buffer.SubData(offset, size, data); + m_buffer.SubData(GLintptr(offset), GLsizeiptr(size), data); return true; } @@ -31,9 +31,9 @@ namespace Nz GL::BufferTarget target; switch (m_type) { - case BufferType_Index: target = GL::BufferTarget::ElementArray; break; - case BufferType_Uniform: target = GL::BufferTarget::Uniform; break; - case BufferType_Vertex: target = GL::BufferTarget::Array; break; + case BufferType::Index: target = GL::BufferTarget::ElementArray; break; + case BufferType::Uniform: target = GL::BufferTarget::Uniform; break; + case BufferType::Vertex: target = GL::BufferTarget::Array; break; default: throw std::runtime_error("unknown buffer type 0x" + NumberToString(UnderlyingCast(m_type), 16)); @@ -41,12 +41,12 @@ namespace Nz GLenum hint = GL_STREAM_COPY; - if (usage & BufferUsage_Dynamic) + if (usage & BufferUsage::Dynamic) hint = GL_DYNAMIC_DRAW; - else if (usage & BufferUsage_DeviceLocal) + else if (usage & BufferUsage::DeviceLocal) hint = GL_STATIC_DRAW; - if (usage & BufferUsage_DirectMapping) + if (usage & BufferUsage::DirectMapping) hint = GL_DYNAMIC_COPY; m_buffer.Reset(target, size, nullptr, hint); @@ -60,7 +60,7 @@ namespace Nz DataStorage OpenGLBuffer::GetStorage() const { - return DataStorage_Hardware; + return DataStorage::Hardware; } void* OpenGLBuffer::Map(BufferAccess access, UInt64 offset, UInt64 size) @@ -68,7 +68,7 @@ namespace Nz GLbitfield accessBit = 0; switch (access) { - case BufferAccess_DiscardAndWrite: + case BufferAccess::DiscardAndWrite: accessBit |= GL_MAP_WRITE_BIT; if (offset == 0 && size == m_size) accessBit |= GL_MAP_INVALIDATE_BUFFER_BIT; @@ -77,15 +77,15 @@ namespace Nz break; - case BufferAccess_ReadOnly: + case BufferAccess::ReadOnly: accessBit |= GL_MAP_READ_BIT; break; - case BufferAccess_ReadWrite: + case BufferAccess::ReadWrite: accessBit |= GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; break; - case BufferAccess_WriteOnly: + case BufferAccess::WriteOnly: accessBit |= GL_MAP_WRITE_BIT; break; diff --git a/src/Nazara/OpenGLRenderer/OpenGLCommandBuffer.cpp b/src/Nazara/OpenGLRenderer/OpenGLCommandBuffer.cpp index f23eba582..7066d8384 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLCommandBuffer.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLCommandBuffer.cpp @@ -3,7 +3,9 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include +#include #include #include #include @@ -17,39 +19,39 @@ namespace Nz { switch (component) { - case ComponentType_Color: + case ComponentType::Color: attrib.normalized = GL_TRUE; attrib.size = 4; attrib.type = GL_UNSIGNED_BYTE; return; - case ComponentType_Float1: - case ComponentType_Float2: - case ComponentType_Float3: - case ComponentType_Float4: + case ComponentType::Float1: + case ComponentType::Float2: + case ComponentType::Float3: + case ComponentType::Float4: attrib.normalized = GL_FALSE; - attrib.size = (component - ComponentType_Float1 + 1); + attrib.size = (UnderlyingCast(component) - UnderlyingCast(ComponentType::Float1) + 1); attrib.type = GL_FLOAT; return; - case ComponentType_Int1: - case ComponentType_Int2: - case ComponentType_Int3: - case ComponentType_Int4: + case ComponentType::Int1: + case ComponentType::Int2: + case ComponentType::Int3: + case ComponentType::Int4: attrib.normalized = GL_FALSE; - attrib.size = (component - ComponentType_Int1 + 1); + attrib.size = (UnderlyingCast(component) - UnderlyingCast(ComponentType::Int1) + 1); attrib.type = GL_INT; return; - case ComponentType_Double1: - case ComponentType_Double2: - case ComponentType_Double3: - case ComponentType_Double4: - case ComponentType_Quaternion: + case ComponentType::Double1: + case ComponentType::Double2: + case ComponentType::Double3: + case ComponentType::Double4: + case ComponentType::Quaternion: break; } - throw std::runtime_error("component type 0x" + NumberToString(component, 16) + " is not handled"); + throw std::runtime_error("component type 0x" + NumberToString(UnderlyingCast(component), 16) + " is not handled"); } } @@ -57,15 +59,22 @@ namespace Nz { const GL::Context* context = GL::Context::GetCurrentContext(); + StackArray fboDrawBuffers = NazaraStackArrayNoInit(GLenum, m_maxColorBufferCount); + for (std::size_t i = 0; i < m_maxColorBufferCount; ++i) + fboDrawBuffers[i] = GLenum(GL_COLOR_ATTACHMENT0 + i); + + StackArray colorIndexes = NazaraStackArrayNoInit(std::size_t, m_maxColorBufferCount); + for (const auto& commandVariant : m_commands) { std::visit([&](auto&& command) { using T = std::decay_t; - if constexpr (std::is_same_v || std::is_same_v) + if constexpr (std::is_same_v) { - // TODO + if (context->glPushDebugGroup) + context->glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, GLsizei(command.regionName.size()), command.regionName.data()); } else if constexpr (std::is_same_v) { @@ -80,20 +89,148 @@ namespace Nz } else if constexpr (std::is_same_v) { - ApplyStates(*context, m_currentStates); - context->glDrawArraysInstanced(GL_TRIANGLES, command.firstVertex, command.vertexCount, command.instanceCount); + ApplyStates(*context, command.states); + context->glDrawArraysInstanced(ToOpenGL(command.states.pipeline->GetPipelineInfo().primitiveMode), command.firstVertex, command.vertexCount, command.instanceCount); } else if constexpr (std::is_same_v) { - ApplyStates(*context, m_currentStates); - context->glDrawElementsInstanced(GL_TRIANGLES, command.indexCount, GL_UNSIGNED_SHORT, nullptr, command.instanceCount); + ApplyStates(*context, command.states); + context->glDrawElementsInstanced(ToOpenGL(command.states.pipeline->GetPipelineInfo().primitiveMode), command.indexCount, GL_UNSIGNED_SHORT, nullptr, command.instanceCount); + } + else if constexpr (std::is_same_v) + { + if (context->glPopDebugGroup) + context->glPopDebugGroup(); } else if constexpr (std::is_same_v) { command.framebuffer->Activate(); context = GL::Context::GetCurrentContext(); - context->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + std::size_t colorBufferCount = command.framebuffer->GetColorBufferCount(); + assert(colorBufferCount <= fboDrawBuffers.size()); + + colorIndexes.fill(0); + std::size_t colorIndex = 0; + + GLbitfield clearFields = 0; + std::optional depthStencilIndex; + + std::size_t attachmentCount = command.renderpass->GetAttachmentCount(); + + for (std::size_t i = 0; i < attachmentCount; ++i) + { + const auto& attachmentInfo = command.renderpass->GetAttachment(i); + switch (PixelFormatInfo::GetContent(attachmentInfo.format)) + { + case PixelFormatContent::ColorRGBA: + colorIndexes[colorIndex++] = i; + break; + + case PixelFormatContent::Depth: + if (!depthStencilIndex) + depthStencilIndex = i; + break; + + case PixelFormatContent::DepthStencil: + if (!depthStencilIndex) + depthStencilIndex = i; + break; + } + } + + if (command.framebuffer->GetType() == OpenGLFramebuffer::Type::FBO) + { + context->glDrawBuffers(GLsizei(colorBufferCount), fboDrawBuffers.data()); + + for (std::size_t i = 0; i < colorBufferCount; ++i) + { + std::size_t attachmentIndex = colorIndexes[i]; + + Nz::Color color = command.clearValues[attachmentIndex].color; + std::array clearColor = { color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f }; + + const auto& attachmentInfo = command.renderpass->GetAttachment(attachmentIndex); + if (attachmentInfo.loadOp == AttachmentLoadOp::Clear) + { + context->ResetColorWriteMasks(); + context->glClearBufferfv(GL_COLOR, GLint(i), clearColor.data()); + } + } + + if (depthStencilIndex) + { + std::size_t attachmentIndex = *depthStencilIndex; + const auto& clearValues = command.clearValues[attachmentIndex]; + + const auto& depthStencilAttachment = command.renderpass->GetAttachment(attachmentIndex); + if (depthStencilAttachment.loadOp == AttachmentLoadOp::Clear && depthStencilAttachment.stencilLoadOp == AttachmentLoadOp::Clear) + { + context->ResetDepthWriteMasks(); + context->ResetStencilWriteMasks(); + context->glClearBufferfi(GL_DEPTH_STENCIL, 0, clearValues.depth, clearValues.stencil); + } + else if (depthStencilAttachment.loadOp == AttachmentLoadOp::Clear) + { + context->ResetDepthWriteMasks(); + context->glClearBufferfv(GL_DEPTH, 0, &clearValues.depth); + } + else if (depthStencilAttachment.stencilLoadOp == AttachmentLoadOp::Clear) + { + context->ResetStencilWriteMasks(); + context->glClearBufferuiv(GL_STENCIL, 0, &clearValues.stencil); + } + } + } + else + { + GLenum buffer = GL_BACK; + context->glDrawBuffers(1, &buffer); + + if (colorIndex > 0) + { + std::size_t colorBufferCount = command.framebuffer->GetColorBufferCount(); + assert(colorBufferCount <= 1); + + std::size_t colorAttachmentIndex = colorIndexes.front(); + + const auto& colorAttachment = command.renderpass->GetAttachment(colorAttachmentIndex); + if (colorAttachment.loadOp == AttachmentLoadOp::Clear) + { + context->ResetColorWriteMasks(); + + Nz::Color color = command.clearValues[colorAttachmentIndex].color; + context->glClearColor(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f); + + clearFields |= GL_COLOR_BUFFER_BIT; + } + } + + if (depthStencilIndex) + { + std::size_t attachmentIndex = *depthStencilIndex; + const auto& clearValues = command.clearValues[attachmentIndex]; + + const auto& depthStencilAttachment = command.renderpass->GetAttachment(attachmentIndex); + if (depthStencilAttachment.loadOp == AttachmentLoadOp::Clear) + { + context->ResetDepthWriteMasks(); + context->glClearDepthf(clearValues.depth); + clearFields |= GL_DEPTH_BUFFER_BIT; + } + + if (depthStencilAttachment.stencilLoadOp == AttachmentLoadOp::Clear && PixelFormatInfo::GetContent(depthStencilAttachment.format) == PixelFormatContent::DepthStencil) + { + context->ResetStencilWriteMasks(); + context->glClearStencil(clearValues.stencil); + clearFields |= GL_STENCIL_BUFFER_BIT; + } + } + + if (clearFields) + context->glClear(clearFields); + } } else static_assert(AlwaysFalse::value, "non-exhaustive visitor"); @@ -104,8 +241,8 @@ namespace Nz void OpenGLCommandBuffer::ApplyStates(const GL::Context& context, const DrawStates& states) { + states.pipeline->Apply(context, states.shouldFlipY); states.shaderBindings->Apply(context); - states.pipeline->Apply(context); if (states.scissorRegion) context.SetScissorBox(states.scissorRegion->x, states.scissorRegion->y, states.scissorRegion->width, states.scissorRegion->height); diff --git a/src/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.cpp b/src/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.cpp index e10d0de22..435e2c1fe 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.cpp @@ -19,9 +19,9 @@ namespace Nz m_commandBuffer.BeginDebugRegion(regionName, color); } - void OpenGLCommandBufferBuilder::BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect, std::initializer_list clearValues) + void OpenGLCommandBufferBuilder::BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti /*renderRect*/, const ClearValues* clearValues, std::size_t clearValueCount) { - m_commandBuffer.SetFramebuffer(static_cast(framebuffer), renderPass, clearValues); + m_commandBuffer.SetFramebuffer(static_cast(framebuffer), static_cast(renderPass), clearValues, clearValueCount); } void OpenGLCommandBufferBuilder::BindIndexBuffer(Nz::AbstractBuffer* indexBuffer, UInt64 offset) @@ -84,14 +84,22 @@ namespace Nz void OpenGLCommandBufferBuilder::EndRenderPass() { + /* nothing to do */ + } + + void OpenGLCommandBufferBuilder::NextSubpass() + { + /* nothing to do */ } void OpenGLCommandBufferBuilder::PreTransferBarrier() { + /* nothing to do */ } void OpenGLCommandBufferBuilder::PostTransferBarrier() { + /* nothing to do */ } void OpenGLCommandBufferBuilder::SetScissor(Nz::Recti scissorRegion) @@ -103,4 +111,9 @@ namespace Nz { m_commandBuffer.SetViewport(viewportRegion); } + + void OpenGLCommandBufferBuilder::TextureBarrier(PipelineStageFlags /*srcStageMask*/, PipelineStageFlags /*dstStageMask*/, MemoryAccessFlags /*srcAccessMask*/, MemoryAccessFlags /*dstAccessMask*/, TextureLayout /*oldLayout*/, TextureLayout /*newLayout*/, const Texture& /*texture*/) + { + /* nothing to do */ + } } diff --git a/src/Nazara/OpenGLRenderer/OpenGLDevice.cpp b/src/Nazara/OpenGLRenderer/OpenGLDevice.cpp index e7c0c070f..61e072e38 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLDevice.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLDevice.cpp @@ -6,9 +6,11 @@ #include #include #include +#include +#include #include #include -#include +#include #include #include #include @@ -24,6 +26,35 @@ namespace Nz if (!m_referenceContext) throw std::runtime_error("failed to create reference context"); + if (!GL::Context::SetCurrentContext(m_referenceContext.get())) + throw std::runtime_error("failed to activate reference context"); + + const GLubyte* vendorStr = m_referenceContext->glGetString(GL_VENDOR); + const GLubyte* rendererStr = m_referenceContext->glGetString(GL_RENDERER); + + m_deviceInfo.name = "OpenGL Device ("; + + if (vendorStr) + m_deviceInfo.name.append(reinterpret_cast(vendorStr)); + + if (rendererStr) + { + if (vendorStr) + m_deviceInfo.name += " - "; + + m_deviceInfo.name.append(reinterpret_cast(rendererStr)); + } + + m_deviceInfo.name += ')'; + + m_deviceInfo.type = RenderDeviceType::Unknown; + + GLint minUboOffsetAlignment; + m_referenceContext->glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &minUboOffsetAlignment); + + assert(minUboOffsetAlignment >= 1); + m_deviceInfo.limits.minUniformBufferOffsetAlignment = static_cast(minUboOffsetAlignment); + m_contexts.insert(m_referenceContext.get()); } @@ -48,6 +79,11 @@ namespace Nz return contextPtr; } + const RenderDeviceInfo& OpenGLDevice::GetDeviceInfo() const + { + return m_deviceInfo; + } + std::shared_ptr OpenGLDevice::InstantiateBuffer(BufferType type) { return std::make_shared(*this, type); @@ -58,6 +94,16 @@ namespace Nz return std::make_shared(); } + std::shared_ptr OpenGLDevice::InstantiateFramebuffer(unsigned int /*width*/, unsigned int /*height*/, const std::shared_ptr& /*renderPass*/, const std::vector>& attachments) + { + return std::make_shared(*this, attachments); + } + + std::shared_ptr OpenGLDevice::InstantiateRenderPass(std::vector attachments, std::vector subpassDescriptions, std::vector subpassDependencies) + { + return std::make_shared(std::move(attachments), std::move(subpassDescriptions), std::move(subpassDependencies)); + } + std::shared_ptr OpenGLDevice::InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) { return std::make_shared(*this, std::move(pipelineInfo)); @@ -68,9 +114,14 @@ namespace Nz return std::make_shared(std::move(pipelineLayoutInfo)); } - std::shared_ptr OpenGLDevice::InstantiateShaderStage(ShaderStageType type, ShaderLanguage lang, const void* source, std::size_t sourceSize) + std::shared_ptr OpenGLDevice::InstantiateShaderModule(ShaderStageTypeFlags shaderStages, ShaderAst::StatementPtr& shaderAst, const ShaderWriter::States& states) { - return std::make_shared(*this, type, lang, source, sourceSize); + return std::make_shared(*this, shaderStages, shaderAst, states); + } + + std::shared_ptr OpenGLDevice::InstantiateShaderModule(ShaderStageTypeFlags shaderStages, ShaderLanguage lang, const void* source, std::size_t sourceSize, const ShaderWriter::States& states) + { + return std::make_shared(*this, shaderStages, lang, source, sourceSize, states); } std::shared_ptr OpenGLDevice::InstantiateTexture(const TextureInfo& params) @@ -82,5 +133,84 @@ namespace Nz { return std::make_shared(*this, params); } - + + bool OpenGLDevice::IsTextureFormatSupported(PixelFormat format, TextureUsage usage) const + { + switch (format) + { + case PixelFormat::Undefined: + return false; + + case PixelFormat::A8: + case PixelFormat::BGR8: + case PixelFormat::BGR8_SRGB: + case PixelFormat::BGRA8: + case PixelFormat::BGRA8_SRGB: + case PixelFormat::L8: + case PixelFormat::LA8: + case PixelFormat::R8: + case PixelFormat::R8I: + case PixelFormat::R8UI: + case PixelFormat::R16: + case PixelFormat::R16F: + case PixelFormat::R16I: + case PixelFormat::R16UI: + case PixelFormat::R32F: + case PixelFormat::R32I: + case PixelFormat::R32UI: + case PixelFormat::RG8: + case PixelFormat::RG8I: + case PixelFormat::RG8UI: + case PixelFormat::RG16: + case PixelFormat::RG16F: + case PixelFormat::RG16I: + case PixelFormat::RG16UI: + case PixelFormat::RG32F: + case PixelFormat::RG32I: + case PixelFormat::RG32UI: + case PixelFormat::RGB5A1: + case PixelFormat::RGB8: + case PixelFormat::RGB8_SRGB: + case PixelFormat::RGB16F: + case PixelFormat::RGB16I: + case PixelFormat::RGB16UI: + case PixelFormat::RGB32F: + case PixelFormat::RGB32I: + case PixelFormat::RGB32UI: + case PixelFormat::RGBA4: + case PixelFormat::RGBA8: + case PixelFormat::RGBA8_SRGB: + case PixelFormat::RGBA16F: + case PixelFormat::RGBA16I: + case PixelFormat::RGBA16UI: + case PixelFormat::RGBA32F: + case PixelFormat::RGBA32I: + case PixelFormat::RGBA32UI: + return usage == TextureUsage::ColorAttachment || usage == TextureUsage::InputAttachment || usage == TextureUsage::ShaderSampling || usage == TextureUsage::TransferDestination || usage == TextureUsage::TransferSource; + + case PixelFormat::DXT1: + case PixelFormat::DXT3: + case PixelFormat::DXT5: + { + if (!m_referenceContext->IsExtensionSupported(GL::Extension::TextureCompressionS3tc)) + return false; + + return usage == TextureUsage::InputAttachment || usage == TextureUsage::ShaderSampling || usage == TextureUsage::TransferDestination || usage == TextureUsage::TransferSource; + } + + case PixelFormat::Depth16: + case PixelFormat::Depth16Stencil8: + case PixelFormat::Depth24: + case PixelFormat::Depth24Stencil8: + case PixelFormat::Depth32F: + case PixelFormat::Depth32FStencil8: + case PixelFormat::Stencil1: + case PixelFormat::Stencil4: + case PixelFormat::Stencil8: + case PixelFormat::Stencil16: + return usage == TextureUsage::DepthStencilAttachment || usage == TextureUsage::ShaderSampling || usage == TextureUsage::TransferDestination || usage == TextureUsage::TransferSource; + } + + return false; + } } diff --git a/src/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.cpp b/src/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.cpp new file mode 100644 index 000000000..504f09ba8 --- /dev/null +++ b/src/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.cpp @@ -0,0 +1,92 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - OpenGL Renderer" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include + +namespace Nz +{ + OpenGLFboFramebuffer::OpenGLFboFramebuffer(OpenGLDevice& device, const std::vector>& attachments) : + OpenGLFramebuffer(OpenGLFramebuffer::Type::FBO) + { + if (!m_framebuffer.Create(device)) + throw std::runtime_error("failed to create framebuffer object"); + + std::size_t colorAttachmentCount = 0; + bool hasDepth = false; + bool hasStencil = false; + + for (std::size_t i = 0; i < attachments.size(); ++i) + { + assert(attachments[i]); + const OpenGLTexture& glTexture = static_cast(*attachments[i]); + + PixelFormat textureFormat = glTexture.GetFormat(); + + GLenum attachment; + switch (PixelFormatInfo::GetContent(textureFormat)) + { + case PixelFormatContent::ColorRGBA: + attachment = static_cast(GL_COLOR_ATTACHMENT0 + colorAttachmentCount); + colorAttachmentCount++; + break; + + case PixelFormatContent::Depth: + if (hasDepth) + throw std::runtime_error("a framebuffer can only have one depth attachment"); + + attachment = GL_DEPTH_ATTACHMENT; + hasDepth = true; + break; + + case PixelFormatContent::DepthStencil: + if (hasDepth) + throw std::runtime_error("a framebuffer can only have one depth attachment"); + + if (hasStencil) + throw std::runtime_error("a framebuffer can only have one stencil attachment"); + + attachment = GL_DEPTH_STENCIL_ATTACHMENT; + hasDepth = true; + hasStencil = true; + break; + + case PixelFormatContent::Stencil: + if (hasStencil) + throw std::runtime_error("a framebuffer can only have one stencil attachment"); + + attachment = GL_STENCIL_ATTACHMENT; + hasStencil = true; + break; + + case PixelFormatContent::Undefined: + default: + throw std::runtime_error("unhandled pixel format " + PixelFormatInfo::GetName(textureFormat)); + } + + m_framebuffer.Texture2D(attachment, ToOpenGL(OpenGLTexture::ToTextureTarget(glTexture.GetType())), glTexture.GetTexture().GetObjectId()); + } + + GLenum status = m_framebuffer.Check(); + if (status != GL_FRAMEBUFFER_COMPLETE) + throw std::runtime_error("invalid framebuffer: 0x" + NumberToString(status, 16)); + + m_colorAttachmentCount = colorAttachmentCount; + } + + void OpenGLFboFramebuffer::Activate() const + { + const GL::Context& context = m_framebuffer.EnsureDeviceContext(); + + context.BindFramebuffer(GL::FramebufferTarget::Draw, m_framebuffer.GetObjectId()); + } + + std::size_t OpenGLFboFramebuffer::GetColorBufferCount() const + { + return m_colorAttachmentCount; + } +} diff --git a/src/Nazara/OpenGLRenderer/OpenGLRenderImage.cpp b/src/Nazara/OpenGLRenderer/OpenGLRenderImage.cpp index 681b4cf46..7e2f04ced 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLRenderImage.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLRenderImage.cpp @@ -31,14 +31,16 @@ namespace Nz return m_uploadPool; } - void OpenGLRenderImage::SubmitCommandBuffer(CommandBuffer* commandBuffer, QueueTypeFlags queueTypeFlags) + void OpenGLRenderImage::Present() + { + m_owner.Present(); + m_uploadPool.Reset(); + FlushReleaseQueue(); + } + + void OpenGLRenderImage::SubmitCommandBuffer(CommandBuffer* commandBuffer, QueueTypeFlags /*queueTypeFlags*/) { OpenGLCommandBuffer* oglCommandBuffer = static_cast(commandBuffer); oglCommandBuffer->Execute(); } - - void OpenGLRenderImage::Present() - { - m_owner.Present(); - } } diff --git a/src/Nazara/OpenGLRenderer/OpenGLRenderPipeline.cpp b/src/Nazara/OpenGLRenderer/OpenGLRenderPipeline.cpp index d3378c941..639104c0d 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLRenderPipeline.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLRenderPipeline.cpp @@ -6,7 +6,9 @@ #include #include #include -#include +#include +#include +#include #include #include #include @@ -14,15 +16,43 @@ namespace Nz { OpenGLRenderPipeline::OpenGLRenderPipeline(OpenGLDevice& device, RenderPipelineInfo pipelineInfo) : - m_pipelineInfo(std::move(pipelineInfo)) + m_pipelineInfo(std::move(pipelineInfo)), + m_isViewportFlipped(false) { if (!m_program.Create(device)) throw std::runtime_error("failed to create program"); - for (const auto& shaderStagePtr : m_pipelineInfo.shaderStages) + ShaderStageTypeFlags stageFlags; + + for (const auto& shaderModulePtr : m_pipelineInfo.shaderModules) { - OpenGLShaderStage& shaderStage = static_cast(*shaderStagePtr); - m_program.AttachShader(shaderStage.GetShader().GetObjectId()); + OpenGLShaderModule& shaderModule = static_cast(*shaderModulePtr); + for (const auto& shaderEntry : shaderModule.GetShaders()) + { + m_program.AttachShader(shaderEntry.shader.GetObjectId()); + stageFlags |= shaderEntry.stage; + } + } + + // OpenGL ES programs must have both vertex and fragment shaders or a compute shader or a mesh and fragment shader. + if (device.GetReferenceContext().GetParams().type == GL::ContextType::OpenGL_ES) + { + auto GenerateIfMissing = [&](ShaderStageType stage) + { + if (!stageFlags.Test(stage)) + { + ShaderAst::StatementPtr dummyAst = ShaderBuilder::DeclareFunction(stage, "main", {}, {}); + OpenGLShaderModule shaderModule(device, stage, dummyAst); + for (const auto& shaderEntry : shaderModule.GetShaders()) + { + m_program.AttachShader(shaderEntry.shader.GetObjectId()); + stageFlags |= shaderEntry.stage; + } + } + }; + + GenerateIfMissing(ShaderStageType::Fragment); + GenerateIfMissing(ShaderStageType::Vertex); } m_program.Link(); @@ -30,11 +60,20 @@ namespace Nz std::string errLog; if (!m_program.GetLinkStatus(&errLog)) throw std::runtime_error("failed to link program: " + errLog); + + m_flipYUniformLocation = m_program.GetUniformLocation(GlslWriter::GetFlipYUniformName()); + if (m_flipYUniformLocation != -1) + m_program.Uniform(m_flipYUniformLocation, 1.f); } - void OpenGLRenderPipeline::Apply(const GL::Context& context) const + void OpenGLRenderPipeline::Apply(const GL::Context& context, bool flipViewport) const { - context.UpdateStates(m_pipelineInfo); - context.BindProgram(m_program.GetObjectId()); //< Bind program after states + context.UpdateStates(m_pipelineInfo, flipViewport); + context.BindProgram(m_program.GetObjectId()); //< Bind program after states (for shader caching) + if (m_isViewportFlipped != flipViewport) + { + m_program.Uniform(m_flipYUniformLocation, (flipViewport) ? -1.f : 1.f); + m_isViewportFlipped = flipViewport; + } } } diff --git a/src/Nazara/OpenGLRenderer/OpenGLRenderWindow.cpp b/src/Nazara/OpenGLRenderer/OpenGLRenderWindow.cpp index 2489b8695..01232a6be 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLRenderWindow.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLRenderWindow.cpp @@ -32,7 +32,7 @@ namespace Nz m_size = size; } - return RenderFrame(&m_renderImage[m_currentFrame], invalidateFramebuffer); + return RenderFrame(m_renderImage[m_currentFrame].get(), invalidateFramebuffer); } bool OpenGLRenderWindow::Create(RendererImpl* renderer, RenderSurface* surface, const RenderWindowParameters& parameters) @@ -40,21 +40,55 @@ namespace Nz DummySurface* dummySurface = static_cast(surface); OpenGLRenderer* glRenderer = static_cast(renderer); - m_device = std::static_pointer_cast(glRenderer->InstanciateRenderDevice(0)); + OpenGLDevice& device = static_cast(*m_owner.GetRenderDevice()); GL::ContextParams contextParams; - m_context = m_device->CreateContext(contextParams, dummySurface->GetWindowHandle()); + m_context = device.CreateContext(contextParams, dummySurface->GetWindowHandle()); if (!m_context) return false; m_size = m_owner.GetSize(); + // TODO: extract the exact window pixel format + PixelFormat colorFormat; + switch (contextParams.bitsPerPixel) + { + case 8: colorFormat = PixelFormat::R8; break; + case 16: colorFormat = PixelFormat::RG8; break; + case 24: colorFormat = PixelFormat::RGB8; break; + + case 32: + default: + colorFormat = PixelFormat::RGBA8; + break; + } + + // TODO: extract the exact depth-stencil format + PixelFormat depthFormat; + if (contextParams.stencilBits > 0) + depthFormat = PixelFormat::Depth24Stencil8; + else if (contextParams.depthBits > 24) + depthFormat = PixelFormat::Depth32F; + else if (contextParams.depthBits > 16) + depthFormat = PixelFormat::Depth24; + else if (contextParams.depthBits > 0) + depthFormat = PixelFormat::Depth16; + else + depthFormat = PixelFormat::Undefined; + + std::vector attachments; + std::vector subpassDescriptions; + std::vector subpassDependencies; + + BuildRenderPass(colorFormat, depthFormat, attachments, subpassDescriptions, subpassDependencies); + m_renderPass.emplace(std::move(attachments), std::move(subpassDescriptions), std::move(subpassDependencies)); + constexpr std::size_t RenderImageCount = 2; m_renderImage.reserve(RenderImageCount); for (std::size_t i = 0; i < RenderImageCount; ++i) - m_renderImage.emplace_back(*this); + m_renderImage.emplace_back(std::make_unique(*this)); return true; } @@ -71,12 +105,7 @@ namespace Nz const OpenGLRenderPass& OpenGLRenderWindow::GetRenderPass() const { - return m_renderPass; - } - - std::shared_ptr OpenGLRenderWindow::GetRenderDevice() - { - return m_device; + return *m_renderPass; } void OpenGLRenderWindow::Present() diff --git a/src/Nazara/OpenGLRenderer/OpenGLRenderer.cpp b/src/Nazara/OpenGLRenderer/OpenGLRenderer.cpp index 63e061bb2..bced38769 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLRenderer.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLRenderer.cpp @@ -24,6 +24,13 @@ namespace Nz { + OpenGLRenderer::OpenGLRenderer() + { + auto& dummyDevice = m_deviceInfos.emplace_back(); + dummyDevice.name = "OpenGL Default Device"; + dummyDevice.type = RenderDeviceType::Unknown; + } + OpenGLRenderer::~OpenGLRenderer() { m_device.reset(); @@ -107,13 +114,8 @@ namespace Nz return 300; } - std::vector OpenGLRenderer::QueryRenderDevices() const + const std::vector& OpenGLRenderer::QueryRenderDevices() const { - std::vector devices; - auto& dummyDevice = devices.emplace_back(); - dummyDevice.name = "OpenGL Default Device"; - dummyDevice.type = RenderDeviceType::Unknown; - - return devices; + return m_deviceInfos; } } diff --git a/src/Nazara/OpenGLRenderer/OpenGLShaderBinding.cpp b/src/Nazara/OpenGLRenderer/OpenGLShaderBinding.cpp index a236d81c7..cf0c031d1 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLShaderBinding.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLShaderBinding.cpp @@ -20,6 +20,8 @@ namespace Nz const auto& textureDescriptor = m_owner.GetTextureDescriptor(m_poolIndex, m_bindingIndex, i); UInt32 textureIndex = textureDescriptor.bindingIndex; + if (textureIndex == OpenGLRenderPipelineLayout::InvalidIndex) + continue; context.BindSampler(textureIndex, textureDescriptor.sampler); context.BindTexture(textureIndex, textureDescriptor.textureTarget, textureDescriptor.texture); @@ -29,24 +31,30 @@ namespace Nz { const auto& uboDescriptor = m_owner.GetUniformBufferDescriptor(m_poolIndex, m_bindingIndex, i); + UInt32 uboIndex = uboDescriptor.bindingIndex; + if (uboIndex == OpenGLRenderPipelineLayout::InvalidIndex) + continue; + context.BindUniformBuffer(uboDescriptor.bindingIndex, uboDescriptor.buffer, uboDescriptor.offset, uboDescriptor.size); } } - void OpenGLShaderBinding::Update(std::initializer_list bindings) + void OpenGLShaderBinding::Update(const Binding* bindings, std::size_t bindingCount) { const auto& layoutInfo = m_owner.GetLayoutInfo(); - for (const Binding& binding : bindings) + for (std::size_t i = 0; i < bindingCount; ++i) { + const Binding& binding = bindings[i]; + assert(binding.bindingIndex < layoutInfo.bindings.size()); const auto& bindingDesc = layoutInfo.bindings[binding.bindingIndex]; std::size_t resourceIndex = 0; - for (std::size_t i = binding.bindingIndex; i > 0; --i) + for (std::size_t j = binding.bindingIndex; j > 0; --j) { - // Use i-1 to prevent underflow in for loop - if (layoutInfo.bindings[i - 1].type == bindingDesc.type) + // Use j-1 to prevent underflow in for loop + if (layoutInfo.bindings[j - 1].type == bindingDesc.type) resourceIndex++; } @@ -59,38 +67,27 @@ namespace Nz const TextureBinding& texBinding = std::get(binding.content); - OpenGLTexture& glTexture = static_cast(*texBinding.texture); - OpenGLTextureSampler& glSampler = static_cast(*texBinding.sampler); - auto& textureDescriptor = m_owner.GetTextureDescriptor(m_poolIndex, m_bindingIndex, resourceIndex); - textureDescriptor.bindingIndex = binding.bindingIndex; + textureDescriptor.bindingIndex = UInt32(binding.bindingIndex); - textureDescriptor.texture = glTexture.GetTexture().GetObjectId(); - textureDescriptor.sampler = glSampler.GetSampler(glTexture.GetLevelCount() > 1).GetObjectId(); - - switch (glTexture.GetType()) + if (OpenGLTexture* glTexture = static_cast(texBinding.texture)) { - case ImageType_2D: - textureDescriptor.textureTarget = GL::TextureTarget::Target2D; - break; + textureDescriptor.texture = glTexture->GetTexture().GetObjectId(); - case ImageType_2D_Array: - textureDescriptor.textureTarget = GL::TextureTarget::Target2D_Array; - break; + if (OpenGLTextureSampler* glSampler = static_cast(texBinding.sampler)) + textureDescriptor.sampler = glSampler->GetSampler(glTexture->GetLevelCount() > 1).GetObjectId(); + else + textureDescriptor.sampler = 0; - case ImageType_3D: - textureDescriptor.textureTarget = GL::TextureTarget::Target3D; - break; - - case ImageType_Cubemap: - textureDescriptor.textureTarget = GL::TextureTarget::Cubemap; - break; - - case ImageType_1D: - case ImageType_1D_Array: - default: - throw std::runtime_error("unsupported texture type"); + textureDescriptor.textureTarget = OpenGLTexture::ToTextureTarget(glTexture->GetType()); } + else + { + textureDescriptor.sampler = 0; + textureDescriptor.texture = 0; + textureDescriptor.textureTarget = GL::TextureTarget::Target2D; + } + break; } @@ -101,15 +98,21 @@ namespace Nz const UniformBufferBinding& uboBinding = std::get(binding.content); - OpenGLBuffer& glBuffer = *static_cast(uboBinding.buffer); - if (glBuffer.GetType() != BufferType_Uniform) - throw std::runtime_error("expected uniform buffer"); - auto& uboDescriptor = m_owner.GetUniformBufferDescriptor(m_poolIndex, m_bindingIndex, resourceIndex); - uboDescriptor.bindingIndex = binding.bindingIndex; - uboDescriptor.buffer = glBuffer.GetBuffer().GetObjectId(); + uboDescriptor.bindingIndex = static_cast(binding.bindingIndex); uboDescriptor.offset = uboBinding.offset; uboDescriptor.size = uboBinding.range; + + if (OpenGLBuffer* glBuffer = static_cast(uboBinding.buffer)) + { + if (glBuffer->GetType() != BufferType::Uniform) + throw std::runtime_error("expected uniform buffer"); + + uboDescriptor.buffer = glBuffer->GetBuffer().GetObjectId(); + } + else + uboDescriptor.buffer = 0; + break; } } diff --git a/src/Nazara/OpenGLRenderer/OpenGLShaderModule.cpp b/src/Nazara/OpenGLRenderer/OpenGLShaderModule.cpp new file mode 100644 index 000000000..25a579766 --- /dev/null +++ b/src/Nazara/OpenGLRenderer/OpenGLShaderModule.cpp @@ -0,0 +1,141 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - OpenGL Renderer" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + OpenGLShaderModule::OpenGLShaderModule(OpenGLDevice& device, ShaderStageTypeFlags shaderStages, ShaderAst::StatementPtr& shaderAst, const ShaderWriter::States& states) + { + NazaraAssert(shaderStages != 0, "at least one shader stage must be specified"); + Create(device, shaderStages, shaderAst, states); + } + + OpenGLShaderModule::OpenGLShaderModule(OpenGLDevice& device, ShaderStageTypeFlags shaderStages, ShaderLanguage lang, const void* source, std::size_t sourceSize, const ShaderWriter::States& states) + { + NazaraAssert(shaderStages != 0, "at least one shader stage must be specified"); + + switch (lang) + { + case ShaderLanguage::GLSL: + { + for (std::size_t i = 0; i < ShaderStageTypeCount; ++i) + { + ShaderStageType shaderStage = static_cast(i); + if (shaderStages.Test(shaderStage)) + { + NazaraAssert(shaderStages == shaderStage, "when supplying GLSL, only one shader stage type can be specified"); + + GL::Shader shader; + if (!shader.Create(device, ToOpenGL(shaderStage))) + throw std::runtime_error("failed to create shader"); //< TODO: Handle error message + + shader.SetSource(reinterpret_cast(source), GLint(sourceSize)); + shader.Compile(); + CheckCompilationStatus(shader); + + auto& entry = m_shaders.emplace_back(); + entry.shader = std::move(shader); + entry.stage = shaderStage; + break; + } + } + + break; + } + + case ShaderLanguage::NazaraBinary: + { + auto shader = ShaderAst::UnserializeShader(source, sourceSize); + Create(device, shaderStages, shader, {}); + break; + } + + case ShaderLanguage::NazaraShader: + { + std::vector tokens = Nz::ShaderLang::Tokenize(std::string_view(static_cast(source), sourceSize)); + + Nz::ShaderLang::Parser parser; + Nz::ShaderAst::StatementPtr shaderAst = parser.Parse(tokens); + Create(device, shaderStages, shaderAst, states); + break; + } + + case ShaderLanguage::SpirV: + { + throw std::runtime_error("TODO"); + + // TODO: Parse SpirV to extract entry points? + + /*if (!device.GetReferenceContext().IsExtensionSupported(GL::Extension::SpirV)) + throw std::runtime_error("SpirV is not supported by this OpenGL implementation"); + + m_shader.SetBinarySource(GL_SHADER_BINARY_FORMAT_SPIR_V_ARB, source, GLsizei(sourceSize)); + m_shader.SpecializeShader("main", 0U, nullptr, nullptr);*/ + break; + } + + default: + throw std::runtime_error("Unsupported shader language"); + } + } + + void OpenGLShaderModule::CheckCompilationStatus(GL::Shader& shader) + { + std::string errorLog; + if (!shader.GetCompilationStatus(&errorLog)) + throw std::runtime_error("Failed to compile shader: " + errorLog); + } + + void OpenGLShaderModule::Create(OpenGLDevice& device, ShaderStageTypeFlags shaderStages, ShaderAst::StatementPtr& shaderAst, const ShaderWriter::States& states) + { + const auto& context = device.GetReferenceContext(); + const auto& contextParams = context.GetParams(); + + GlslWriter::Environment env; + env.glES = (contextParams.type == GL::ContextType::OpenGL_ES); + env.glMajorVersion = contextParams.glMajorVersion; + env.glMinorVersion = contextParams.glMinorVersion; + env.extCallback = [&](const std::string_view& ext) + { + return context.IsExtensionSupported(std::string(ext)); + }; + env.flipYPosition = true; + + GlslWriter writer; + writer.SetEnv(env); + + for (std::size_t i = 0; i < ShaderStageTypeCount; ++i) + { + ShaderStageType shaderStage = static_cast(i); + if (shaderStages.Test(shaderStage)) + { + GL::Shader shader; + + if (!shader.Create(device, ToOpenGL(shaderStage))) + throw std::runtime_error("failed to create shader"); //< TODO: Handle error message + + std::string code = writer.Generate(shaderStage, shaderAst, states); + + shader.SetSource(code.data(), GLint(code.size())); + shader.Compile(); + + CheckCompilationStatus(shader); + + auto& entry = m_shaders.emplace_back(); + entry.shader = std::move(shader); + entry.stage = shaderStage; + } + } + } +} diff --git a/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp b/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp deleted file mode 100644 index 068ef9634..000000000 --- a/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - OpenGL Renderer" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Nz -{ - OpenGLShaderStage::OpenGLShaderStage(OpenGLDevice& device, ShaderStageType type, ShaderLanguage lang, const void* source, std::size_t sourceSize) - { - if (!m_shader.Create(device, ToOpenGL(type))) - throw std::runtime_error("failed to create shader"); //< TODO: Handle error message - - switch (lang) - { - case ShaderLanguage::GLSL: - m_shader.SetSource(reinterpret_cast(source), GLint(sourceSize)); - m_shader.Compile(); - break; - - case ShaderLanguage::NazaraBinary: - { - ByteStream byteStream(source, sourceSize); - auto shader = Nz::UnserializeShader(byteStream); - - if (shader.GetStage() != type) - throw std::runtime_error("incompatible shader stage"); - - const auto& context = device.GetReferenceContext(); - const auto& contextParams = context.GetParams(); - - GlslWriter::Environment env; - env.glES = (contextParams.type == GL::ContextType::OpenGL_ES); - env.glMajorVersion = contextParams.glMajorVersion; - env.glMinorVersion = contextParams.glMinorVersion; - env.extCallback = [&](const std::string_view& ext) - { - return context.IsExtensionSupported(std::string(ext)); - }; - env.flipYPosition = true; - - GlslWriter writer; - writer.SetEnv(env); - - std::string code = writer.Generate(shader); - - m_shader.SetSource(code.data(), code.size()); - m_shader.Compile(); - break; - } - - case ShaderLanguage::SpirV: - { - if (!device.GetReferenceContext().IsExtensionSupported(GL::Extension::SpirV)) - throw std::runtime_error("SpirV is not supported by this OpenGL implementation"); - - m_shader.SetBinarySource(GL_SHADER_BINARY_FORMAT_SPIR_V_ARB, source, GLsizei(sourceSize)); - m_shader.SpecializeShader("main", 0U, nullptr, nullptr); - break; - } - - default: - throw std::runtime_error("Unsupported shader language"); - } - - std::string errorLog; - if (!m_shader.GetCompilationStatus(&errorLog)) - throw std::runtime_error("Failed to compile shader: " + errorLog); - } -} diff --git a/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp b/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp index 53cb0bfbb..8866598fe 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp @@ -22,24 +22,24 @@ namespace Nz switch (params.type) { - case ImageType_1D: + case ImageType::E1D: break; - case ImageType_1D_Array: + case ImageType::E1D_Array: break; - case ImageType_2D: - for (unsigned int level = 0; level < m_params.mipmapLevel; ++level) - m_texture.TexImage2D(0, format->internalFormat, GetLevelSize(params.width, level), GetLevelSize(params.height, level), 0, format->format, format->type); + case ImageType::E2D: + m_texture.TexStorage2D(GL::TextureTarget::Target2D, params.mipmapLevel, format->internalFormat, params.width, params.height); break; - case ImageType_2D_Array: + case ImageType::E2D_Array: break; - case ImageType_3D: + case ImageType::E3D: break; - case ImageType_Cubemap: + case ImageType::Cubemap: + m_texture.TexStorage2D(GL::TextureTarget::Cubemap, params.mipmapLevel, format->internalFormat, params.width, params.height); break; default: @@ -80,24 +80,34 @@ namespace Nz switch (m_params.type) { - case ImageType_1D: + case ImageType::E1D: break; - case ImageType_1D_Array: + case ImageType::E1D_Array: break; - case ImageType_2D: - m_texture.TexSubImage2D(0, 0, 0, m_params.width, m_params.height, format->format, format->type, ptr); + case ImageType::E2D: + m_texture.TexSubImage2D(GL::TextureTarget::Target2D, 0, 0, 0, m_params.width, m_params.height, format->format, format->type, ptr); break; - case ImageType_2D_Array: + case ImageType::E2D_Array: break; - case ImageType_3D: + case ImageType::E3D: break; - case ImageType_Cubemap: + case ImageType::Cubemap: + { + std::size_t faceSize = PixelFormatInfo::ComputeSize(m_params.pixelFormat, m_params.width, m_params.height, 1); + const UInt8* facePtr = static_cast(ptr); + + for (GL::TextureTarget face : { GL::TextureTarget::CubemapPositiveX, GL::TextureTarget::CubemapNegativeX, GL::TextureTarget::CubemapPositiveY, GL::TextureTarget::CubemapNegativeY, GL::TextureTarget::CubemapPositiveZ, GL::TextureTarget::CubemapNegativeZ }) + { + m_texture.TexSubImage2D(face, 0, 0, 0, m_params.width, m_params.height, format->format, format->type, facePtr); + facePtr += faceSize; + } break; + } default: break; diff --git a/src/Nazara/OpenGLRenderer/OpenGLUploadPool.cpp b/src/Nazara/OpenGLRenderer/OpenGLUploadPool.cpp index 54901ee8d..a4c610c84 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLUploadPool.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLUploadPool.cpp @@ -27,7 +27,7 @@ namespace Nz for (Block& block : m_blocks) { - if (block.freeOffset + size > m_blockSize) + if (block.freeOffset + size > block.size) continue; //< Not enough space if (!bestBlock.block) @@ -41,17 +41,37 @@ namespace Nz // No block found, allocate a new one if (!bestBlock.block) { + // Handle really big allocations (TODO: Handle them separately as they shouldn't be common and can consume a lot of memory) + UInt64 blockSize = std::max(m_blockSize, size); + Block newBlock; + newBlock.size = blockSize; + newBlock.memory.resize(m_blockSize); bestBlock.block = &m_blocks.emplace_back(std::move(newBlock)); bestBlock.offset = 0; } - Allocation& allocationData = m_allocations.emplace_back(); + // Now find the proper allocation buffer + std::size_t allocationBlockIndex = m_nextAllocationIndex / AllocationPerBlock; + std::size_t allocationIndex = m_nextAllocationIndex % AllocationPerBlock; + + if (allocationBlockIndex >= m_allocationBlocks.size()) + { + assert(allocationBlockIndex == m_allocationBlocks.size()); + m_allocationBlocks.emplace_back(std::make_unique()); + } + + auto& allocationBlock = *m_allocationBlocks[allocationBlockIndex]; + + Allocation& allocationData = allocationBlock[allocationIndex]; allocationData.mappedPtr = static_cast(bestBlock.block->memory.data()) + bestBlock.offset; allocationData.size = size; + bestBlock.block->freeOffset += size; + m_nextAllocationIndex++; + return allocationData; } @@ -60,6 +80,6 @@ namespace Nz for (Block& block : m_blocks) block.freeOffset = 0; - m_allocations.clear(); + m_nextAllocationIndex = 0; } } diff --git a/src/Nazara/OpenGLRenderer/OpenGLVaoCache.cpp b/src/Nazara/OpenGLRenderer/OpenGLVaoCache.cpp index 62f3f0166..172872e69 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLVaoCache.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLVaoCache.cpp @@ -30,7 +30,7 @@ namespace Nz::GL if (setup.indexBuffer != 0) m_context.BindBuffer(BufferTarget::ElementArray, setup.indexBuffer, true); - std::size_t bindingIndex = 0; + GLuint bindingIndex = 0; for (const auto& attribOpt : setup.vertexAttribs) { if (attribOpt) diff --git a/src/Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.cpp b/src/Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.cpp index 48b900a5c..a7e8283f6 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.cpp @@ -17,4 +17,9 @@ namespace Nz context.BindFramebuffer(GL::FramebufferTarget::Draw, 0); } + + std::size_t OpenGLWindowFramebuffer::GetColorBufferCount() const + { + return 1; + } } diff --git a/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp b/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp index 4b50659da..e719249e1 100644 --- a/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp +++ b/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp @@ -14,8 +14,6 @@ #include #include -#define NAZARA_OPENGLRENDERER_DEBUG 1 - namespace Nz::GL { thread_local const Context* s_currentContext = nullptr; @@ -73,8 +71,7 @@ namespace Nz::GL func = reinterpret_cast(originalFuncPtr); -#if !defined(NAZARA_COMPILER_MSVC) || NAZARA_PLATFORM_x64 -#if NAZARA_OPENGLRENDERER_DEBUG +#if defined(NAZARA_OPENGLRENDERER_DEBUG) && (!defined(NAZARA_COMPILER_MSVC) || defined(NAZARA_PLATFORM_x64)) if (func) { if (std::strcmp(funcName, "glGetError") != 0) //< Prevent infinite recursion @@ -83,7 +80,6 @@ namespace Nz::GL func = Wrapper::WrapErrorHandling(); } } -#endif #endif if (!func) @@ -216,6 +212,9 @@ namespace Nz::GL unit.buffer = buffer; unit.offset = offset; unit.size = size; + + // glBindBufferRange does replace the currently bound buffer + m_state.bufferTargets[UnderlyingCast(BufferTarget::Uniform)] = buffer; } } @@ -282,6 +281,9 @@ namespace Nz::GL m_extensionStatus.fill(ExtensionStatus::NotSupported); + if (m_supportedExtensions.count("GL_EXT_texture_compression_s3tc")) + m_extensionStatus[UnderlyingCast(Extension::TextureCompressionS3tc)] = ExtensionStatus::EXT; + // TextureFilterAnisotropic if (m_supportedExtensions.count("GL_ARB_texture_filter_anisotropic")) m_extensionStatus[UnderlyingCast(Extension::TextureFilterAnisotropic)] = ExtensionStatus::ARB; @@ -362,6 +364,8 @@ namespace Nz::GL glGetIntegerv(GL_VIEWPORT, res.data()); m_state.viewport = { res[0], res[1], res[2], res[3] }; + m_state.renderStates.frontFace = FrontFace::CounterClockwise; //< OpenGL default front face is counter-clockwise + EnableVerticalSync(false); return true; @@ -434,19 +438,31 @@ namespace Nz::GL } } - void Context::UpdateStates(const RenderStates& renderStates) const + void Context::UpdateStates(const RenderStates& renderStates, bool isViewportFlipped) const { if (!SetCurrentContext(this)) throw std::runtime_error("failed to activate context"); if (renderStates.blending) { - if (m_state.renderStates.dstBlend != renderStates.dstBlend || - m_state.renderStates.srcBlend != renderStates.srcBlend) + auto& currentBlend = m_state.renderStates.blend; + const auto& targetBlend = renderStates.blend; + + if (currentBlend.modeColor != targetBlend.modeColor || currentBlend.modeAlpha != targetBlend.modeAlpha) { - glBlendFunc(ToOpenGL(renderStates.srcBlend), ToOpenGL(renderStates.dstBlend)); - m_state.renderStates.dstBlend = renderStates.dstBlend; - m_state.renderStates.srcBlend = renderStates.srcBlend; + glBlendEquationSeparate(ToOpenGL(targetBlend.modeColor), ToOpenGL(targetBlend.modeAlpha)); + currentBlend.modeAlpha = targetBlend.modeAlpha; + currentBlend.modeColor = targetBlend.modeColor; + } + + if (currentBlend.dstAlpha != targetBlend.dstAlpha || currentBlend.dstColor != targetBlend.dstColor || + currentBlend.srcAlpha != targetBlend.srcAlpha || currentBlend.srcColor != targetBlend.srcColor) + { + glBlendFuncSeparate(ToOpenGL(targetBlend.srcColor), ToOpenGL(targetBlend.dstColor), ToOpenGL(targetBlend.srcAlpha), ToOpenGL(targetBlend.dstAlpha)); + currentBlend.dstAlpha = targetBlend.dstAlpha; + currentBlend.dstColor = targetBlend.dstColor; + currentBlend.srcAlpha = targetBlend.srcAlpha; + currentBlend.srcColor = targetBlend.srcColor; } } @@ -454,7 +470,7 @@ namespace Nz::GL { if (m_state.renderStates.depthCompare != renderStates.depthCompare) { - glDepthFunc(ToOpenGL(m_state.renderStates.depthCompare)); + glDepthFunc(ToOpenGL(renderStates.depthCompare)); m_state.renderStates.depthCompare = renderStates.depthCompare; } @@ -469,11 +485,21 @@ namespace Nz::GL { if (m_state.renderStates.cullingSide != renderStates.cullingSide) { - glCullFace(ToOpenGL(m_state.renderStates.cullingSide)); + glCullFace(ToOpenGL(renderStates.cullingSide)); m_state.renderStates.cullingSide = renderStates.cullingSide; } } + FrontFace targetFrontFace = renderStates.frontFace; + if (!isViewportFlipped) + targetFrontFace = (targetFrontFace == FrontFace::Clockwise) ? FrontFace::CounterClockwise : FrontFace::Clockwise; + + if (m_state.renderStates.frontFace != targetFrontFace) + { + glFrontFace(ToOpenGL(targetFrontFace)); + m_state.renderStates.frontFace = targetFrontFace; + } + /* TODO: Use glPolyonMode if available (OpenGL) if (m_state.renderStates.faceFilling != renderStates.faceFilling) @@ -491,12 +517,12 @@ namespace Nz::GL if (currentStencilData.compare != newStencilData.compare || currentStencilData.reference != newStencilData.reference || - currentStencilData.writeMask != newStencilData.writeMask) + currentStencilData.compareMask != newStencilData.compareMask) { - glStencilFuncSeparate((front) ? GL_FRONT : GL_BACK, ToOpenGL(newStencilData.compare), newStencilData.reference, newStencilData.writeMask); + glStencilFuncSeparate((front) ? GL_FRONT : GL_BACK, ToOpenGL(newStencilData.compare), newStencilData.reference, newStencilData.compareMask); currentStencilData.compare = newStencilData.compare; + currentStencilData.compareMask = newStencilData.compareMask; currentStencilData.reference = newStencilData.reference; - currentStencilData.writeMask = newStencilData.writeMask; } if (currentStencilData.depthFail != newStencilData.depthFail || @@ -508,6 +534,12 @@ namespace Nz::GL currentStencilData.fail = newStencilData.fail; currentStencilData.pass = newStencilData.pass; } + + if (currentStencilData.writeMask != newStencilData.writeMask) + { + glStencilMaskSeparate((front) ? GL_FRONT : GL_BACK, newStencilData.writeMask); + currentStencilData.writeMask = newStencilData.writeMask; + } }; ApplyStencilStates(true); @@ -644,8 +676,11 @@ namespace Nz::GL void Context::HandleDebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message) const { + if (id == 0) + return; + std::stringstream ss; - ss << "OpenGL debug message (ID: 0x" << std::to_string(id) << "):\n"; + ss << "OpenGL debug message (ID: 0x" << id << "):\n"; ss << "Sent by context: " << this; ss << "\n-Source: "; switch (source) diff --git a/src/Nazara/OpenGLRenderer/Wrapper/EGL/EGLContextBase.cpp b/src/Nazara/OpenGLRenderer/Wrapper/EGL/EGLContextBase.cpp index 8e7820c2d..72a848613 100644 --- a/src/Nazara/OpenGLRenderer/Wrapper/EGL/EGLContextBase.cpp +++ b/src/Nazara/OpenGLRenderer/Wrapper/EGL/EGLContextBase.cpp @@ -51,7 +51,7 @@ namespace Nz::GL return CreateInternal(configs[configIndex], shareContext); } - bool EGLContextBase::Create(const ContextParams& params, WindowHandle window, const EGLContextBase* shareContext) + bool EGLContextBase::Create(const ContextParams& /*params*/, WindowHandle /*window*/, const EGLContextBase* /*shareContext*/) { NazaraError("Unexpected context creation call"); return false; @@ -140,7 +140,7 @@ namespace Nz::GL }; EGLint numConfig = 0; - if (m_loader.eglChooseConfig(m_display, configAttributes, configs, maxConfigCount, &numConfig) != GL_TRUE) + if (m_loader.eglChooseConfig(m_display, configAttributes, configs, EGLint(maxConfigCount), &numConfig) != GL_TRUE) { NazaraError(std::string("failed to retrieve compatible EGL configurations: ") + EGLLoader::TranslateError(m_loader.eglGetError())); return false; diff --git a/src/Nazara/OpenGLRenderer/Wrapper/EGL/EGLLoader.cpp b/src/Nazara/OpenGLRenderer/Wrapper/EGL/EGLLoader.cpp index a63697e5c..3b66140cb 100644 --- a/src/Nazara/OpenGLRenderer/Wrapper/EGL/EGLLoader.cpp +++ b/src/Nazara/OpenGLRenderer/Wrapper/EGL/EGLLoader.cpp @@ -202,7 +202,7 @@ namespace Nz::GL } } - bool EGLLoader::ImplementFallback(const std::string_view& function) + bool EGLLoader::ImplementFallback(const std::string_view& /*function*/) { return false; } diff --git a/src/Nazara/OpenGLRenderer/Wrapper/Linux/EGLContextX11.cpp b/src/Nazara/OpenGLRenderer/Wrapper/Linux/EGLContextX11.cpp index ce7463754..2343f61a4 100644 --- a/src/Nazara/OpenGLRenderer/Wrapper/Linux/EGLContextX11.cpp +++ b/src/Nazara/OpenGLRenderer/Wrapper/Linux/EGLContextX11.cpp @@ -38,15 +38,4 @@ namespace Nz::GL return CreateInternal(configs[configIndex], shareContext); } - - void EGLContextX11::Destroy() - { - EGLContextBase::Destroy(); - - if (m_xdisplay) - { - XCloseDisplay(m_xdisplay); - m_xdisplay = nullptr; - } - } } diff --git a/src/Nazara/OpenGLRenderer/Wrapper/WGL/WGLContext.cpp b/src/Nazara/OpenGLRenderer/Wrapper/WGL/WGLContext.cpp index ffa9339e3..fc7c46c16 100644 --- a/src/Nazara/OpenGLRenderer/Wrapper/WGL/WGLContext.cpp +++ b/src/Nazara/OpenGLRenderer/Wrapper/WGL/WGLContext.cpp @@ -133,7 +133,7 @@ namespace Nz::GL WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_ES_PROFILE_BIT_EXT }; - m_handle = baseContext->wglCreateContextAttribsARB(m_deviceContext, nullptr, attributes.data()); + m_handle = baseContext->wglCreateContextAttribsARB(m_deviceContext, (shareContext) ? shareContext->m_handle : nullptr, attributes.data()); if (m_handle) break; } @@ -174,7 +174,7 @@ namespace Nz::GL WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB }; - m_handle = baseContext->wglCreateContextAttribsARB(m_deviceContext, nullptr, attributes.data()); + m_handle = baseContext->wglCreateContextAttribsARB(m_deviceContext, (shareContext) ? shareContext->m_handle : nullptr, attributes.data()); if (m_handle) { m_params.type = ContextType::OpenGL; @@ -198,16 +198,16 @@ namespace Nz::GL return false; } - m_params.type = ContextType::OpenGL; - } - - if (shareContext) - { - if (!m_loader.wglShareLists(shareContext->m_handle, m_handle)) + if (shareContext) { - NazaraError("failed to share context objects: " + Error::GetLastSystemError()); - return false; + if (!m_loader.wglShareLists(shareContext->m_handle, m_handle)) + { + NazaraError("failed to share context objects: " + Error::GetLastSystemError()); + return false; + } } + + m_params.type = ContextType::OpenGL; } LoadWGLExt(); @@ -377,7 +377,7 @@ namespace Nz::GL return false; } - if (DescribePixelFormat(m_deviceContext, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &descriptor) != 0) + if (m_loader.DescribePixelFormat(m_deviceContext, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &descriptor) != 0) { m_params.bitsPerPixel = descriptor.cColorBits + descriptor.cAlphaBits; m_params.depthBits = descriptor.cDepthBits; diff --git a/src/Nazara/Physics2D/Arbiter2D.cpp b/src/Nazara/Physics2D/Arbiter2D.cpp index 9da160216..2cb35ff4f 100644 --- a/src/Nazara/Physics2D/Arbiter2D.cpp +++ b/src/Nazara/Physics2D/Arbiter2D.cpp @@ -39,7 +39,7 @@ namespace Nz float Arbiter2D::GetContactDepth(std::size_t i) const { - return cpArbiterGetDepth(m_arbiter, int(i)); + return float(cpArbiterGetDepth(m_arbiter, int(i))); } Nz::Vector2f Arbiter2D::GetContactPointA(std::size_t i) const diff --git a/src/Nazara/Physics2D/Collider2D.cpp b/src/Nazara/Physics2D/Collider2D.cpp index 9d0743b88..4546df0e3 100644 --- a/src/Nazara/Physics2D/Collider2D.cpp +++ b/src/Nazara/Physics2D/Collider2D.cpp @@ -3,6 +3,8 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include +#include #include #include #include @@ -13,6 +15,16 @@ namespace Nz { + namespace + { + constexpr cpSpaceDebugColor white = { 1.f, 1.f, 1.f, 1.f }; + + Vector2f FromChipmunk(const cpVect& v) + { + return Vector2f(float(v.x), float(v.y)); + } + } + Collider2D::~Collider2D() = default; void Collider2D::ForEachPolygon(const std::function& callback) const @@ -20,65 +32,108 @@ namespace Nz // Currently, the only way to get only the polygons of a shape is to create a temporary cpSpace containing only this shape // A better way to do this would be to reimplement this function in every subclass type in the very same way chipmunk does - PhysWorld2D physWorld; - RigidBody2D rigidBody(&physWorld, 0.f); + cpSpace* space = cpSpaceNew(); + if (!space) + throw std::runtime_error("failed to create chipmunk space"); - std::vector shapeVector; - rigidBody.SetGeom(const_cast(this), false, false); //< Won't be used for writing, but still ugly + CallOnExit spaceRRID([&] { cpSpaceFree(space); }); - PhysWorld2D::DebugDrawOptions drawCallbacks; - drawCallbacks.circleCallback = [&](const Vector2f& origin, const RadianAnglef& /*rotation*/, float radius, Nz::Color /*outlineColor*/, Nz::Color /*fillColor*/, void* /*userData*/) + cpBody* body = cpSpaceGetStaticBody(space); + + std::vector shapes; + CreateShapes(body, &shapes); + CallOnExit shapeRRID([&] { + for (cpShape* shape : shapes) + cpShapeDestroy(shape); + }); + + for (cpShape* shape : shapes) + cpSpaceAddShape(space, shape); + + using CallbackType = std::decay_t; + + cpSpaceDebugDrawOptions drawOptions; + drawOptions.collisionPointColor = white; + drawOptions.constraintColor = white; + drawOptions.shapeOutlineColor = white; + drawOptions.data = const_cast(static_cast(&callback)); + drawOptions.flags = CP_SPACE_DEBUG_DRAW_SHAPES; + + // Callback trampoline + drawOptions.colorForShape = [](cpShape* /*shape*/, cpDataPointer /*userdata*/) { return white; }; + drawOptions.drawCircle = [](cpVect pos, cpFloat /*angle*/, cpFloat radius, cpSpaceDebugColor /*outlineColor*/, cpSpaceDebugColor /*fillColor*/, cpDataPointer userdata) + { + const auto& callback = *static_cast(userdata); + constexpr std::size_t circleVerticesCount = 20; std::array vertices; + Vector2f origin = FromChipmunk(pos); + float r = static_cast(radius); + RadianAnglef angleBetweenVertices = 2.f * float(M_PI) / vertices.size(); for (std::size_t i = 0; i < vertices.size(); ++i) { RadianAnglef angle = float(i) * angleBetweenVertices; std::pair sincos = angle.GetSinCos(); - vertices[i] = origin + Vector2f(radius * sincos.first, radius * sincos.second); + vertices[i] = origin + Vector2f(r * sincos.first, r * sincos.second); } callback(vertices.data(), vertices.size()); }; - drawCallbacks.polygonCallback = [&](const Vector2f* vertices, std::size_t vertexCount, float radius, Nz::Color /*outlineColor*/, Nz::Color /*fillColor*/, void* /*userData*/) - { - //TODO: Handle radius - callback(vertices, vertexCount); - }; + drawOptions.drawDot = [](cpFloat /*size*/, cpVect /*pos*/, cpSpaceDebugColor /*color*/, cpDataPointer /*userdata*/) {}; //< Dummy - drawCallbacks.segmentCallback = [&](const Vector2f& first, const Vector2f& second, Nz::Color /*color*/, void* /*userData*/) + drawOptions.drawFatSegment = [](cpVect a, cpVect b, cpFloat radius, cpSpaceDebugColor /*outlineColor*/, cpSpaceDebugColor /*fillColor*/, cpDataPointer userdata) { - std::array vertices = { first, second }; + const auto& callback = *static_cast(userdata); - callback(vertices.data(), vertices.size()); - }; - - drawCallbacks.thickSegmentCallback = [&](const Vector2f& first, const Vector2f& second, float thickness, Nz::Color /*outlineColor*/, Nz::Color /*fillColor*/, void* /*userData*/) - { static std::pair sincos = Nz::DegreeAnglef(90.f).GetSinCos(); - Vector2f normal = Vector2f::Normalize(second - first); + Vector2f from = FromChipmunk(a); + Vector2f to = FromChipmunk(b); + + Vector2f normal = Vector2f::Normalize(to - from); Vector2f thicknessNormal(sincos.second * normal.x - sincos.first * normal.y, sincos.first * normal.x + sincos.second * normal.y); + float thickness = static_cast(radius); + std::array vertices; - vertices[0] = first + thickness * thicknessNormal; - vertices[1] = first - thickness * thicknessNormal; - vertices[2] = second - thickness * thicknessNormal; - vertices[3] = second + thickness * thicknessNormal; + vertices[0] = from + thickness * thicknessNormal; + vertices[1] = from - thickness * thicknessNormal; + vertices[2] = to - thickness * thicknessNormal; + vertices[3] = to + thickness * thicknessNormal; callback(vertices.data(), vertices.size()); }; - physWorld.DebugDraw(drawCallbacks, true, false, false); + drawOptions.drawPolygon = [](int vertexCount, const cpVect* vertices, cpFloat /*radius*/, cpSpaceDebugColor /*outlineColor*/, cpSpaceDebugColor /*fillColor*/, cpDataPointer userdata) + { + const auto& callback = *static_cast(userdata); + + StackArray nVertices = NazaraStackArray(Vector2f, vertexCount); + for (int i = 0; i < vertexCount; ++i) + nVertices[i].Set(float(vertices[i].x), float(vertices[i].y)); + + callback(nVertices.data(), nVertices.size()); + }; + + drawOptions.drawSegment = [](cpVect a, cpVect b, cpSpaceDebugColor /*fillColor*/, cpDataPointer userdata) + { + const auto& callback = *static_cast(userdata); + + std::array vertices = { FromChipmunk(a), FromChipmunk(b) }; + callback(vertices.data(), vertices.size()); + }; + + cpSpaceDebugDraw(space, &drawOptions); } - std::size_t Collider2D::GenerateShapes(RigidBody2D* body, std::vector* shapes) const + std::size_t Collider2D::GenerateShapes(cpBody* body, std::vector* shapes) const { std::size_t shapeCount = CreateShapes(body, shapes); @@ -123,12 +178,12 @@ namespace Nz ColliderType2D BoxCollider2D::GetType() const { - return ColliderType2D_Box; + return ColliderType2D::Box; } - std::size_t BoxCollider2D::CreateShapes(RigidBody2D* body, std::vector* shapes) const + std::size_t BoxCollider2D::CreateShapes(cpBody* body, std::vector* shapes) const { - shapes->push_back(cpBoxShapeNew2(body->GetHandle(), cpBBNew(m_rect.x, m_rect.y, m_rect.x + m_rect.width, m_rect.y + m_rect.height), m_radius)); + shapes->push_back(cpBoxShapeNew2(body, cpBBNew(m_rect.x, m_rect.y, m_rect.x + m_rect.width, m_rect.y + m_rect.height), m_radius)); return 1; } @@ -152,18 +207,18 @@ namespace Nz ColliderType2D CircleCollider2D::GetType() const { - return ColliderType2D_Circle; + return ColliderType2D::Circle; } - std::size_t CircleCollider2D::CreateShapes(RigidBody2D* body, std::vector* shapes) const + std::size_t CircleCollider2D::CreateShapes(cpBody* body, std::vector* shapes) const { - shapes->push_back(cpCircleShapeNew(body->GetHandle(), m_radius, cpv(m_offset.x, m_offset.y))); + shapes->push_back(cpCircleShapeNew(body, m_radius, cpv(m_offset.x, m_offset.y))); return 1; } /******************************** CompoundCollider2D *********************************/ - CompoundCollider2D::CompoundCollider2D(std::vector geoms) : + CompoundCollider2D::CompoundCollider2D(std::vector> geoms) : m_geoms(std::move(geoms)), m_doesOverrideCollisionProperties(true) { @@ -191,10 +246,10 @@ namespace Nz ColliderType2D CompoundCollider2D::GetType() const { - return ColliderType2D_Compound; + return ColliderType2D::Compound; } - std::size_t CompoundCollider2D::CreateShapes(RigidBody2D* body, std::vector* shapes) const + std::size_t CompoundCollider2D::CreateShapes(cpBody* body, std::vector* shapes) const { // Since C++ does not allow protected call from other objects, we have to be a friend of Collider2D, yay @@ -205,7 +260,7 @@ namespace Nz return shapeCount; } - std::size_t CompoundCollider2D::GenerateShapes(RigidBody2D* body, std::vector* shapes) const + std::size_t CompoundCollider2D::GenerateShapes(cpBody* body, std::vector* shapes) const { // This is our parent's default behavior if (m_doesOverrideCollisionProperties) @@ -248,12 +303,12 @@ namespace Nz ColliderType2D ConvexCollider2D::GetType() const { - return ColliderType2D_Convex; + return ColliderType2D::Convex; } - std::size_t ConvexCollider2D::CreateShapes(RigidBody2D* body, std::vector* shapes) const + std::size_t ConvexCollider2D::CreateShapes(cpBody* body, std::vector* shapes) const { - shapes->push_back(cpPolyShapeNew(body->GetHandle(), int(m_vertices.size()), reinterpret_cast(m_vertices.data()), cpTransformIdentity, m_radius)); + shapes->push_back(cpPolyShapeNew(body, int(m_vertices.size()), reinterpret_cast(m_vertices.data()), cpTransformIdentity, m_radius)); return 1; } @@ -261,7 +316,7 @@ namespace Nz ColliderType2D NullCollider2D::GetType() const { - return ColliderType2D_Null; + return ColliderType2D::Null; } Nz::Vector2f NullCollider2D::ComputeCenterOfMass() const @@ -274,7 +329,7 @@ namespace Nz return (mass > 0.f) ? 1.f : 0.f; //< Null inertia is only possible for static/kinematic objects } - std::size_t NullCollider2D::CreateShapes(RigidBody2D* /*body*/, std::vector* /*shapes*/) const + std::size_t NullCollider2D::CreateShapes(cpBody* /*body*/, std::vector* /*shapes*/) const { return 0; } @@ -293,12 +348,12 @@ namespace Nz ColliderType2D SegmentCollider2D::GetType() const { - return ColliderType2D_Segment; + return ColliderType2D::Segment; } - std::size_t SegmentCollider2D::CreateShapes(RigidBody2D* body, std::vector* shapes) const + std::size_t SegmentCollider2D::CreateShapes(cpBody* body, std::vector* shapes) const { - cpShape* segment = cpSegmentShapeNew(body->GetHandle(), cpv(m_first.x, m_first.y), cpv(m_second.x, m_second.y), m_thickness); + cpShape* segment = cpSegmentShapeNew(body, cpv(m_first.x, m_first.y), cpv(m_second.x, m_second.y), m_thickness); cpSegmentShapeSetNeighbors(segment, cpv(m_firstNeighbor.x, m_firstNeighbor.y), cpv(m_secondNeighbor.x, m_secondNeighbor.y)); shapes->push_back(segment); diff --git a/src/Nazara/Physics2D/RigidBody2D.cpp b/src/Nazara/Physics2D/RigidBody2D.cpp index 409ec357f..81214f859 100644 --- a/src/Nazara/Physics2D/RigidBody2D.cpp +++ b/src/Nazara/Physics2D/RigidBody2D.cpp @@ -18,7 +18,7 @@ namespace Nz { } - RigidBody2D::RigidBody2D(PhysWorld2D* world, float mass, Collider2DRef geom) : + RigidBody2D::RigidBody2D(PhysWorld2D* world, float mass, std::shared_ptr geom) : m_positionOffset(Vector2f::Zero()), m_geom(), m_userData(nullptr), @@ -101,11 +101,11 @@ namespace Nz { switch (coordSys) { - case CoordSys_Global: + case CoordSys::Global: cpBodyApplyForceAtWorldPoint(m_handle, cpv(force.x, force.y), cpv(point.x, point.y)); break; - case CoordSys_Local: + case CoordSys::Local: cpBodyApplyForceAtLocalPoint(m_handle, cpv(force.x, force.y), cpv(point.x, point.y)); break; } @@ -120,11 +120,11 @@ namespace Nz { switch (coordSys) { - case CoordSys_Global: + case CoordSys::Global: cpBodyApplyImpulseAtWorldPoint(m_handle, cpv(impulse.x, impulse.y), cpv(point.x, point.y)); break; - case CoordSys_Local: + case CoordSys::Local: cpBodyApplyImpulseAtLocalPoint(m_handle, cpv(impulse.x, impulse.y), cpv(point.x, point.y)); break; } @@ -233,7 +233,7 @@ namespace Nz return float(cpShapeGetFriction(m_shapes[shapeIndex])); } - const Collider2DRef& RigidBody2D::GetGeom() const + const std::shared_ptr& RigidBody2D::GetGeom() const { return m_geom; } @@ -254,11 +254,11 @@ namespace Nz switch (coordSys) { - case CoordSys_Global: + case CoordSys::Global: massCenter = cpBodyLocalToWorld(m_handle, massCenter); break; - case CoordSys_Local: + case CoordSys::Local: break; // Nothing to do } @@ -374,7 +374,7 @@ namespace Nz cpShapeSetFriction(m_shapes[shapeIndex], cpFloat(friction)); } - void RigidBody2D::SetGeom(Collider2DRef geom, bool recomputeMoment, bool recomputeMassCenter) + void RigidBody2D::SetGeom(std::shared_ptr geom, bool recomputeMoment, bool recomputeMassCenter) { // We have no public way of getting rid of an existing geom without removing the whole body // So let's save some attributes of the body, destroy it and rebuild it @@ -393,11 +393,11 @@ namespace Nz } if (geom) - m_geom = geom; + m_geom = std::move(geom); else - m_geom = NullCollider2D::New(); + m_geom = std::make_shared(); - m_geom->GenerateShapes(this, &m_shapes); + m_geom->GenerateShapes(m_handle, &m_shapes); for (cpShape* shape : m_shapes) cpShapeSetUserData(shape, this); @@ -456,11 +456,11 @@ namespace Nz switch (coordSys) { - case CoordSys_Global: + case CoordSys::Global: massCenter = cpBodyWorldToLocal(m_handle, massCenter); break; - case CoordSys_Local: + case CoordSys::Local: break; // Nothing to do } diff --git a/src/Nazara/Physics3D/Collider3D.cpp b/src/Nazara/Physics3D/Collider3D.cpp index 7736e6129..b1c9681cd 100644 --- a/src/Nazara/Physics3D/Collider3D.cpp +++ b/src/Nazara/Physics3D/Collider3D.cpp @@ -5,33 +5,33 @@ #include #include #include -#include +#include #include namespace Nz { namespace { - Collider3DRef CreateGeomFromPrimitive(const Primitive& primitive) + std::shared_ptr CreateGeomFromPrimitive(const Primitive& primitive) { switch (primitive.type) { - case PrimitiveType_Box: - return BoxCollider3D::New(primitive.box.lengths, primitive.matrix); + case PrimitiveType::Box: + return std::make_shared(primitive.box.lengths, primitive.matrix); - case PrimitiveType_Cone: - return ConeCollider3D::New(primitive.cone.length, primitive.cone.radius, primitive.matrix); + case PrimitiveType::Cone: + return std::make_shared(primitive.cone.length, primitive.cone.radius, primitive.matrix); - case PrimitiveType_Plane: - return BoxCollider3D::New(Vector3f(primitive.plane.size.x, 0.01f, primitive.plane.size.y), primitive.matrix); + case PrimitiveType::Plane: + return std::make_shared(Vector3f(primitive.plane.size.x, 0.01f, primitive.plane.size.y), primitive.matrix); ///TODO: PlaneGeom? - case PrimitiveType_Sphere: - return SphereCollider3D::New(primitive.sphere.size, primitive.matrix.GetTranslation()); + case PrimitiveType::Sphere: + return std::make_shared(primitive.sphere.size, primitive.matrix.GetTranslation()); } - NazaraError("Primitive type not handled (0x" + NumberToString(primitive.type, 16) + ')'); - return Collider3DRef(); + NazaraError("Primitive type not handled (0x" + NumberToString(UnderlyingCast(primitive.type), 16) + ')'); + return std::shared_ptr(); } } @@ -148,42 +148,24 @@ namespace Nz return it->second; } - Collider3DRef Collider3D::Build(const PrimitiveList& list) + std::shared_ptr Collider3D::Build(const PrimitiveList& list) { std::size_t primitiveCount = list.GetSize(); if (primitiveCount > 1) { - std::vector geoms(primitiveCount); + std::vector> geoms(primitiveCount); for (unsigned int i = 0; i < primitiveCount; ++i) geoms[i] = CreateGeomFromPrimitive(list.GetPrimitive(i)); - return CompoundCollider3D::New(std::move(geoms)); + return std::make_shared(std::move(geoms)); } else if (primitiveCount > 0) return CreateGeomFromPrimitive(list.GetPrimitive(0)); else - return NullCollider3D::New(); + return std::make_shared(); } - bool Collider3D::Initialize() - { - if (!Collider3DLibrary::Initialize()) - { - NazaraError("Failed to initialise library"); - return false; - } - - return true; - } - - void Collider3D::Uninitialize() - { - Collider3DLibrary::Uninitialize(); - } - - Collider3DLibrary::LibraryMap Collider3D::s_library; - /********************************** BoxCollider3D **********************************/ BoxCollider3D::BoxCollider3D(const Vector3f& lengths, const Matrix4f& transformMatrix) : @@ -220,7 +202,7 @@ namespace Nz ColliderType3D BoxCollider3D::GetType() const { - return ColliderType3D_Box; + return ColliderType3D::Box; } NewtonCollision* BoxCollider3D::CreateHandle(PhysWorld3D* world) const @@ -254,7 +236,7 @@ namespace Nz ColliderType3D CapsuleCollider3D::GetType() const { - return ColliderType3D_Capsule; + return ColliderType3D::Capsule; } NewtonCollision* CapsuleCollider3D::CreateHandle(PhysWorld3D* world) const @@ -264,19 +246,19 @@ namespace Nz /******************************* CompoundCollider3D ********************************/ - CompoundCollider3D::CompoundCollider3D(std::vector geoms) : + CompoundCollider3D::CompoundCollider3D(std::vector> geoms) : m_geoms(std::move(geoms)) { } - const std::vector& CompoundCollider3D::GetGeoms() const + const std::vector>& CompoundCollider3D::GetGeoms() const { return m_geoms; } ColliderType3D CompoundCollider3D::GetType() const { - return ColliderType3D_Compound; + return ColliderType3D::Compound; } NewtonCollision* CompoundCollider3D::CreateHandle(PhysWorld3D* world) const @@ -284,12 +266,12 @@ namespace Nz NewtonCollision* compoundCollision = NewtonCreateCompoundCollision(world->GetHandle(), 0); NewtonCompoundCollisionBeginAddRemove(compoundCollision); - for (const Collider3DRef& geom : m_geoms) + for (const std::shared_ptr& geom : m_geoms) { - if (geom->GetType() == ColliderType3D_Compound) + if (geom->GetType() == ColliderType3D::Compound) { - CompoundCollider3D* compoundGeom = static_cast(geom.Get()); - for (const Collider3DRef& piece : compoundGeom->GetGeoms()) + CompoundCollider3D& compoundGeom = static_cast(*geom); + for (const std::shared_ptr& piece : compoundGeom.GetGeoms()) NewtonCompoundCollisionAddSubCollision(compoundCollision, piece->GetHandle(world)); } else @@ -326,7 +308,7 @@ namespace Nz ColliderType3D ConeCollider3D::GetType() const { - return ColliderType3D_Cone; + return ColliderType3D::Cone; } NewtonCollision* ConeCollider3D::CreateHandle(PhysWorld3D* world) const @@ -357,7 +339,7 @@ namespace Nz ColliderType3D ConvexCollider3D::GetType() const { - return ColliderType3D_ConvexHull; + return ColliderType3D::ConvexHull; } NewtonCollision* ConvexCollider3D::CreateHandle(PhysWorld3D* world) const @@ -391,7 +373,7 @@ namespace Nz ColliderType3D CylinderCollider3D::GetType() const { - return ColliderType3D_Cylinder; + return ColliderType3D::Cylinder; } NewtonCollision* CylinderCollider3D::CreateHandle(PhysWorld3D* world) const @@ -407,7 +389,7 @@ namespace Nz ColliderType3D NullCollider3D::GetType() const { - return ColliderType3D_Null; + return ColliderType3D::Null; } void NullCollider3D::ComputeInertialMatrix(Vector3f* inertia, Vector3f* center) const @@ -458,7 +440,7 @@ namespace Nz ColliderType3D SphereCollider3D::GetType() const { - return ColliderType3D_Sphere; + return ColliderType3D::Sphere; } NewtonCollision* SphereCollider3D::CreateHandle(PhysWorld3D* world) const diff --git a/src/Nazara/Physics3D/PhysWorld3D.cpp b/src/Nazara/Physics3D/PhysWorld3D.cpp index b436821f1..3cabfb2e6 100644 --- a/src/Nazara/Physics3D/PhysWorld3D.cpp +++ b/src/Nazara/Physics3D/PhysWorld3D.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include diff --git a/src/Nazara/Physics3D/Physics3D.cpp b/src/Nazara/Physics3D/Physics3D.cpp index d54bb2c7c..5795dbeff 100644 --- a/src/Nazara/Physics3D/Physics3D.cpp +++ b/src/Nazara/Physics3D/Physics3D.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include namespace Nz @@ -16,13 +16,6 @@ namespace Nz Physics3D::Physics3D(Config /*config*/) : ModuleBase("Physics3D", this) { - if (!Collider3D::Initialize()) - throw std::runtime_error("failed to initialize colliders"); - } - - Physics3D::~Physics3D() - { - Collider3D::Uninitialize(); } unsigned int Physics3D::GetMemoryUsed() diff --git a/src/Nazara/Physics3D/RigidBody3D.cpp b/src/Nazara/Physics3D/RigidBody3D.cpp index c6fc9b891..40d6bd833 100644 --- a/src/Nazara/Physics3D/RigidBody3D.cpp +++ b/src/Nazara/Physics3D/RigidBody3D.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include #include @@ -12,11 +12,11 @@ namespace Nz { RigidBody3D::RigidBody3D(PhysWorld3D* world, const Matrix4f& mat) : - RigidBody3D(world, NullCollider3D::New(), mat) + RigidBody3D(world, std::make_shared(), mat) { } - RigidBody3D::RigidBody3D(PhysWorld3D* world, Collider3DRef geom, const Matrix4f& mat) : + RigidBody3D::RigidBody3D(PhysWorld3D* world, std::shared_ptr geom, const Matrix4f& mat) : m_geom(std::move(geom)), m_matrix(mat), m_forceAccumulator(Vector3f::Zero()), @@ -28,7 +28,7 @@ namespace Nz NazaraAssert(m_world, "Invalid world"); if (!m_geom) - m_geom = NullCollider3D::New(); + m_geom = std::make_shared(); m_body = NewtonCreateDynamicBody(m_world->GetHandle(), m_geom->GetHandle(m_world), m_matrix); NewtonBodySetUserData(m_body, this); @@ -84,11 +84,11 @@ namespace Nz { switch (coordSys) { - case CoordSys_Global: + case CoordSys::Global: m_forceAccumulator += force; break; - case CoordSys_Local: + case CoordSys::Local: m_forceAccumulator += GetRotation() * force; break; } @@ -101,13 +101,13 @@ namespace Nz { switch (coordSys) { - case CoordSys_Global: + case CoordSys::Global: m_forceAccumulator += force; - m_torqueAccumulator += Vector3f::CrossProduct(point - GetMassCenter(CoordSys_Global), force); + m_torqueAccumulator += Vector3f::CrossProduct(point - GetMassCenter(CoordSys::Global), force); break; - case CoordSys_Local: - return AddForce(m_matrix.Transform(force, 0.f), m_matrix.Transform(point), CoordSys_Global); + case CoordSys::Local: + return AddForce(m_matrix.Transform(force, 0.f), m_matrix.Transform(point), CoordSys::Global); } // On réveille le corps pour que le callback soit appelé et que les forces soient appliquées @@ -118,11 +118,11 @@ namespace Nz { switch (coordSys) { - case CoordSys_Global: + case CoordSys::Global: m_torqueAccumulator += torque; break; - case CoordSys_Local: + case CoordSys::Local: m_torqueAccumulator += m_matrix.Transform(torque, 0.f); break; } @@ -165,7 +165,7 @@ namespace Nz return angularVelocity; } - const Collider3DRef& RigidBody3D::GetGeom() const + const std::shared_ptr& RigidBody3D::GetGeom() const { return m_geom; } @@ -205,11 +205,11 @@ namespace Nz switch (coordSys) { - case CoordSys_Global: + case CoordSys::Global: center = m_matrix.Transform(center); break; - case CoordSys_Local: + case CoordSys::Local: break; // Aucune opération à effectuer sur le centre de rotation } @@ -276,14 +276,14 @@ namespace Nz NewtonBodySetOmega(m_body, &angularVelocity.x); } - void RigidBody3D::SetGeom(Collider3DRef geom) + void RigidBody3D::SetGeom(std::shared_ptr geom) { - if (m_geom.Get() != geom) + if (m_geom != geom) { if (geom) - m_geom = geom; + m_geom = std::move(geom); else - m_geom = NullCollider3D::New(); + m_geom = std::make_shared(); NewtonBodySetCollision(m_body, m_geom->GetHandle(m_world)); } diff --git a/src/Nazara/Platform/Cursor.cpp b/src/Nazara/Platform/Cursor.cpp index 95bb6f755..b3aacb10a 100644 --- a/src/Nazara/Platform/Cursor.cpp +++ b/src/Nazara/Platform/Cursor.cpp @@ -3,24 +3,43 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include namespace Nz { + Cursor::Cursor() = default; + + Cursor::Cursor(const Image& cursor, const Vector2i& hotSpot, SystemCursor placeholder) + { + ErrorFlags flags(ErrorMode::ThrowException, true); + Create(cursor, hotSpot, placeholder); + } + + Cursor::Cursor(SystemCursor systemCursor) + { + ErrorFlags flags(ErrorMode::ThrowException, true); + Create(systemCursor); + } + + Cursor::Cursor(Cursor&&) noexcept = default; + Cursor::~Cursor() = default; + bool Cursor::Create(const Image& cursor, const Vector2i& hotSpot, SystemCursor placeholder) { Destroy(); - std::unique_ptr impl(new CursorImpl); - if (!impl->Create(cursor, hotSpot.x, hotSpot.y)) + try { - NazaraError("Failed to create cursor implementation"); + m_impl = std::make_unique(cursor, hotSpot); + } + catch (const std::exception& e) + { + NazaraError(e.what()); return false; } - m_cursorImage = cursor; - m_impl = impl.release(); m_systemCursor = placeholder; return true; @@ -28,52 +47,46 @@ namespace Nz void Cursor::Destroy() { - m_cursorImage.Destroy(); - - if (m_impl) - { - m_impl->Destroy(); - - delete m_impl; - m_impl = nullptr; - } + m_impl.reset(); } bool Cursor::Create(SystemCursor cursor) { Destroy(); - std::unique_ptr impl(new CursorImpl); - if (!impl->Create(cursor)) + try { - NazaraError("Failed to create cursor implementation"); + m_impl = std::make_unique(cursor); + } + catch (const std::exception& e) + { + NazaraError(e.what()); return false; } - m_impl = impl.release(); m_systemCursor = cursor; return true; } + Cursor& Cursor::operator=(Cursor&&) noexcept = default; + bool Cursor::Initialize() { - if (!CursorImpl::Initialize()) - return false; - - for (std::size_t i = 0; i <= SystemCursor_Max; ++i) - s_systemCursors[i].Create(static_cast(i)); + for (std::size_t i = 0; i < SystemCursorCount; ++i) + { + s_systemCursors[i] = std::make_shared(); + s_systemCursors[i]->Create(static_cast(i)); + } return true; } void Cursor::Uninitialize() { - for (Cursor& cursor : s_systemCursors) - cursor.Destroy(); - - CursorImpl::Uninitialize(); + for (std::shared_ptr& cursor : s_systemCursors) + cursor.reset(); } - std::array Cursor::s_systemCursors; + std::array, SystemCursorCount> Cursor::s_systemCursors; } diff --git a/src/Nazara/Platform/Icon.cpp b/src/Nazara/Platform/Icon.cpp index bc2cb5820..0367a8341 100644 --- a/src/Nazara/Platform/Icon.cpp +++ b/src/Nazara/Platform/Icon.cpp @@ -8,30 +8,38 @@ namespace Nz { + Icon::Icon() = default; + + Icon::Icon(const Image& icon) + { + ErrorFlags flags(ErrorMode::ThrowException, true); + Create(icon); + } + + Icon::Icon(Icon&&) noexcept = default; + Icon::~Icon() = default; + bool Icon::Create(const Image& icon) { Destroy(); - std::unique_ptr impl(new IconImpl); - if (!impl->Create(icon)) + try { - NazaraError("Failed to create icon implementation"); + m_impl = std::make_unique(icon); + } + catch (const std::exception& e) + { + NazaraError(e.what()); return false; } - m_impl = impl.release(); - return true; } void Icon::Destroy() { - if (m_impl) - { - m_impl->Destroy(); - - delete m_impl; - m_impl = nullptr; - } + m_impl.reset(); } + + Icon& Icon::operator=(Icon&&) noexcept = default; } diff --git a/src/Nazara/Platform/SDL2/CursorImpl.cpp b/src/Nazara/Platform/SDL2/CursorImpl.cpp index 5c963ab99..78cc03019 100644 --- a/src/Nazara/Platform/SDL2/CursorImpl.cpp +++ b/src/Nazara/Platform/SDL2/CursorImpl.cpp @@ -2,67 +2,87 @@ // This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include -#include #include -#include +#include #include +#include +#include namespace Nz { - bool CursorImpl::Create(const Image& cursor, int hotSpotX, int hotSpotY) + namespace { - m_iconImage = cursor; - if (!m_iconImage.Convert(PixelFormat_BGRA8)) + std::array s_systemCursorIds = { + SDL_SYSTEM_CURSOR_CROSSHAIR, // SystemCursor::Crosshair + SDL_SYSTEM_CURSOR_ARROW, // SystemCursor::Default + SDL_SYSTEM_CURSOR_HAND, // SystemCursor::Hand + SDL_SYSTEM_CURSOR_ARROW, // SystemCursor::Help + SDL_SYSTEM_CURSOR_SIZEALL, // SystemCursor::Move + SDL_NUM_SYSTEM_CURSORS, // SystemCursor::None + SDL_SYSTEM_CURSOR_HAND, // SystemCursor::Pointer + SDL_SYSTEM_CURSOR_WAITARROW, // SystemCursor::Progress + SDL_SYSTEM_CURSOR_SIZEWE, // SystemCursor::ResizeE + SDL_SYSTEM_CURSOR_SIZENS, // SystemCursor::ResizeN + SDL_SYSTEM_CURSOR_SIZENESW, // SystemCursor::ResizeNE + SDL_SYSTEM_CURSOR_SIZENWSE, // SystemCursor::ResizeNW + SDL_SYSTEM_CURSOR_SIZENS, // SystemCursor::ResizeS + SDL_SYSTEM_CURSOR_SIZENWSE, // SystemCursor::ResizeSE + SDL_SYSTEM_CURSOR_SIZENESW, // SystemCursor::ResizeSW + SDL_SYSTEM_CURSOR_SIZEWE, // SystemCursor::ResizeW + SDL_SYSTEM_CURSOR_IBEAM, // SystemCursor::Text + SDL_SYSTEM_CURSOR_WAIT // SystemCursor::Wait + }; + + static_assert(SystemCursorCount == 18, "System cursor array is incomplete"); + } + + CursorImpl::CursorImpl(const Image& cursor, const Vector2i& hotSpot) + { + ErrorFlags errFlags(ErrorMode::ThrowException); + + m_cursorImage = cursor; + if (!m_cursorImage.Convert(PixelFormat::BGRA8)) NazaraError("Failed to convert icon to BGRA8"); - return false; - } - m_icon = SDL_CreateRGBSurfaceWithFormatFrom( - m_iconImage.GetPixels(), - m_iconImage.GetWidth(), - m_iconImage.GetHeight(), + m_surface = SDL_CreateRGBSurfaceWithFormatFrom( + m_cursorImage.GetPixels(), + m_cursorImage.GetWidth(), + m_cursorImage.GetHeight(), 32, - 32 * m_iconImage.GetWidth(), - SDL_PIXELFORMAT_BGRA8888 - ); + 4 * m_cursorImage.GetWidth(), + SDL_PIXELFORMAT_BGRA32 + ); - if (!m_icon) - { - NazaraError(SDL_GetError()); - - return false; - } - - m_cursor = SDL_CreateColorCursor(m_icon, hotSpotX, hotSpotY); + if (!m_surface) + NazaraError("failed to create SDL Surface for cursor: " + std::string(SDL_GetError())); + m_cursor = SDL_CreateColorCursor(m_surface, hotSpot.x, hotSpot.y); if (!m_cursor) { - NazaraError(SDL_GetError()); + if (m_surface) //< Just in case exceptions were disabled + SDL_FreeSurface(m_surface); - return false; + NazaraError("failed to create SDL cursor: " + std::string(SDL_GetError())); } - - return true; } - bool CursorImpl::Create(SystemCursor cursor) + CursorImpl::CursorImpl(SystemCursor cursor) { - if (cursor != SystemCursor_None) - m_cursor = SDL_CreateSystemCursor(s_systemCursorIds[cursor]); - else - m_cursor = nullptr; + ErrorFlags errFlags(ErrorMode::ThrowException); - m_icon = nullptr; - - return true; + if (cursor != SystemCursor::None) + { + m_cursor = SDL_CreateSystemCursor(s_systemCursorIds[UnderlyingCast(cursor)]); + if (!m_cursor) + NazaraError("failed to create SDL cursor: " + std::string(SDL_GetError())); + } } - void CursorImpl::Destroy() + CursorImpl::~CursorImpl() { - if (m_icon) - SDL_FreeSurface(m_icon); + if (m_surface) + SDL_FreeSurface(m_surface); if (m_cursor) SDL_FreeCursor(m_cursor); @@ -72,37 +92,4 @@ namespace Nz { return m_cursor; } - - bool CursorImpl::Initialize() - { - return true; - } - - void CursorImpl::Uninitialize() - { - } - - std::array CursorImpl::s_systemCursorIds = - { - SDL_SYSTEM_CURSOR_CROSSHAIR, // SystemCursor_Crosshair - SDL_SYSTEM_CURSOR_ARROW, // SystemCursor_Default - SDL_SYSTEM_CURSOR_HAND, // SystemCursor_Hand - SDL_SYSTEM_CURSOR_ARROW, // SystemCursor_Help - SDL_SYSTEM_CURSOR_SIZEALL, // SystemCursor_Move - SDL_NUM_SYSTEM_CURSORS, // SystemCursor_None - SDL_SYSTEM_CURSOR_HAND, // SystemCursor_Pointer - SDL_SYSTEM_CURSOR_WAITARROW, // SystemCursor_Progress - SDL_SYSTEM_CURSOR_SIZEWE, // SystemCursor_ResizeE - SDL_SYSTEM_CURSOR_SIZENS, // SystemCursor_ResizeN - SDL_SYSTEM_CURSOR_SIZENESW, // SystemCursor_ResizeNE - SDL_SYSTEM_CURSOR_SIZENWSE, // SystemCursor_ResizeNW - SDL_SYSTEM_CURSOR_SIZENS, // SystemCursor_ResizeS - SDL_SYSTEM_CURSOR_SIZENWSE, // SystemCursor_ResizeSE - SDL_SYSTEM_CURSOR_SIZENESW, // SystemCursor_ResizeSW - SDL_SYSTEM_CURSOR_SIZEWE, // SystemCursor_ResizeW - SDL_SYSTEM_CURSOR_IBEAM, // SystemCursor_Text - SDL_SYSTEM_CURSOR_WAIT // SystemCursor_Wait - }; - - static_assert(SystemCursor_Max + 1 == 18, "System cursor array is incomplete"); } diff --git a/src/Nazara/Platform/SDL2/CursorImpl.hpp b/src/Nazara/Platform/SDL2/CursorImpl.hpp index 6e637055a..c93ae17ae 100644 --- a/src/Nazara/Platform/SDL2/CursorImpl.hpp +++ b/src/Nazara/Platform/SDL2/CursorImpl.hpp @@ -7,38 +7,33 @@ #ifndef NAZARA_CURSORIMPL_HPP #define NAZARA_CURSORIMPL_HPP -#include -#include #include +#include +#include +#include #include - #include namespace Nz { - class Image; - class CursorImpl { - friend class Cursor; - public: - bool Create(const Image& image, int hotSpotX, int hotSpotY); - bool Create(SystemCursor cursor); - - void Destroy(); + CursorImpl(const Image& image, const Vector2i& hotSpot); + CursorImpl(SystemCursor cursor); + CursorImpl(const CursorImpl&) = delete; + CursorImpl(CursorImpl&&) noexcept = default; + ~CursorImpl(); SDL_Cursor* GetCursor(); + CursorImpl& operator=(const CursorImpl&) = delete; + CursorImpl& operator=(CursorImpl&&) noexcept = default; + private: - static bool Initialize(); - static void Uninitialize(); - - SDL_Cursor* m_cursor = nullptr; - SDL_Surface* m_icon = nullptr; - Image m_iconImage; - - static std::array s_systemCursorIds; + MovablePtr m_cursor; + MovablePtr m_surface; + Image m_cursorImage; }; } diff --git a/src/Nazara/Platform/SDL2/IconImpl.cpp b/src/Nazara/Platform/SDL2/IconImpl.cpp index 1ef8c4fd8..9fd730679 100644 --- a/src/Nazara/Platform/SDL2/IconImpl.cpp +++ b/src/Nazara/Platform/SDL2/IconImpl.cpp @@ -3,20 +3,20 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include #include namespace Nz { - bool IconImpl::Create(const Image& icon) + IconImpl::IconImpl(const Image& icon) { + ErrorFlags errFlags(ErrorMode::ThrowException); + m_iconImage = icon; - if (!m_iconImage.Convert(PixelFormat_BGRA8)) - { + if (!m_iconImage.Convert(PixelFormat::BGRA8)) NazaraError("Failed to convert icon to BGRA8"); - return false; - } m_icon = SDL_CreateRGBSurfaceWithFormatFrom( m_iconImage.GetPixels(), @@ -25,21 +25,16 @@ namespace Nz 32, 32 * m_iconImage.GetWidth(), SDL_PIXELFORMAT_BGRA8888 - ); + ); if (!m_icon) - { - NazaraError(SDL_GetError()); - return false; - } - - return true; + NazaraError("failed to create SDL Surface for icon: " + std::string(SDL_GetError())); } - void IconImpl::Destroy() + IconImpl::~IconImpl() { - SDL_FreeSurface(m_icon); - m_iconImage.Destroy(); + if (m_icon) + SDL_FreeSurface(m_icon); } SDL_Surface* IconImpl::GetIcon() diff --git a/src/Nazara/Platform/SDL2/IconImpl.hpp b/src/Nazara/Platform/SDL2/IconImpl.hpp index 35389f950..600ba357a 100644 --- a/src/Nazara/Platform/SDL2/IconImpl.hpp +++ b/src/Nazara/Platform/SDL2/IconImpl.hpp @@ -8,25 +8,28 @@ #define NAZARA_ICONIMPL_HPP #include +#include #include #include namespace Nz { - class Image; - class IconImpl { public: - bool Create(const Image& image); - void Destroy(); + IconImpl(const Image& image); + IconImpl(const IconImpl&) = delete; + IconImpl(IconImpl&&) noexcept = default; + ~IconImpl(); SDL_Surface* GetIcon(); - private: + IconImpl& operator=(const IconImpl&) = default; + IconImpl& operator=(IconImpl&&) noexcept = default; - SDL_Surface* m_icon = nullptr; + private: Image m_iconImage; + MovablePtr m_icon; }; } diff --git a/src/Nazara/Platform/SDL2/WindowImpl.cpp b/src/Nazara/Platform/SDL2/WindowImpl.cpp index c50b976c7..0ac8fb89e 100644 --- a/src/Nazara/Platform/SDL2/WindowImpl.cpp +++ b/src/Nazara/Platform/SDL2/WindowImpl.cpp @@ -16,6 +16,9 @@ #include #include #include +#include +#include +#include namespace Nz { @@ -62,7 +65,7 @@ namespace Nz bool WindowImpl::Create(const VideoMode& mode, const std::string& title, WindowStyleFlags style) { - bool async = (style & WindowStyle_Threaded) != 0; + bool async = (style & WindowStyle::Threaded) != 0; if (async) { NazaraError("SDL2 backend doesn't support asyn window for now"); @@ -71,7 +74,7 @@ namespace Nz } - bool fullscreen = (style & WindowStyle_Fullscreen) != 0; + bool fullscreen = (style & WindowStyle::Fullscreen) != 0; Uint32 winStyle = 0; @@ -91,16 +94,16 @@ namespace Nz } else { - if (!(style & WindowStyle_Titlebar)) + if (!(style & WindowStyle::Titlebar)) winStyle |= SDL_WINDOW_BORDERLESS; x = SDL_WINDOWPOS_CENTERED; y = SDL_WINDOWPOS_CENTERED; } - if (style & WindowStyle_Resizable) + if (style & WindowStyle::Resizable) winStyle |= SDL_WINDOW_RESIZABLE; - if (style & WindowStyle_Max) + if (style & WindowStyle::Max) winStyle |= SDL_WINDOW_MAXIMIZED; m_eventListener = true; @@ -195,7 +198,7 @@ namespace Nz if (SDL_GetWindowWMInfo(m_handle, &wmInfo) != SDL_TRUE) { - ErrorFlags flags(ErrorFlag_ThrowException, true); + ErrorFlags flags(ErrorMode::ThrowException, true); NazaraError(std::string("failed to retrieve window manager info: ") + SDL_GetError()); } @@ -232,7 +235,7 @@ namespace Nz #endif default: { - ErrorFlags flags(ErrorFlag_ThrowException, true); + ErrorFlags flags(ErrorMode::ThrowException, true); NazaraError("unhandled window subsystem"); } } @@ -310,7 +313,7 @@ namespace Nz auto window = static_cast(userdata); WindowEvent evt; - evt.type = WindowEventType::WindowEventType_Max; + evt.type = WindowEventType::Max; switch (event->type) { @@ -321,10 +324,10 @@ namespace Nz switch (event->window.event) { case SDL_WINDOWEVENT_CLOSE: - evt.type = Nz::WindowEventType::WindowEventType_Quit; + evt.type = WindowEventType::Quit; break; case SDL_WINDOWEVENT_RESIZED: - evt.type = Nz::WindowEventType::WindowEventType_Resized; + evt.type = WindowEventType::Resized; evt.size.width = static_cast(std::max(0, event->window.data1)); evt.size.height = static_cast(std::max(0, event->window.data2)); @@ -333,7 +336,7 @@ namespace Nz break; case SDL_WINDOWEVENT_MOVED: - evt.type = Nz::WindowEventType::WindowEventType_Moved; + evt.type = WindowEventType::Moved; evt.position.x = event->window.data1; evt.position.y = event->window.data2; @@ -342,19 +345,19 @@ namespace Nz break; case SDL_WINDOWEVENT_FOCUS_GAINED: - evt.type = Nz::WindowEventType::WindowEventType_GainedFocus; + evt.type = WindowEventType::GainedFocus; break; case SDL_WINDOWEVENT_FOCUS_LOST: - evt.type = Nz::WindowEventType::WindowEventType_LostFocus; + evt.type = WindowEventType::LostFocus; break; case SDL_WINDOWEVENT_ENTER: - evt.type = Nz::WindowEventType::WindowEventType_MouseEntered; + evt.type = WindowEventType::MouseEntered; break; case SDL_WINDOWEVENT_LEAVE: - evt.type = Nz::WindowEventType::WindowEventType_MouseLeft; + evt.type = WindowEventType::MouseLeft; break; } @@ -371,7 +374,7 @@ namespace Nz return 0; } - evt.type = Nz::WindowEventType::WindowEventType_MouseMoved; + evt.type = WindowEventType::MouseMoved; evt.mouseMove.x = event->motion.x; evt.mouseMove.y = event->motion.y; @@ -390,12 +393,12 @@ namespace Nz if (event->button.clicks % 2 == 0) { - evt.type = Nz::WindowEventType::WindowEventType_MouseButtonDoubleClicked; + evt.type = WindowEventType::MouseButtonDoubleClicked; window->m_parent->PushEvent(evt); } - evt.type = Nz::WindowEventType::WindowEventType_MouseButtonPressed; + evt.type = WindowEventType::MouseButtonPressed; break; @@ -407,7 +410,7 @@ namespace Nz evt.mouseButton.x = event->button.x; evt.mouseButton.y = event->button.y; - evt.type = Nz::WindowEventType::WindowEventType_MouseButtonReleased; + evt.type = WindowEventType::MouseButtonReleased; break; @@ -415,7 +418,7 @@ namespace Nz if (SDL_GetWindowID(window->m_handle) != event->wheel.windowID) return 0; - evt.type = Nz::WindowEventType::WindowEventType_MouseWheelMoved; + evt.type = WindowEventType::MouseWheelMoved; evt.mouseWheel.delta = event->wheel.y; @@ -425,7 +428,7 @@ namespace Nz if (SDL_GetWindowID(window->m_handle) != event->key.windowID) return 0; - evt.type = WindowEventType_KeyPressed; + evt.type = WindowEventType::KeyPressed; evt.key.scancode = SDLHelper::FromSDL(event->key.keysym.scancode); evt.key.virtualKey = SDLHelper::FromSDL(event->key.keysym.sym); @@ -443,7 +446,7 @@ namespace Nz break; window->m_parent->PushEvent(evt); - evt.type = WindowEventType_TextEntered; + evt.type = WindowEventType::TextEntered; evt.text.character = U'\n'; evt.text.repeated = event->key.repeat != 0; @@ -454,7 +457,7 @@ namespace Nz case Nz::Keyboard::VKey::Backspace: window->m_parent->PushEvent(evt); - evt.type = WindowEventType_TextEntered; + evt.type = WindowEventType::TextEntered; evt.text.character = U'\b'; evt.text.repeated = event->key.repeat != 0; @@ -472,7 +475,7 @@ namespace Nz if (SDL_GetWindowID(window->m_handle) != event->key.windowID) return 0; - evt.type = WindowEventType_KeyReleased; + evt.type = WindowEventType::KeyReleased; evt.key.scancode = SDLHelper::FromSDL(event->key.keysym.scancode); evt.key.virtualKey = SDLHelper::FromSDL(event->key.keysym.sym); @@ -485,29 +488,32 @@ namespace Nz break; case SDL_TEXTINPUT: + { if (SDL_GetWindowID(window->m_handle) != event->text.windowID) return 0; - evt.type = WindowEventType_TextEntered; + evt.type = WindowEventType::TextEntered; evt.text.repeated = false; - for (decltype(evt.text.character) codepoint : ToUtf32String(event->text.text)) + utf8::unchecked::iterator it(event->text.text); + do { - evt.text.character = codepoint; + evt.text.character = *it; window->m_parent->PushEvent(evt); - } + } while (*it++); // prevent post switch event - evt.type = WindowEventType::WindowEventType_Max; + evt.type = WindowEventType::Max; break; + } case SDL_TEXTEDITING: if (SDL_GetWindowID(window->m_handle) != event->edit.windowID) return 0; - evt.type = WindowEventType_TextEdited; + evt.type = WindowEventType::TextEdited; evt.edit.length = event->edit.length; window->m_lastEditEventLength = evt.edit.length; @@ -519,7 +525,7 @@ namespace Nz break; } - if (evt.type != WindowEventType::WindowEventType_Max) + if (evt.type != WindowEventType::Max) window->m_parent->PushEvent(evt); } catch (std::exception e) diff --git a/src/Nazara/Platform/Window.cpp b/src/Nazara/Platform/Window.cpp index 733a459c3..dca2d7639 100644 --- a/src/Nazara/Platform/Window.cpp +++ b/src/Nazara/Platform/Window.cpp @@ -61,12 +61,12 @@ namespace Nz Destroy(); // Inspired by the code of the SFML by Laurent Gomila (and its team) - if (style & WindowStyle_Fullscreen) + if (style & WindowStyle::Fullscreen) { if (fullscreenWindow) { NazaraError("Window " + PointerToString(fullscreenWindow) + " already in fullscreen mode"); - style &= ~WindowStyle_Fullscreen; + style &= ~WindowStyle::Fullscreen; } else { @@ -79,10 +79,10 @@ namespace Nz fullscreenWindow = this; } } - else if (style & WindowStyle_Closable || style & WindowStyle_Resizable) - style |= WindowStyle_Titlebar; + else if (style & WindowStyle::Closable || style & WindowStyle::Resizable) + style |= WindowStyle::Titlebar; - m_asyncWindow = (style & WindowStyle_Threaded) != 0; + m_asyncWindow = (style & WindowStyle::Threaded) != 0; std::unique_ptr impl = std::make_unique(this); if (!impl->Create(mode, title, style)) @@ -152,7 +152,7 @@ namespace Nz void Window::Destroy() { - m_cursor.Reset(); + m_cursor.reset(); if (m_impl) { @@ -341,7 +341,7 @@ namespace Nz } } - void Window::SetCursor(CursorRef cursor) + void Window::SetCursor(std::shared_ptr cursor) { NazaraAssert(m_impl, "Window not created"); NazaraAssert(cursor && cursor->IsValid(), "Invalid cursor"); @@ -382,10 +382,10 @@ namespace Nz m_impl->SetFocus(); } - void Window::SetIcon(IconRef icon) + void Window::SetIcon(std::shared_ptr icon) { NazaraAssert(m_impl, "Window not created"); - NazaraAssert(icon && icon.IsValid(), "Invalid icon"); + NazaraAssert(icon, "Invalid icon"); m_icon = std::move(icon); m_impl->SetIcon(*m_icon); @@ -629,7 +629,7 @@ namespace Nz void Window::ConnectSlots() { - m_cursorUpdateSlot.Connect(m_cursorController.OnCursorUpdated, [this](const CursorController*, const CursorRef& cursor) + m_cursorUpdateSlot.Connect(m_cursorController.OnCursorUpdated, [this](const CursorController*, const std::shared_ptr& cursor) { if (IsValid()) SetCursor(cursor); @@ -663,15 +663,15 @@ namespace Nz switch (event.type) { - case WindowEventType_MouseEntered: + case WindowEventType::MouseEntered: m_impl->RefreshCursor(); break; - case WindowEventType_Resized: + case WindowEventType::Resized: OnWindowResized(); break; - case WindowEventType_Quit: + case WindowEventType::Quit: if (m_closeOnQuit) Close(); diff --git a/src/Nazara/Renderer/RenderBuffer.cpp b/src/Nazara/Renderer/RenderBuffer.cpp index 96f4bf05d..89f80fd0b 100644 --- a/src/Nazara/Renderer/RenderBuffer.cpp +++ b/src/Nazara/Renderer/RenderBuffer.cpp @@ -44,14 +44,14 @@ namespace Nz DataStorage RenderBuffer::GetStorage() const { - return DataStorage::DataStorage_Hardware; + return DataStorage::Hardware; } void* RenderBuffer::Map(BufferAccess access, UInt64 offset, UInt64 size) { if (void* ptr = m_softwareBuffer.Map(access, offset, size)) { - if (access != BufferAccess_ReadOnly) + if (access != BufferAccess::ReadOnly) { for (auto& bufferPair : m_hardwareBuffers) bufferPair.second.synchronized = false; diff --git a/src/Nazara/Renderer/RenderDevice.cpp b/src/Nazara/Renderer/RenderDevice.cpp index a4d377db6..826482736 100644 --- a/src/Nazara/Renderer/RenderDevice.cpp +++ b/src/Nazara/Renderer/RenderDevice.cpp @@ -11,10 +11,10 @@ namespace Nz { RenderDevice::~RenderDevice() = default; - std::shared_ptr RenderDevice::InstantiateShaderStage(ShaderStageType type, ShaderLanguage lang, const std::filesystem::path& sourcePath) + std::shared_ptr RenderDevice::InstantiateShaderModule(ShaderStageTypeFlags shaderStages, ShaderLanguage lang, const std::filesystem::path& sourcePath, const ShaderWriter::States& states) { File file(sourcePath); - if (!file.Open(OpenMode_ReadOnly | OpenMode_Text)) + if (!file.Open(OpenMode::ReadOnly | OpenMode::Text)) { NazaraError("Failed to open \"" + sourcePath.generic_u8string() + '"'); return {}; @@ -29,6 +29,6 @@ namespace Nz return {}; } - return InstantiateShaderStage(type, lang, source.data(), source.size()); + return InstantiateShaderModule(shaderStages, lang, source.data(), source.size(), states); } } diff --git a/src/Nazara/Renderer/RenderFrame.cpp b/src/Nazara/Renderer/RenderFrame.cpp index 485ba2aa1..17ffd2dc2 100644 --- a/src/Nazara/Renderer/RenderFrame.cpp +++ b/src/Nazara/Renderer/RenderFrame.cpp @@ -25,14 +25,6 @@ namespace Nz return m_image->GetUploadPool(); } - void RenderFrame::SubmitCommandBuffer(CommandBuffer* commandBuffer, QueueTypeFlags queueTypeFlags) - { - if (!m_image) - throw std::runtime_error("frame is either invalid or has already been presented"); - - m_image->SubmitCommandBuffer(commandBuffer, queueTypeFlags); - } - void RenderFrame::Present() { if (!m_image) @@ -41,4 +33,12 @@ namespace Nz m_image->Present(); m_image = nullptr; } + + void RenderFrame::SubmitCommandBuffer(CommandBuffer* commandBuffer, QueueTypeFlags queueTypeFlags) + { + if (!m_image) + throw std::runtime_error("frame is either invalid or has already been presented"); + + m_image->SubmitCommandBuffer(commandBuffer, queueTypeFlags); + } } diff --git a/src/Nazara/Renderer/RenderImage.cpp b/src/Nazara/Renderer/RenderImage.cpp index 68ba064c7..6560534a1 100644 --- a/src/Nazara/Renderer/RenderImage.cpp +++ b/src/Nazara/Renderer/RenderImage.cpp @@ -7,5 +7,10 @@ namespace Nz { - RenderImage::~RenderImage() = default; + RenderImage::~RenderImage() + { + FlushReleaseQueue(); + } + + RenderImage::Releasable::~Releasable() = default; } diff --git a/src/Nazara/Renderer/RenderWindow.cpp b/src/Nazara/Renderer/RenderWindow.cpp index 48a218ab8..ea4412526 100644 --- a/src/Nazara/Renderer/RenderWindow.cpp +++ b/src/Nazara/Renderer/RenderWindow.cpp @@ -11,6 +11,22 @@ namespace Nz { + bool RenderWindow::Create(std::shared_ptr renderDevice, VideoMode mode, const std::string& title, WindowStyleFlags style, const RenderWindowParameters& parameters) + { + m_parameters = parameters; + m_renderDevice = std::move(renderDevice); + + return Window::Create(mode, title, style); + } + + bool RenderWindow::Create(std::shared_ptr renderDevice, void* handle, const RenderWindowParameters& parameters) + { + m_parameters = parameters; + m_renderDevice = std::move(renderDevice); + + return Window::Create(handle); + } + void RenderWindow::Display() { if (m_framerateLimit > 0) @@ -28,17 +44,9 @@ namespace Nz ///TODO } - std::shared_ptr RenderWindow::GetRenderDevice() - { - if (!m_impl) - return std::shared_ptr(); - - return m_impl->GetRenderDevice(); - } - bool RenderWindow::OnWindowCreated() { - RendererImpl *rendererImpl = Renderer::Instance()->GetRendererImpl(); + RendererImpl* rendererImpl = Renderer::Instance()->GetRendererImpl(); auto surface = rendererImpl->CreateRenderSurfaceImpl(); if (!surface->Create(GetSystemHandle())) { @@ -64,6 +72,7 @@ namespace Nz void RenderWindow::OnWindowDestroy() { m_impl.reset(); + m_renderDevice.reset(); m_surface.reset(); } diff --git a/src/Nazara/Renderer/RenderWindowImpl.cpp b/src/Nazara/Renderer/RenderWindowImpl.cpp new file mode 100644 index 000000000..8e44a79a9 --- /dev/null +++ b/src/Nazara/Renderer/RenderWindowImpl.cpp @@ -0,0 +1,74 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + RenderWindowImpl::~RenderWindowImpl() = default; + + void RenderWindowImpl::BuildRenderPass(PixelFormat colorFormat, PixelFormat depthFormat, std::vector& attachments, std::vector& subpassDescriptions, std::vector& subpassDependencies) + { + assert(colorFormat != PixelFormat::Undefined); + + attachments.push_back({ + colorFormat, + AttachmentLoadOp::Clear, + AttachmentLoadOp::Discard, + AttachmentStoreOp::Store, + AttachmentStoreOp::Discard, + TextureLayout::Undefined, + TextureLayout::Present + }); + + RenderPass::AttachmentReference colorReference = { + 0, + TextureLayout::ColorOutput + }; + + subpassDescriptions.push_back( + { + { colorReference }, + {}, + {}, + std::nullopt + }); + + subpassDependencies.push_back({ + RenderPass::ExternalSubpassIndex, + PipelineStage::ColorOutput, + {}, + + 0, + PipelineStage::ColorOutput, + MemoryAccess::ColorWrite, + + true //< tilable + }); + + if (depthFormat != PixelFormat::Undefined) + { + attachments.push_back({ + depthFormat, + AttachmentLoadOp::Clear, + AttachmentLoadOp::Discard, + AttachmentStoreOp::Discard, + AttachmentStoreOp::Discard, + TextureLayout::Undefined, + TextureLayout::DepthStencilReadWrite + }); + + subpassDescriptions.front().depthStencilAttachment = RenderPass::AttachmentReference{ + 1, + TextureLayout::DepthStencilReadWrite + }; + + auto& subpassDependency = subpassDependencies.front(); + subpassDependency.fromStages |= PipelineStage::FragmentTestsEarly; + subpassDependency.toStages |= PipelineStage::FragmentTestsEarly; + subpassDependency.toAccessFlags |= MemoryAccess::DepthStencilWrite; + } + } +} diff --git a/src/Nazara/Renderer/Renderer.cpp b/src/Nazara/Renderer/Renderer.cpp index 04fa06029..beb12588c 100644 --- a/src/Nazara/Renderer/Renderer.cpp +++ b/src/Nazara/Renderer/Renderer.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -30,9 +31,50 @@ namespace Nz { - namespace + Renderer::Renderer(Config config) : + ModuleBase("Renderer", this) { - std::array s_rendererPaths = { + LoadBackend(config); + + Buffer::SetBufferFactory(DataStorage::Hardware, [](Buffer* parent, BufferType type) -> std::unique_ptr { return std::make_unique(parent, type); }); + } + + Renderer::~Renderer() + { + // Uninitialize module here + Buffer::SetBufferFactory(DataStorage::Hardware, nullptr); + + m_rendererImpl.reset(); + } + + std::shared_ptr Renderer::InstanciateRenderDevice(std::size_t deviceIndex) + { + return m_rendererImpl->InstanciateRenderDevice(deviceIndex); + } + + RenderAPI Renderer::QueryAPI() const + { + return m_rendererImpl->QueryAPI(); + } + + std::string Renderer::QueryAPIString() const + { + return m_rendererImpl->QueryAPIString(); + } + + UInt32 Renderer::QueryAPIVersion() const + { + return m_rendererImpl->QueryAPIVersion(); + } + + const std::vector& Renderer::QueryRenderDevices() const + { + return m_rendererImpl->QueryRenderDevices(); + } + + void Renderer::LoadBackend(const Config& config) + { + constexpr std::array rendererPaths = { NazaraRendererPrefix "NazaraDirect3DRenderer" NazaraRendererDebugSuffix, // Direct3D NazaraRendererPrefix "NazaraMantleRenderer" NazaraRendererDebugSuffix, // Mantle NazaraRendererPrefix "NazaraMetalRenderer" NazaraRendererDebugSuffix, // Metal @@ -41,11 +83,7 @@ namespace Nz nullptr // Unknown }; - } - Renderer::Renderer(Config config) : - ModuleBase("Renderer", this) - { struct RendererImplementations { std::filesystem::path fileName; @@ -55,7 +93,7 @@ namespace Nz auto RegisterImpl = [&](RenderAPI api, auto ComputeScore) { - const char* rendererName = s_rendererPaths[UnderlyingCast(api)]; + const char* rendererName = rendererPaths[UnderlyingCast(api)]; assert(rendererName); std::filesystem::path fileName(rendererName); @@ -122,16 +160,6 @@ namespace Nz m_rendererLib = std::move(chosenLib); NazaraDebug("Using " + m_rendererImpl->QueryAPIString() + " as renderer"); - - Buffer::SetBufferFactory(DataStorage_Hardware, [](Buffer* parent, BufferType type) -> AbstractBuffer* { return new RenderBuffer(parent, type); }); - } - - Renderer::~Renderer() - { - // Uninitialize module here - Buffer::SetBufferFactory(DataStorage_Hardware, nullptr); - - m_rendererImpl.reset(); } Renderer* Renderer::s_instance = nullptr; diff --git a/src/Nazara/Renderer/RendererWindowImpl.cpp b/src/Nazara/Renderer/RendererWindowImpl.cpp deleted file mode 100644 index c677d8e34..000000000 --- a/src/Nazara/Renderer/RendererWindowImpl.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include - -namespace Nz -{ - RenderWindowImpl::~RenderWindowImpl() = default; -} diff --git a/src/Nazara/Renderer/ShaderStageImpl.cpp b/src/Nazara/Renderer/ShaderModule.cpp similarity index 71% rename from src/Nazara/Renderer/ShaderStageImpl.cpp rename to src/Nazara/Renderer/ShaderModule.cpp index dd3e48a63..9994c1eb2 100644 --- a/src/Nazara/Renderer/ShaderStageImpl.cpp +++ b/src/Nazara/Renderer/ShaderModule.cpp @@ -2,10 +2,10 @@ // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include namespace Nz { - ShaderStageImpl::~ShaderStageImpl() = default; + ShaderModule::~ShaderModule() = default; } diff --git a/src/Nazara/Renderer/Texture.cpp b/src/Nazara/Renderer/Texture.cpp index 78e72e65c..3ea632314 100644 --- a/src/Nazara/Renderer/Texture.cpp +++ b/src/Nazara/Renderer/Texture.cpp @@ -3,9 +3,108 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include +#include +#include #include namespace Nz { Texture::~Texture() = default; + + bool TextureParams::IsValid() const + { + if (!ImageParams::IsValid()) + return false; + + if (!renderDevice) + { + NazaraError("no render device set"); + return false; + } + + if (!usageFlags) + { + NazaraError("a texture should have at least one usage flag"); + return false; + } + + return true; + } + + std::shared_ptr Texture::CreateFromImage(const Image& image, const TextureParams& params) + { + NazaraAssert(params.IsValid(), "Invalid TextureParams"); + + Nz::TextureInfo texParams; + texParams.depth = image.GetDepth(); + texParams.height = image.GetHeight(); + texParams.pixelFormat = image.GetFormat(); + texParams.type = image.GetType(); + texParams.width = image.GetWidth(); + texParams.usageFlags = params.usageFlags; + + std::shared_ptr texture = params.renderDevice->InstantiateTexture(texParams); + if (!texture->Update(image.GetConstPixels())) + { + NazaraError("failed to update texture"); + return {}; + } + + return texture; + } + + std::shared_ptr Texture::LoadFromFile(const std::filesystem::path& filePath, const TextureParams& params) + { + std::shared_ptr image = Image::LoadFromFile(filePath, params); + return CreateFromImage(*image, params); + } + + std::shared_ptr Texture::LoadFromMemory(const void* data, std::size_t size, const TextureParams& params) + { + std::shared_ptr image = Image::LoadFromMemory(data, size, params); + return CreateFromImage(*image, params); + } + + std::shared_ptr Texture::LoadFromStream(Stream& stream, const TextureParams& params) + { + std::shared_ptr image = Image::LoadFromStream(stream, params); + return CreateFromImage(*image, params); + } + + std::shared_ptr Texture::LoadArrayFromFile(const std::filesystem::path& filePath, const TextureParams& textureParams, const Vector2ui& atlasSize) + { + std::shared_ptr image = Image::LoadArrayFromFile(filePath, textureParams, atlasSize); + return CreateFromImage(*image, textureParams); + } + + std::shared_ptr Texture::LoadArrayFromMemory(const void* data, std::size_t size, const TextureParams& textureParams, const Vector2ui& atlasSize) + { + std::shared_ptr image = Image::LoadArrayFromMemory(data, size, textureParams, atlasSize); + return CreateFromImage(*image, textureParams); + } + + std::shared_ptr Texture::LoadArrayFromStream(Stream& stream, const TextureParams& textureParams, const Vector2ui& atlasSize) + { + std::shared_ptr image = Image::LoadArrayFromStream(stream, textureParams, atlasSize); + return CreateFromImage(*image, textureParams); + } + + std::shared_ptr Texture::LoadCubemapFromFile(const std::filesystem::path& filePath, const TextureParams& textureParams, const CubemapParams& cubemapParams) + { + std::shared_ptr image = Image::LoadCubemapFromFile(filePath, textureParams, cubemapParams); + return CreateFromImage(*image, textureParams); + } + + std::shared_ptr Texture::LoadCubemapFromMemory(const void* data, std::size_t size, const TextureParams& textureParams, const CubemapParams& cubemapParams) + { + std::shared_ptr image = Image::LoadCubemapFromMemory(data, size, textureParams, cubemapParams); + return CreateFromImage(*image, textureParams); + } + + std::shared_ptr Texture::LoadCubemapFromStream(Stream& stream, const TextureParams& textureParams, const CubemapParams& cubemapParams) + { + std::shared_ptr image = Image::LoadCubemapFromStream(stream, textureParams, cubemapParams); + return CreateFromImage(*image, textureParams); + } } diff --git a/src/Nazara/Shader/Ast/AstCloner.cpp b/src/Nazara/Shader/Ast/AstCloner.cpp new file mode 100644 index 000000000..4fdc9a05b --- /dev/null +++ b/src/Nazara/Shader/Ast/AstCloner.cpp @@ -0,0 +1,391 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz::ShaderAst +{ + ExpressionPtr AstCloner::Clone(const ExpressionPtr& expr) + { + expr->Visit(*this); + + assert(m_statementStack.empty() && m_expressionStack.size() == 1); + return PopExpression(); + } + + StatementPtr AstCloner::Clone(const StatementPtr& statement) + { + statement->Visit(*this); + + assert(m_expressionStack.empty() && m_statementStack.size() == 1); + return PopStatement(); + } + + ExpressionPtr AstCloner::CloneExpression(Expression& expr) + { + expr.Visit(*this); + return PopExpression(); + } + + StatementPtr AstCloner::CloneStatement(Statement& statement) + { + statement.Visit(*this); + return PopStatement(); + } + + StatementPtr AstCloner::Clone(BranchStatement& node) + { + auto clone = std::make_unique(); + clone->condStatements.reserve(node.condStatements.size()); + + for (auto& cond : node.condStatements) + { + auto& condStatement = clone->condStatements.emplace_back(); + condStatement.condition = CloneExpression(cond.condition); + condStatement.statement = CloneStatement(cond.statement); + } + + clone->elseStatement = CloneStatement(node.elseStatement); + + return clone; + } + + StatementPtr AstCloner::Clone(ConditionalStatement& node) + { + auto clone = std::make_unique(); + clone->optionIndex = node.optionIndex; + clone->statement = CloneStatement(node.statement); + + return clone; + } + + StatementPtr AstCloner::Clone(DeclareExternalStatement& node) + { + auto clone = std::make_unique(); + clone->externalVars = node.externalVars; + clone->varIndex = node.varIndex; + + return clone; + } + + StatementPtr AstCloner::Clone(DeclareFunctionStatement& node) + { + auto clone = std::make_unique(); + clone->depthWrite = node.depthWrite; + clone->earlyFragmentTests = node.earlyFragmentTests; + clone->entryStage = node.entryStage; + clone->funcIndex = node.funcIndex; + clone->name = node.name; + clone->optionName = node.optionName; + clone->parameters = node.parameters; + clone->returnType = node.returnType; + clone->varIndex = node.varIndex; + + clone->statements.reserve(node.statements.size()); + for (auto& statement : node.statements) + clone->statements.push_back(CloneStatement(statement)); + + return clone; + } + + StatementPtr AstCloner::Clone(DeclareOptionStatement& node) + { + auto clone = std::make_unique(); + clone->initialValue = CloneExpression(node.initialValue); + clone->optIndex = node.optIndex; + clone->optName = node.optName; + clone->optType = node.optType; + + return clone; + } + + StatementPtr AstCloner::Clone(DeclareStructStatement& node) + { + auto clone = std::make_unique(); + clone->structIndex = node.structIndex; + clone->description = node.description; + + return clone; + } + + StatementPtr AstCloner::Clone(DeclareVariableStatement& node) + { + auto clone = std::make_unique(); + clone->varIndex = node.varIndex; + clone->varName = node.varName; + clone->varType = node.varType; + clone->initialExpression = CloneExpression(node.initialExpression); + + return clone; + } + + StatementPtr AstCloner::Clone(DiscardStatement& /*node*/) + { + return std::make_unique(); + } + + StatementPtr AstCloner::Clone(ExpressionStatement& node) + { + auto clone = std::make_unique(); + clone->expression = CloneExpression(node.expression); + + return clone; + } + + StatementPtr AstCloner::Clone(MultiStatement& node) + { + auto clone = std::make_unique(); + clone->statements.reserve(node.statements.size()); + for (auto& statement : node.statements) + clone->statements.push_back(CloneStatement(statement)); + + return clone; + } + + StatementPtr AstCloner::Clone(NoOpStatement& /*node*/) + { + return std::make_unique(); + } + + StatementPtr AstCloner::Clone(ReturnStatement& node) + { + auto clone = std::make_unique(); + clone->returnExpr = CloneExpression(node.returnExpr); + + return clone; + } + + ExpressionPtr AstCloner::Clone(AccessIdentifierExpression& node) + { + auto clone = std::make_unique(); + clone->identifiers = node.identifiers; + clone->expr = CloneExpression(node.expr); + + clone->cachedExpressionType = node.cachedExpressionType; + + return clone; + } + + ExpressionPtr AstCloner::Clone(AccessIndexExpression& node) + { + auto clone = std::make_unique(); + clone->expr = CloneExpression(node.expr); + + clone->indices.reserve(node.indices.size()); + for (auto& parameter : node.indices) + clone->indices.push_back(CloneExpression(parameter)); + + clone->cachedExpressionType = node.cachedExpressionType; + + return clone; + } + + ExpressionPtr AstCloner::Clone(AssignExpression& node) + { + auto clone = std::make_unique(); + clone->op = node.op; + clone->left = CloneExpression(node.left); + clone->right = CloneExpression(node.right); + + clone->cachedExpressionType = node.cachedExpressionType; + + return clone; + } + + ExpressionPtr AstCloner::Clone(BinaryExpression& node) + { + auto clone = std::make_unique(); + clone->op = node.op; + clone->left = CloneExpression(node.left); + clone->right = CloneExpression(node.right); + + clone->cachedExpressionType = node.cachedExpressionType; + + return clone; + } + + ExpressionPtr AstCloner::Clone(CallFunctionExpression& node) + { + auto clone = std::make_unique(); + clone->targetFunction = node.targetFunction; + + clone->parameters.reserve(node.parameters.size()); + for (auto& parameter : node.parameters) + clone->parameters.push_back(CloneExpression(parameter)); + + clone->cachedExpressionType = node.cachedExpressionType; + + return clone; + } + + ExpressionPtr AstCloner::Clone(CallMethodExpression& node) + { + auto clone = std::make_unique(); + clone->methodName = node.methodName; + + clone->object = CloneExpression(node.object); + + clone->parameters.reserve(node.parameters.size()); + for (auto& parameter : node.parameters) + clone->parameters.push_back(CloneExpression(parameter)); + + clone->cachedExpressionType = node.cachedExpressionType; + + return clone; + } + + ExpressionPtr AstCloner::Clone(CastExpression& node) + { + auto clone = std::make_unique(); + clone->targetType = node.targetType; + + std::size_t expressionCount = 0; + for (auto& expr : node.expressions) + { + if (!expr) + break; + + clone->expressions[expressionCount++] = CloneExpression(expr); + } + + clone->cachedExpressionType = node.cachedExpressionType; + + return clone; + } + + ExpressionPtr AstCloner::Clone(ConditionalExpression& node) + { + auto clone = std::make_unique(); + clone->optionIndex = node.optionIndex; + clone->falsePath = CloneExpression(node.falsePath); + clone->truePath = CloneExpression(node.truePath); + + clone->cachedExpressionType = node.cachedExpressionType; + + return clone; + } + + ExpressionPtr AstCloner::Clone(ConstantExpression& node) + { + auto clone = std::make_unique(); + clone->value = node.value; + + clone->cachedExpressionType = node.cachedExpressionType; + + return clone; + } + + ExpressionPtr AstCloner::Clone(IdentifierExpression& node) + { + auto clone = std::make_unique(); + clone->identifier = node.identifier; + + clone->cachedExpressionType = node.cachedExpressionType; + + return clone; + } + + ExpressionPtr AstCloner::Clone(IntrinsicExpression& node) + { + auto clone = std::make_unique(); + clone->intrinsic = node.intrinsic; + + clone->parameters.reserve(node.parameters.size()); + for (auto& parameter : node.parameters) + clone->parameters.push_back(CloneExpression(parameter)); + + clone->cachedExpressionType = node.cachedExpressionType; + + return clone; + } + + ExpressionPtr AstCloner::Clone(SelectOptionExpression& node) + { + auto clone = std::make_unique(); + clone->optionName = node.optionName; + clone->falsePath = CloneExpression(node.falsePath); + clone->truePath = CloneExpression(node.truePath); + + clone->cachedExpressionType = node.cachedExpressionType; + + return clone; + } + + ExpressionPtr AstCloner::Clone(SwizzleExpression& node) + { + auto clone = std::make_unique(); + clone->componentCount = node.componentCount; + clone->components = node.components; + clone->expression = CloneExpression(node.expression); + + clone->cachedExpressionType = node.cachedExpressionType; + + return clone; + } + + ExpressionPtr AstCloner::Clone(VariableExpression& node) + { + auto clone = std::make_unique(); + clone->variableId = node.variableId; + + clone->cachedExpressionType = node.cachedExpressionType; + + return clone; + } + + ExpressionPtr AstCloner::Clone(UnaryExpression& node) + { + auto clone = std::make_unique(); + clone->expression = CloneExpression(node.expression); + clone->op = node.op; + + clone->cachedExpressionType = node.cachedExpressionType; + + return clone; + } + +#define NAZARA_SHADERAST_EXPRESSION(NodeType) void AstCloner::Visit(NodeType& node) \ + { \ + PushExpression(Clone(node)); \ + } + +#define NAZARA_SHADERAST_STATEMENT(NodeType) void AstCloner::Visit(NodeType& node) \ + { \ + PushStatement(Clone(node)); \ + } + +#include + + void AstCloner::PushExpression(ExpressionPtr expression) + { + m_expressionStack.emplace_back(std::move(expression)); + } + + void AstCloner::PushStatement(StatementPtr statement) + { + m_statementStack.emplace_back(std::move(statement)); + } + + ExpressionPtr AstCloner::PopExpression() + { + assert(!m_expressionStack.empty()); + + ExpressionPtr expr = std::move(m_expressionStack.back()); + m_expressionStack.pop_back(); + + return expr; + } + + StatementPtr AstCloner::PopStatement() + { + assert(!m_statementStack.empty()); + + StatementPtr expr = std::move(m_statementStack.back()); + m_statementStack.pop_back(); + + return expr; + } +} diff --git a/src/Nazara/Shader/Ast/AstExpressionVisitor.cpp b/src/Nazara/Shader/Ast/AstExpressionVisitor.cpp new file mode 100644 index 000000000..671b0c306 --- /dev/null +++ b/src/Nazara/Shader/Ast/AstExpressionVisitor.cpp @@ -0,0 +1,11 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz::ShaderAst +{ + AstExpressionVisitor::~AstExpressionVisitor() = default; +} diff --git a/src/Nazara/Shader/Ast/AstExpressionVisitorExcept.cpp b/src/Nazara/Shader/Ast/AstExpressionVisitorExcept.cpp new file mode 100644 index 000000000..954f8693f --- /dev/null +++ b/src/Nazara/Shader/Ast/AstExpressionVisitorExcept.cpp @@ -0,0 +1,15 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz::ShaderAst +{ +#define NAZARA_SHADERAST_EXPRESSION(Node) void ExpressionVisitorExcept::Visit(ShaderAst::Node& /*node*/) \ + { \ + throw std::runtime_error("unexpected " #Node " node"); \ + } +#include +} diff --git a/src/Nazara/Shader/Ast/AstOptimizer.cpp b/src/Nazara/Shader/Ast/AstOptimizer.cpp new file mode 100644 index 000000000..d178ff423 --- /dev/null +++ b/src/Nazara/Shader/Ast/AstOptimizer.cpp @@ -0,0 +1,965 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include + +namespace Nz::ShaderAst +{ + namespace + { + template + std::unique_ptr static_unique_pointer_cast(std::unique_ptr&& ptr) + { + return std::unique_ptr(static_cast(ptr.release())); + } + + template + struct is_complete_helper + { + template static auto test(U*)->std::integral_constant; + static auto test(...) -> std::false_type; + + using type = decltype(test((T*)0)); + }; + + template + struct is_complete : is_complete_helper::type {}; + + template + inline constexpr bool is_complete_v = is_complete::value; + + /*************************************************************************************************/ + + template + struct BinaryConstantPropagation; + + // CompEq + template + struct BinaryCompEqBase + { + std::unique_ptr operator()(const T1& lhs, const T2& rhs) + { + return ShaderBuilder::Constant(lhs == rhs); + } + }; + + template + struct BinaryCompEq; + + template + struct BinaryConstantPropagation + { + using Op = BinaryCompEq; + }; + + // CompGe + template + struct BinaryCompGeBase + { + std::unique_ptr operator()(const T1& lhs, const T2& rhs) + { + return ShaderBuilder::Constant(lhs >= rhs); + } + }; + + template + struct BinaryCompGe; + + template + struct BinaryConstantPropagation + { + using Op = BinaryCompGe; + }; + + // CompGt + template + struct BinaryCompGtBase + { + std::unique_ptr operator()(const T1& lhs, const T2& rhs) + { + return ShaderBuilder::Constant(lhs > rhs); + } + }; + + template + struct BinaryCompGt; + + template + struct BinaryConstantPropagation + { + using Op = BinaryCompGt; + }; + + // CompLe + template + struct BinaryCompLeBase + { + std::unique_ptr operator()(const T1& lhs, const T2& rhs) + { + return ShaderBuilder::Constant(lhs <= rhs); + } + }; + + template + struct BinaryCompLe; + + template + struct BinaryConstantPropagation + { + using Op = BinaryCompLe; + }; + + // CompLt + template + struct BinaryCompLtBase + { + std::unique_ptr operator()(const T1& lhs, const T2& rhs) + { + return ShaderBuilder::Constant(lhs < rhs); + } + }; + + template + struct BinaryCompLt; + + template + struct BinaryConstantPropagation + { + using Op = BinaryCompLe; + }; + + // CompNe + template + struct BinaryCompNeBase + { + std::unique_ptr operator()(const T1& lhs, const T2& rhs) + { + return ShaderBuilder::Constant(lhs != rhs); + } + }; + + template + struct BinaryCompNe; + + template + struct BinaryConstantPropagation + { + using Op = BinaryCompNe; + }; + + // Addition + template + struct BinaryAdditionBase + { + std::unique_ptr operator()(const T1& lhs, const T2& rhs) + { + return ShaderBuilder::Constant(lhs + rhs); + } + }; + + template + struct BinaryAddition; + + template + struct BinaryConstantPropagation + { + using Op = BinaryAddition; + }; + + // Division + template + struct BinaryDivisionBase + { + std::unique_ptr operator()(const T1& lhs, const T2& rhs) + { + return ShaderBuilder::Constant(lhs / rhs); + } + }; + + template + struct BinaryDivision; + + template + struct BinaryConstantPropagation + { + using Op = BinaryDivision; + }; + + // Multiplication + template + struct BinaryMultiplicationBase + { + std::unique_ptr operator()(const T1& lhs, const T2& rhs) + { + return ShaderBuilder::Constant(lhs * rhs); + } + }; + + template + struct BinaryMultiplication; + + template + struct BinaryConstantPropagation + { + using Op = BinaryMultiplication; + }; + + // Subtraction + template + struct BinarySubtractionBase + { + std::unique_ptr operator()(const T1& lhs, const T2& rhs) + { + return ShaderBuilder::Constant(lhs - rhs); + } + }; + + template + struct BinarySubtraction; + + template + struct BinaryConstantPropagation + { + using Op = BinarySubtraction; + }; + + /*************************************************************************************************/ + + template + struct CastConstantBase + { + std::unique_ptr operator()(const Args&... args) + { + return ShaderBuilder::Constant(T(args...)); + } + }; + + template + struct CastConstant; + + template + struct CastConstantPropagation + { + using Op = CastConstant; + }; + + /*************************************************************************************************/ + + template + struct UnaryConstantPropagation; + + // LogicalNot + template + struct UnaryLogicalNotBase + { + std::unique_ptr operator()(const T& arg) + { + return ShaderBuilder::Constant(!arg); + } + }; + + template + struct UnaryLogicalNot; + + template + struct UnaryConstantPropagation + { + using Op = UnaryLogicalNot; + }; + + // Minus + template + struct UnaryMinusBase + { + std::unique_ptr operator()(const T& arg) + { + return ShaderBuilder::Constant(-arg); + } + }; + + template + struct UnaryMinus; + + template + struct UnaryConstantPropagation + { + using Op = UnaryMinus; + }; + + // Plus + template + struct UnaryPlusBase + { + std::unique_ptr operator()(const T& arg) + { + return ShaderBuilder::Constant(arg); + } + }; + + template + struct UnaryPlus; + + template + struct UnaryConstantPropagation + { + using Op = UnaryPlus; + }; + +#define EnableOptimisation(Op, ...) template<> struct Op<__VA_ARGS__> : Op##Base<__VA_ARGS__> {} + + // Binary + + EnableOptimisation(BinaryCompEq, bool, bool); + EnableOptimisation(BinaryCompEq, double, double); + EnableOptimisation(BinaryCompEq, float, float); + EnableOptimisation(BinaryCompEq, Int32, Int32); + EnableOptimisation(BinaryCompEq, Vector2f, Vector2f); + EnableOptimisation(BinaryCompEq, Vector3f, Vector3f); + EnableOptimisation(BinaryCompEq, Vector4f, Vector4f); + EnableOptimisation(BinaryCompEq, Vector2i32, Vector2i32); + EnableOptimisation(BinaryCompEq, Vector3i32, Vector3i32); + EnableOptimisation(BinaryCompEq, Vector4i32, Vector4i32); + + EnableOptimisation(BinaryCompGe, bool, bool); + EnableOptimisation(BinaryCompGe, double, double); + EnableOptimisation(BinaryCompGe, float, float); + EnableOptimisation(BinaryCompGe, Int32, Int32); + EnableOptimisation(BinaryCompGe, Vector2f, Vector2f); + EnableOptimisation(BinaryCompGe, Vector3f, Vector3f); + EnableOptimisation(BinaryCompGe, Vector4f, Vector4f); + EnableOptimisation(BinaryCompGe, Vector2i32, Vector2i32); + EnableOptimisation(BinaryCompGe, Vector3i32, Vector3i32); + EnableOptimisation(BinaryCompGe, Vector4i32, Vector4i32); + + EnableOptimisation(BinaryCompGt, bool, bool); + EnableOptimisation(BinaryCompGt, double, double); + EnableOptimisation(BinaryCompGt, float, float); + EnableOptimisation(BinaryCompGt, Int32, Int32); + EnableOptimisation(BinaryCompGt, Vector2f, Vector2f); + EnableOptimisation(BinaryCompGt, Vector3f, Vector3f); + EnableOptimisation(BinaryCompGt, Vector4f, Vector4f); + EnableOptimisation(BinaryCompGt, Vector2i32, Vector2i32); + EnableOptimisation(BinaryCompGt, Vector3i32, Vector3i32); + EnableOptimisation(BinaryCompGt, Vector4i32, Vector4i32); + + EnableOptimisation(BinaryCompLe, bool, bool); + EnableOptimisation(BinaryCompLe, double, double); + EnableOptimisation(BinaryCompLe, float, float); + EnableOptimisation(BinaryCompLe, Int32, Int32); + EnableOptimisation(BinaryCompLe, Vector2f, Vector2f); + EnableOptimisation(BinaryCompLe, Vector3f, Vector3f); + EnableOptimisation(BinaryCompLe, Vector4f, Vector4f); + EnableOptimisation(BinaryCompLe, Vector2i32, Vector2i32); + EnableOptimisation(BinaryCompLe, Vector3i32, Vector3i32); + EnableOptimisation(BinaryCompLe, Vector4i32, Vector4i32); + + EnableOptimisation(BinaryCompLt, bool, bool); + EnableOptimisation(BinaryCompLt, double, double); + EnableOptimisation(BinaryCompLt, float, float); + EnableOptimisation(BinaryCompLt, Int32, Int32); + EnableOptimisation(BinaryCompLt, Vector2f, Vector2f); + EnableOptimisation(BinaryCompLt, Vector3f, Vector3f); + EnableOptimisation(BinaryCompLt, Vector4f, Vector4f); + EnableOptimisation(BinaryCompLt, Vector2i32, Vector2i32); + EnableOptimisation(BinaryCompLt, Vector3i32, Vector3i32); + EnableOptimisation(BinaryCompLt, Vector4i32, Vector4i32); + + EnableOptimisation(BinaryCompNe, bool, bool); + EnableOptimisation(BinaryCompNe, double, double); + EnableOptimisation(BinaryCompNe, float, float); + EnableOptimisation(BinaryCompNe, Int32, Int32); + EnableOptimisation(BinaryCompNe, Vector2f, Vector2f); + EnableOptimisation(BinaryCompNe, Vector3f, Vector3f); + EnableOptimisation(BinaryCompNe, Vector4f, Vector4f); + EnableOptimisation(BinaryCompNe, Vector2i32, Vector2i32); + EnableOptimisation(BinaryCompNe, Vector3i32, Vector3i32); + EnableOptimisation(BinaryCompNe, Vector4i32, Vector4i32); + + EnableOptimisation(BinaryAddition, double, double); + EnableOptimisation(BinaryAddition, float, float); + EnableOptimisation(BinaryAddition, Int32, Int32); + EnableOptimisation(BinaryAddition, Vector2f, Vector2f); + EnableOptimisation(BinaryAddition, Vector3f, Vector3f); + EnableOptimisation(BinaryAddition, Vector4f, Vector4f); + EnableOptimisation(BinaryAddition, Vector2i32, Vector2i32); + EnableOptimisation(BinaryAddition, Vector3i32, Vector3i32); + EnableOptimisation(BinaryAddition, Vector4i32, Vector4i32); + + EnableOptimisation(BinaryDivision, double, double); + EnableOptimisation(BinaryDivision, double, Vector2d); + EnableOptimisation(BinaryDivision, double, Vector3d); + EnableOptimisation(BinaryDivision, double, Vector4d); + EnableOptimisation(BinaryDivision, float, float); + EnableOptimisation(BinaryDivision, float, Vector2f); + EnableOptimisation(BinaryDivision, float, Vector3f); + EnableOptimisation(BinaryDivision, float, Vector4f); + EnableOptimisation(BinaryDivision, Int32, Int32); + EnableOptimisation(BinaryDivision, Int32, Vector2i32); + EnableOptimisation(BinaryDivision, Int32, Vector3i32); + EnableOptimisation(BinaryDivision, Int32, Vector4i32); + EnableOptimisation(BinaryDivision, Vector2f, float); + EnableOptimisation(BinaryDivision, Vector2f, Vector2f); + EnableOptimisation(BinaryDivision, Vector3f, float); + EnableOptimisation(BinaryDivision, Vector3f, Vector3f); + EnableOptimisation(BinaryDivision, Vector4f, float); + EnableOptimisation(BinaryDivision, Vector4f, Vector4f); + EnableOptimisation(BinaryDivision, Vector2d, double); + EnableOptimisation(BinaryDivision, Vector2d, Vector2d); + EnableOptimisation(BinaryDivision, Vector3d, double); + EnableOptimisation(BinaryDivision, Vector3d, Vector3d); + EnableOptimisation(BinaryDivision, Vector4d, double); + EnableOptimisation(BinaryDivision, Vector4d, Vector4d); + EnableOptimisation(BinaryDivision, Vector2i32, Int32); + EnableOptimisation(BinaryDivision, Vector2i32, Vector2i32); + EnableOptimisation(BinaryDivision, Vector3i32, Int32); + EnableOptimisation(BinaryDivision, Vector3i32, Vector3i32); + EnableOptimisation(BinaryDivision, Vector4i32, Int32); + EnableOptimisation(BinaryDivision, Vector4i32, Vector4i32); + + EnableOptimisation(BinaryMultiplication, double, double); + EnableOptimisation(BinaryMultiplication, double, Vector2d); + EnableOptimisation(BinaryMultiplication, double, Vector3d); + EnableOptimisation(BinaryMultiplication, double, Vector4d); + EnableOptimisation(BinaryMultiplication, float, float); + EnableOptimisation(BinaryMultiplication, float, Vector2f); + EnableOptimisation(BinaryMultiplication, float, Vector3f); + EnableOptimisation(BinaryMultiplication, float, Vector4f); + EnableOptimisation(BinaryMultiplication, Int32, Int32); + EnableOptimisation(BinaryMultiplication, Int32, Vector2i32); + EnableOptimisation(BinaryMultiplication, Int32, Vector3i32); + EnableOptimisation(BinaryMultiplication, Int32, Vector4i32); + EnableOptimisation(BinaryMultiplication, Vector2f, float); + EnableOptimisation(BinaryMultiplication, Vector2f, Vector2f); + EnableOptimisation(BinaryMultiplication, Vector3f, float); + EnableOptimisation(BinaryMultiplication, Vector3f, Vector3f); + EnableOptimisation(BinaryMultiplication, Vector4f, float); + EnableOptimisation(BinaryMultiplication, Vector4f, Vector4f); + EnableOptimisation(BinaryMultiplication, Vector2d, double); + EnableOptimisation(BinaryMultiplication, Vector2d, Vector2d); + EnableOptimisation(BinaryMultiplication, Vector3d, double); + EnableOptimisation(BinaryMultiplication, Vector3d, Vector3d); + EnableOptimisation(BinaryMultiplication, Vector4d, double); + EnableOptimisation(BinaryMultiplication, Vector4d, Vector4d); + EnableOptimisation(BinaryMultiplication, Vector2i32, Int32); + EnableOptimisation(BinaryMultiplication, Vector2i32, Vector2i32); + EnableOptimisation(BinaryMultiplication, Vector3i32, Int32); + EnableOptimisation(BinaryMultiplication, Vector3i32, Vector3i32); + EnableOptimisation(BinaryMultiplication, Vector4i32, Int32); + EnableOptimisation(BinaryMultiplication, Vector4i32, Vector4i32); + + EnableOptimisation(BinarySubtraction, double, double); + EnableOptimisation(BinarySubtraction, float, float); + EnableOptimisation(BinarySubtraction, Int32, Int32); + EnableOptimisation(BinarySubtraction, Vector2f, Vector2f); + EnableOptimisation(BinarySubtraction, Vector3f, Vector3f); + EnableOptimisation(BinarySubtraction, Vector4f, Vector4f); + EnableOptimisation(BinarySubtraction, Vector2i32, Vector2i32); + EnableOptimisation(BinarySubtraction, Vector3i32, Vector3i32); + EnableOptimisation(BinarySubtraction, Vector4i32, Vector4i32); + + // Cast + + EnableOptimisation(CastConstant, bool, bool); + EnableOptimisation(CastConstant, bool, Int32); + EnableOptimisation(CastConstant, bool, UInt32); + + EnableOptimisation(CastConstant, double, double); + EnableOptimisation(CastConstant, double, float); + EnableOptimisation(CastConstant, double, Int32); + EnableOptimisation(CastConstant, double, UInt32); + + EnableOptimisation(CastConstant, float, double); + EnableOptimisation(CastConstant, float, float); + EnableOptimisation(CastConstant, float, Int32); + EnableOptimisation(CastConstant, float, UInt32); + + EnableOptimisation(CastConstant, Int32, double); + EnableOptimisation(CastConstant, Int32, float); + EnableOptimisation(CastConstant, Int32, Int32); + EnableOptimisation(CastConstant, Int32, UInt32); + + EnableOptimisation(CastConstant, UInt32, double); + EnableOptimisation(CastConstant, UInt32, float); + EnableOptimisation(CastConstant, UInt32, Int32); + EnableOptimisation(CastConstant, UInt32, UInt32); + + //EnableOptimisation(CastConstant, Vector2d, double, double); + //EnableOptimisation(CastConstant, Vector3d, double, double, double); + //EnableOptimisation(CastConstant, Vector4d, double, double, double, double); + + EnableOptimisation(CastConstant, Vector2f, float, float); + EnableOptimisation(CastConstant, Vector3f, float, float, float); + EnableOptimisation(CastConstant, Vector4f, float, float, float, float); + + EnableOptimisation(CastConstant, Vector2i32, Int32, Int32); + EnableOptimisation(CastConstant, Vector3i32, Int32, Int32, Int32); + EnableOptimisation(CastConstant, Vector4i32, Int32, Int32, Int32, Int32); + + //EnableOptimisation(CastConstant, Vector2ui32, UInt32, UInt32); + //EnableOptimisation(CastConstant, Vector3ui32, UInt32, UInt32, UInt32); + //EnableOptimisation(CastConstant, Vector4ui32, UInt32, UInt32, UInt32, UInt32); + + // Unary + + EnableOptimisation(UnaryLogicalNot, bool); + + EnableOptimisation(UnaryMinus, double); + EnableOptimisation(UnaryMinus, float); + EnableOptimisation(UnaryMinus, Int32); + EnableOptimisation(UnaryMinus, Vector2f); + EnableOptimisation(UnaryMinus, Vector3f); + EnableOptimisation(UnaryMinus, Vector4f); + EnableOptimisation(UnaryMinus, Vector2i32); + EnableOptimisation(UnaryMinus, Vector3i32); + EnableOptimisation(UnaryMinus, Vector4i32); + + EnableOptimisation(UnaryPlus, double); + EnableOptimisation(UnaryPlus, float); + EnableOptimisation(UnaryPlus, Int32); + EnableOptimisation(UnaryPlus, Vector2f); + EnableOptimisation(UnaryPlus, Vector3f); + EnableOptimisation(UnaryPlus, Vector4f); + EnableOptimisation(UnaryPlus, Vector2i32); + EnableOptimisation(UnaryPlus, Vector3i32); + EnableOptimisation(UnaryPlus, Vector4i32); + +#undef EnableOptimisation + } + + StatementPtr AstOptimizer::Optimise(const StatementPtr& statement) + { + m_enabledOptions.reset(); + return CloneStatement(statement); + } + + StatementPtr AstOptimizer::Optimise(const StatementPtr& statement, UInt64 enabledConditions) + { + m_enabledOptions = enabledConditions; + + return CloneStatement(statement); + } + + ExpressionPtr AstOptimizer::Clone(BinaryExpression& node) + { + auto lhs = CloneExpression(node.left); + auto rhs = CloneExpression(node.right); + + if (lhs->GetType() == NodeType::ConstantExpression && rhs->GetType() == NodeType::ConstantExpression) + { + auto lhsConstant = static_unique_pointer_cast(std::move(lhs)); + auto rhsConstant = static_unique_pointer_cast(std::move(rhs)); + + ExpressionPtr optimized; + switch (node.op) + { + case BinaryType::Add: + optimized = PropagateBinaryConstant(std::move(lhsConstant), std::move(rhsConstant)); + break; + + case BinaryType::Subtract: + optimized = PropagateBinaryConstant(std::move(lhsConstant), std::move(rhsConstant)); + break; + + case BinaryType::Multiply: + optimized = PropagateBinaryConstant(std::move(lhsConstant), std::move(rhsConstant)); + break; + + case BinaryType::Divide: + optimized = PropagateBinaryConstant(std::move(lhsConstant), std::move(rhsConstant)); + break; + + case BinaryType::CompEq: + optimized = PropagateBinaryConstant(std::move(lhsConstant), std::move(rhsConstant)); + break; + + case BinaryType::CompGe: + optimized = PropagateBinaryConstant(std::move(lhsConstant), std::move(rhsConstant)); + break; + + case BinaryType::CompGt: + optimized = PropagateBinaryConstant(std::move(lhsConstant), std::move(rhsConstant)); + break; + + case BinaryType::CompLe: + optimized = PropagateBinaryConstant(std::move(lhsConstant), std::move(rhsConstant)); + break; + + case BinaryType::CompLt: + optimized = PropagateBinaryConstant(std::move(lhsConstant), std::move(rhsConstant)); + break; + + case BinaryType::CompNe: + optimized = PropagateBinaryConstant(std::move(lhsConstant), std::move(rhsConstant)); + break; + } + + if (optimized) + return optimized; + } + + auto binary = ShaderBuilder::Binary(node.op, std::move(lhs), std::move(rhs)); + binary->cachedExpressionType = node.cachedExpressionType; + + return binary; + } + + ExpressionPtr AstOptimizer::Clone(CastExpression& node) + { + std::array expressions; + + std::size_t expressionCount = 0; + for (const auto& expression : node.expressions) + { + if (!expression) + break; + + expressions[expressionCount] = CloneExpression(expression); + expressionCount++; + } + + ExpressionPtr optimized; + if (IsPrimitiveType(node.targetType)) + { + if (expressionCount == 1 && expressions.front()->GetType() == NodeType::ConstantExpression) + { + auto constantExpr = static_unique_pointer_cast(std::move(expressions.front())); + + switch (std::get(node.targetType)) + { + case PrimitiveType::Boolean: optimized = PropagateSingleValueCast(std::move(constantExpr)); break; + case PrimitiveType::Float32: optimized = PropagateSingleValueCast(std::move(constantExpr)); break; + case PrimitiveType::Int32: optimized = PropagateSingleValueCast(std::move(constantExpr)); break; + case PrimitiveType::UInt32: optimized = PropagateSingleValueCast(std::move(constantExpr)); break; + } + } + } + else if (IsVectorType(node.targetType)) + { + const auto& vecType = std::get(node.targetType); + + // Decompose vector into values (cast(vec3, float) => cast(float, float, float, float)) + std::vector constantValues; + for (std::size_t i = 0; i < expressionCount; ++i) + { + if (expressions[i]->GetType() != NodeType::ConstantExpression) + { + constantValues.clear(); + break; + } + + const auto& constantExpr = static_cast(*expressions[i]); + + if (!constantValues.empty() && GetExpressionType(constantValues.front()) != GetExpressionType(constantExpr.value)) + { + // Unhandled case, all cast parameters are expected to be of the same type + constantValues.clear(); + break; + } + + std::visit([&](auto&& arg) + { + using T = std::decay_t; + + if constexpr (std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v) + constantValues.push_back(arg); + else if constexpr (std::is_same_v || std::is_same_v) + { + constantValues.push_back(arg.x); + constantValues.push_back(arg.y); + } + else if constexpr (std::is_same_v || std::is_same_v) + { + constantValues.push_back(arg.x); + constantValues.push_back(arg.y); + constantValues.push_back(arg.z); + } + else if constexpr (std::is_same_v || std::is_same_v) + { + constantValues.push_back(arg.x); + constantValues.push_back(arg.y); + constantValues.push_back(arg.z); + constantValues.push_back(arg.w); + } + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, constantExpr.value); + } + + if (!constantValues.empty()) + { + assert(constantValues.size() == vecType.componentCount); + + std::visit([&](auto&& arg) + { + using T = std::decay_t; + + switch (vecType.componentCount) + { + case 2: + optimized = PropagateVec2Cast(std::get(constantValues[0]), std::get(constantValues[1])); + break; + + case 3: + optimized = PropagateVec3Cast(std::get(constantValues[0]), std::get(constantValues[1]), std::get(constantValues[2])); + break; + + case 4: + optimized = PropagateVec4Cast(std::get(constantValues[0]), std::get(constantValues[1]), std::get(constantValues[2]), std::get(constantValues[3])); + break; + } + }, constantValues.front()); + } + } + + if (optimized) + return optimized; + + auto cast = ShaderBuilder::Cast(node.targetType, std::move(expressions)); + cast->cachedExpressionType = node.cachedExpressionType; + + return cast; + } + + StatementPtr AstOptimizer::Clone(BranchStatement& node) + { + std::vector statements; + StatementPtr elseStatement; + + for (auto& condStatement : node.condStatements) + { + auto cond = CloneExpression(condStatement.condition); + + if (cond->GetType() == NodeType::ConstantExpression) + { + auto& constant = static_cast(*cond); + + assert(constant.cachedExpressionType); + const ExpressionType& constantType = constant.cachedExpressionType.value(); + + assert(IsPrimitiveType(constantType)); + assert(std::get(constantType) == PrimitiveType::Boolean); + + bool cValue = std::get(constant.value); + if (!cValue) + continue; + + if (statements.empty()) + { + // First condition is true, dismiss the branch + return AstCloner::Clone(condStatement.statement); + } + else + { + // Some condition after the first one is true, make it the else statement and stop there + elseStatement = CloneStatement(condStatement.statement); + break; + } + } + else + { + auto& c = statements.emplace_back(); + c.condition = std::move(cond); + c.statement = CloneStatement(condStatement.statement); + } + } + + if (statements.empty()) + { + // All conditions have been removed, replace by else statement or no-op + if (node.elseStatement) + return AstCloner::Clone(node.elseStatement); + else + return ShaderBuilder::NoOp(); + } + + if (!elseStatement) + elseStatement = CloneStatement(node.elseStatement); + + return ShaderBuilder::Branch(std::move(statements), std::move(elseStatement)); + } + + ExpressionPtr AstOptimizer::Clone(ConditionalExpression& node) + { + if (!m_enabledOptions) + return AstCloner::Clone(node); + + if (TestBit(*m_enabledOptions, node.optionIndex)) + return AstCloner::Clone(node.truePath); + else + return AstCloner::Clone(node.falsePath); + } + + ExpressionPtr AstOptimizer::Clone(UnaryExpression& node) + { + auto expr = CloneExpression(node.expression); + + if (expr->GetType() == NodeType::ConstantExpression) + { + auto constantExpr = static_unique_pointer_cast(std::move(expr)); + + ExpressionPtr optimized; + switch (node.op) + { + case UnaryType::LogicalNot: + optimized = PropagateUnaryConstant(std::move(constantExpr)); + break; + + case UnaryType::Minus: + optimized = PropagateUnaryConstant(std::move(constantExpr)); + break; + + case UnaryType::Plus: + optimized = PropagateUnaryConstant(std::move(constantExpr)); + break; + } + + if (optimized) + return optimized; + } + + auto unary = ShaderBuilder::Unary(node.op, std::move(expr)); + unary->cachedExpressionType = node.cachedExpressionType; + + return unary; + } + + StatementPtr AstOptimizer::Clone(ConditionalStatement& node) + { + if (!m_enabledOptions) + return AstCloner::Clone(node); + + if (TestBit(*m_enabledOptions, node.optionIndex)) + return AstCloner::Clone(node); + else + return ShaderBuilder::NoOp(); + } + + template + ExpressionPtr AstOptimizer::PropagateBinaryConstant(std::unique_ptr&& lhs, std::unique_ptr&& rhs) + { + std::unique_ptr optimized; + std::visit([&](auto&& arg1) + { + using T1 = std::decay_t; + + std::visit([&](auto&& arg2) + { + using T2 = std::decay_t; + using PCType = BinaryConstantPropagation; + + if constexpr (is_complete_v) + { + using Op = typename PCType::Op; + if constexpr (is_complete_v) + optimized = Op{}(arg1, arg2); + } + + }, rhs->value); + }, lhs->value); + + if (optimized) + optimized->cachedExpressionType = GetExpressionType(optimized->value); + + return optimized; + } + + template + ExpressionPtr AstOptimizer::PropagateSingleValueCast(std::unique_ptr&& operand) + { + std::unique_ptr optimized; + + std::visit([&](auto&& arg) + { + using T = std::decay_t; + using CCType = CastConstantPropagation; + + if constexpr (is_complete_v) + { + using Op = typename CCType::Op; + if constexpr (is_complete_v) + optimized = Op{}(arg); + } + }, operand->value); + + return optimized; + } + + template + ExpressionPtr AstOptimizer::PropagateUnaryConstant(std::unique_ptr&& operand) + { + std::unique_ptr optimized; + std::visit([&](auto&& arg) + { + using T = std::decay_t; + using PCType = UnaryConstantPropagation; + + if constexpr (is_complete_v) + { + using Op = typename PCType::Op; + if constexpr (is_complete_v) + optimized = Op{}(arg); + } + }, operand->value); + + if (optimized) + optimized->cachedExpressionType = GetExpressionType(optimized->value); + + return optimized; + } + + template + ExpressionPtr AstOptimizer::PropagateVec2Cast(TargetType v1, TargetType v2) + { + std::unique_ptr optimized; + + using CCType = CastConstantPropagation, TargetType, TargetType>; + + if constexpr (is_complete_v) + { + using Op = typename CCType::Op; + if constexpr (is_complete_v) + optimized = Op{}(v1, v2); + } + + return optimized; + } + + template + ExpressionPtr AstOptimizer::PropagateVec3Cast(TargetType v1, TargetType v2, TargetType v3) + { + std::unique_ptr optimized; + + using CCType = CastConstantPropagation, TargetType, TargetType, TargetType>; + + if constexpr (is_complete_v) + { + using Op = typename CCType::Op; + if constexpr (is_complete_v) + optimized = Op{}(v1, v2, v3); + } + + return optimized; + } + + template + ExpressionPtr AstOptimizer::PropagateVec4Cast(TargetType v1, TargetType v2, TargetType v3, TargetType v4) + { + std::unique_ptr optimized; + + using CCType = CastConstantPropagation, TargetType, TargetType, TargetType, TargetType>; + + if constexpr (is_complete_v) + { + using Op = typename CCType::Op; + if constexpr (is_complete_v) + optimized = Op{}(v1, v2, v3, v4); + } + + return optimized; + } +} diff --git a/src/Nazara/Shader/Ast/AstRecursiveVisitor.cpp b/src/Nazara/Shader/Ast/AstRecursiveVisitor.cpp new file mode 100644 index 000000000..1268b8bf7 --- /dev/null +++ b/src/Nazara/Shader/Ast/AstRecursiveVisitor.cpp @@ -0,0 +1,173 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz::ShaderAst +{ + void AstRecursiveVisitor::Visit(AccessIdentifierExpression& node) + { + node.expr->Visit(*this); + } + + void AstRecursiveVisitor::Visit(AccessIndexExpression& node) + { + node.expr->Visit(*this); + for (auto& index : node.indices) + index->Visit(*this); + } + + void AstRecursiveVisitor::Visit(AssignExpression& node) + { + node.left->Visit(*this); + node.right->Visit(*this); + } + + void AstRecursiveVisitor::Visit(BinaryExpression& node) + { + node.left->Visit(*this); + node.right->Visit(*this); + } + + void AstRecursiveVisitor::Visit(CallFunctionExpression& node) + { + for (auto& param : node.parameters) + param->Visit(*this); + } + + void AstRecursiveVisitor::Visit(CallMethodExpression& node) + { + node.object->Visit(*this); + + for (auto& param : node.parameters) + param->Visit(*this); + } + + void AstRecursiveVisitor::Visit(CastExpression& node) + { + for (auto& expr : node.expressions) + { + if (!expr) + break; + + expr->Visit(*this); + } + } + + void AstRecursiveVisitor::Visit(ConditionalExpression& node) + { + node.truePath->Visit(*this); + node.falsePath->Visit(*this); + } + + void AstRecursiveVisitor::Visit(ConstantExpression& /*node*/) + { + /* Nothing to do */ + } + + void AstRecursiveVisitor::Visit(IdentifierExpression& /*node*/) + { + /* Nothing to do */ + } + + void AstRecursiveVisitor::Visit(IntrinsicExpression& node) + { + for (auto& param : node.parameters) + param->Visit(*this); + } + + void AstRecursiveVisitor::Visit(SelectOptionExpression& node) + { + node.truePath->Visit(*this); + node.falsePath->Visit(*this); + } + + void AstRecursiveVisitor::Visit(SwizzleExpression& node) + { + node.expression->Visit(*this); + } + + void AstRecursiveVisitor::Visit(VariableExpression& /*node*/) + { + /* Nothing to do */ + } + + void AstRecursiveVisitor::Visit(UnaryExpression& node) + { + node.expression->Visit(*this); + } + + void AstRecursiveVisitor::Visit(BranchStatement& node) + { + for (auto& cond : node.condStatements) + { + cond.condition->Visit(*this); + cond.statement->Visit(*this); + } + + if (node.elseStatement) + node.elseStatement->Visit(*this); + } + + void AstRecursiveVisitor::Visit(ConditionalStatement& node) + { + node.statement->Visit(*this); + } + + void AstRecursiveVisitor::Visit(DeclareExternalStatement& /*node*/) + { + /* Nothing to do */ + } + + void AstRecursiveVisitor::Visit(DeclareFunctionStatement& node) + { + for (auto& statement : node.statements) + statement->Visit(*this); + } + + void AstRecursiveVisitor::Visit(DeclareOptionStatement& node) + { + if (node.initialValue) + node.initialValue->Visit(*this); + } + + void AstRecursiveVisitor::Visit(DeclareStructStatement& /*node*/) + { + /* Nothing to do */ + } + + void AstRecursiveVisitor::Visit(DeclareVariableStatement& node) + { + if (node.initialExpression) + node.initialExpression->Visit(*this); + } + + void AstRecursiveVisitor::Visit(DiscardStatement& /*node*/) + { + /* Nothing to do */ + } + + void AstRecursiveVisitor::Visit(ExpressionStatement& node) + { + node.expression->Visit(*this); + } + + void AstRecursiveVisitor::Visit(MultiStatement& node) + { + for (auto& statement : node.statements) + statement->Visit(*this); + } + + void AstRecursiveVisitor::Visit(NoOpStatement& /*node*/) + { + /* Nothing to do */ + } + + void AstRecursiveVisitor::Visit(ReturnStatement& node) + { + if (node.returnExpr) + node.returnExpr->Visit(*this); + } +} diff --git a/src/Nazara/Shader/Ast/AstReflect.cpp b/src/Nazara/Shader/Ast/AstReflect.cpp new file mode 100644 index 000000000..350e0484f --- /dev/null +++ b/src/Nazara/Shader/Ast/AstReflect.cpp @@ -0,0 +1,25 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz::ShaderAst +{ + void AstReflect::Reflect(const StatementPtr& statement, const Callbacks& callbacks) + { + assert(statement); + + m_callbacks = &callbacks; + statement->Visit(*this); + } + + void AstReflect::Visit(DeclareOptionStatement& node) + { + assert(m_callbacks); + if (m_callbacks->onOptionDeclaration) + m_callbacks->onOptionDeclaration(node.optName, node.optType); + } +} diff --git a/src/Nazara/Shader/Ast/AstSerializer.cpp b/src/Nazara/Shader/Ast/AstSerializer.cpp new file mode 100644 index 000000000..6c489bbce --- /dev/null +++ b/src/Nazara/Shader/Ast/AstSerializer.cpp @@ -0,0 +1,772 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include + +namespace Nz::ShaderAst +{ + namespace + { + constexpr UInt32 s_magicNumber = 0x4E534852; + constexpr UInt32 s_currentVersion = 1; + + class ShaderSerializerVisitor : public AstExpressionVisitor, public AstStatementVisitor + { + public: + ShaderSerializerVisitor(AstSerializerBase& serializer) : + m_serializer(serializer) + { + } + +#define NAZARA_SHADERAST_NODE(Node) void Visit(Node& node) override \ + { \ + m_serializer.Serialize(node); \ + } +#include + + private: + AstSerializerBase& m_serializer; + }; + } + + void AstSerializerBase::Serialize(AccessIdentifierExpression& node) + { + Node(node.expr); + + Container(node.identifiers); + for (std::string& identifier : node.identifiers) + Value(identifier); + } + + void AstSerializerBase::Serialize(AccessIndexExpression& node) + { + Node(node.expr); + + Container(node.indices); + for (auto& identifier : node.indices) + Node(identifier); + } + + void AstSerializerBase::Serialize(AssignExpression& node) + { + Enum(node.op); + Node(node.left); + Node(node.right); + } + + void AstSerializerBase::Serialize(BinaryExpression& node) + { + Enum(node.op); + Node(node.left); + Node(node.right); + } + + void AstSerializerBase::Serialize(CallFunctionExpression& node) + { + UInt32 typeIndex; + if (IsWriting()) + typeIndex = UInt32(node.targetFunction.index()); + + Value(typeIndex); + + // Waiting for template lambda in C++20 + auto SerializeValue = [&](auto dummyType) + { + using T = std::decay_t; + + auto& value = (IsWriting()) ? std::get(node.targetFunction) : node.targetFunction.emplace(); + Value(value); + }; + + static_assert(std::variant_size_v == 2); + switch (typeIndex) + { + case 0: SerializeValue(std::string()); break; + case 1: SerializeValue(std::size_t()); break; + } + + Container(node.parameters); + for (auto& param : node.parameters) + Node(param); + } + + void AstSerializerBase::Serialize(CallMethodExpression& node) + { + Node(node.object); + Value(node.methodName); + + Container(node.parameters); + for (auto& param : node.parameters) + Node(param); + } + + void AstSerializerBase::Serialize(CastExpression& node) + { + Type(node.targetType); + for (auto& expr : node.expressions) + Node(expr); + } + + void AstSerializerBase::Serialize(ConditionalExpression& node) + { + SizeT(node.optionIndex); + Node(node.truePath); + Node(node.falsePath); + } + + void AstSerializerBase::Serialize(ConstantExpression& node) + { + UInt32 typeIndex; + if (IsWriting()) + typeIndex = UInt32(node.value.index()); + + Value(typeIndex); + + // Waiting for template lambda in C++20 + auto SerializeValue = [&](auto dummyType) + { + using T = std::decay_t; + + auto& value = (IsWriting()) ? std::get(node.value) : node.value.emplace(); + Value(value); + }; + + static_assert(std::variant_size_v == 10); + switch (typeIndex) + { + case 0: SerializeValue(bool()); break; + case 1: SerializeValue(float()); break; + case 2: SerializeValue(Int32()); break; + case 3: SerializeValue(UInt32()); break; + case 4: SerializeValue(Vector2f()); break; + case 5: SerializeValue(Vector3f()); break; + case 6: SerializeValue(Vector4f()); break; + case 7: SerializeValue(Vector2i32()); break; + case 8: SerializeValue(Vector3i32()); break; + case 9: SerializeValue(Vector4i32()); break; + default: throw std::runtime_error("unexpected data type"); + } + } + + void AstSerializerBase::Serialize(IdentifierExpression& node) + { + Value(node.identifier); + } + + void AstSerializerBase::Serialize(IntrinsicExpression& node) + { + Enum(node.intrinsic); + Container(node.parameters); + for (auto& param : node.parameters) + Node(param); + } + + void AstSerializerBase::Serialize(SelectOptionExpression& node) + { + Value(node.optionName); + Node(node.truePath); + Node(node.falsePath); + } + + void AstSerializerBase::Serialize(SwizzleExpression& node) + { + SizeT(node.componentCount); + Node(node.expression); + + for (std::size_t i = 0; i < node.componentCount; ++i) + Enum(node.components[i]); + } + + void AstSerializerBase::Serialize(VariableExpression& node) + { + SizeT(node.variableId); + } + + void AstSerializerBase::Serialize(UnaryExpression& node) + { + Enum(node.op); + Node(node.expression); + } + + + void AstSerializerBase::Serialize(BranchStatement& node) + { + Container(node.condStatements); + for (auto& condStatement : node.condStatements) + { + Node(condStatement.condition); + Node(condStatement.statement); + } + + Node(node.elseStatement); + } + + void AstSerializerBase::Serialize(ConditionalStatement& node) + { + SizeT(node.optionIndex); + Node(node.statement); + } + + void AstSerializerBase::Serialize(DeclareExternalStatement& node) + { + OptVal(node.varIndex); + + Container(node.externalVars); + for (auto& extVar : node.externalVars) + { + Value(extVar.name); + Type(extVar.type); + OptVal(extVar.bindingIndex); + } + } + + void AstSerializerBase::Serialize(DeclareFunctionStatement& node) + { + Value(node.name); + Type(node.returnType); + OptEnum(node.depthWrite); + OptVal(node.earlyFragmentTests); + OptEnum(node.entryStage); + OptVal(node.funcIndex); + Value(node.optionName); + OptVal(node.varIndex); + + Container(node.parameters); + for (auto& parameter : node.parameters) + { + Value(parameter.name); + Type(parameter.type); + } + + Container(node.statements); + for (auto& statement : node.statements) + Node(statement); + } + + void AstSerializerBase::Serialize(DeclareOptionStatement& node) + { + OptVal(node.optIndex); + Value(node.optName); + Type(node.optType); + Node(node.initialValue); + } + + void AstSerializerBase::Serialize(DeclareStructStatement& node) + { + OptVal(node.structIndex); + + Value(node.description.name); + OptEnum(node.description.layout); + + Container(node.description.members); + for (auto& member : node.description.members) + { + Value(member.name); + Type(member.type); + OptEnum(member.builtin); + OptVal(member.locationIndex); + } + } + + void AstSerializerBase::Serialize(DeclareVariableStatement& node) + { + OptVal(node.varIndex); + Value(node.varName); + Type(node.varType); + Node(node.initialExpression); + } + + void AstSerializerBase::Serialize(DiscardStatement& /*node*/) + { + /* Nothing to do */ + } + + void AstSerializerBase::Serialize(ExpressionStatement& node) + { + Node(node.expression); + } + + void AstSerializerBase::Serialize(MultiStatement& node) + { + Container(node.statements); + for (auto& statement : node.statements) + Node(statement); + } + + void AstSerializerBase::Serialize(NoOpStatement& /*node*/) + { + /* Nothing to do */ + } + + void AstSerializerBase::Serialize(ReturnStatement& node) + { + Node(node.returnExpr); + } + + void ShaderAstSerializer::Serialize(StatementPtr& shader) + { + m_stream << s_magicNumber << s_currentVersion; + + Node(shader); + + m_stream.FlushBits(); + } + + bool ShaderAstSerializer::IsWriting() const + { + return true; + } + + void ShaderAstSerializer::Node(ExpressionPtr& node) + { + NodeType nodeType = (node) ? node->GetType() : NodeType::None; + m_stream << static_cast(nodeType); + + if (node) + { + ShaderSerializerVisitor visitor(*this); + node->Visit(visitor); + } + } + + void ShaderAstSerializer::Node(StatementPtr& node) + { + NodeType nodeType = (node) ? node->GetType() : NodeType::None; + m_stream << static_cast(nodeType); + + if (node) + { + ShaderSerializerVisitor visitor(*this); + node->Visit(visitor); + } + } + + void ShaderAstSerializer::Type(ExpressionType& type) + { + std::visit([&](auto&& arg) + { + using T = std::decay_t; + + if constexpr (std::is_same_v) + m_stream << UInt8(0); + else if constexpr (std::is_same_v) + { + m_stream << UInt8(1); + m_stream << UInt32(arg); + } + else if constexpr (std::is_same_v) + { + m_stream << UInt8(2); + m_stream << arg.name; + } + else if constexpr (std::is_same_v) + { + m_stream << UInt8(3); + m_stream << UInt32(arg.columnCount); + m_stream << UInt32(arg.rowCount); + m_stream << UInt32(arg.type); + } + else if constexpr (std::is_same_v) + { + m_stream << UInt8(4); + m_stream << UInt32(arg.dim); + m_stream << UInt32(arg.sampledType); + } + else if constexpr (std::is_same_v) + { + m_stream << UInt8(5); + m_stream << UInt32(arg.structIndex); + } + else if constexpr (std::is_same_v) + { + m_stream << UInt8(6); + m_stream << std::get(arg.containedType).name; + } + else if constexpr (std::is_same_v) + { + m_stream << UInt8(7); + m_stream << UInt32(arg.componentCount); + m_stream << UInt32(arg.type); + } + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, type); + } + + void ShaderAstSerializer::Value(bool& val) + { + m_stream << val; + } + + void ShaderAstSerializer::Value(float& val) + { + m_stream << val; + } + + void ShaderAstSerializer::Value(std::string& val) + { + m_stream << val; + } + + void ShaderAstSerializer::Value(Int32& val) + { + m_stream << val; + } + + void ShaderAstSerializer::Value(Vector2f& val) + { + m_stream << val; + } + + void ShaderAstSerializer::Value(Vector3f& val) + { + m_stream << val; + } + + void ShaderAstSerializer::Value(Vector4f& val) + { + m_stream << val; + } + + void ShaderAstSerializer::Value(Vector2i32& val) + { + m_stream << val; + } + + void ShaderAstSerializer::Value(Vector3i32& val) + { + m_stream << val; + } + + void ShaderAstSerializer::Value(Vector4i32& val) + { + m_stream << val; + } + + void ShaderAstSerializer::Value(UInt8& val) + { + m_stream << val; + } + + void ShaderAstSerializer::Value(UInt16& val) + { + m_stream << val; + } + + void ShaderAstSerializer::Value(UInt32& val) + { + m_stream << val; + } + + void ShaderAstSerializer::Value(UInt64& val) + { + m_stream << val; + } + + StatementPtr ShaderAstUnserializer::Unserialize() + { + UInt32 magicNumber; + UInt32 version; + m_stream >> magicNumber; + if (magicNumber != s_magicNumber) + throw std::runtime_error("invalid shader file"); + + m_stream >> version; + if (version > s_currentVersion) + throw std::runtime_error("unsupported version"); + + StatementPtr node; + + Node(node); + if (!node) + throw std::runtime_error("functions can only have statements"); + + return node; + } + + bool ShaderAstUnserializer::IsWriting() const + { + return false; + } + + void ShaderAstUnserializer::Node(ExpressionPtr& node) + { + Int32 nodeTypeInt; + m_stream >> nodeTypeInt; + + if (nodeTypeInt < static_cast(NodeType::None) || nodeTypeInt > static_cast(NodeType::Max)) + throw std::runtime_error("invalid node type"); + + NodeType nodeType = static_cast(nodeTypeInt); + switch (nodeType) + { + case NodeType::None: break; + +#define NAZARA_SHADERAST_EXPRESSION(Node) case NodeType:: Node : node = std::make_unique(); break; +#include + + default: throw std::runtime_error("unexpected node type"); + } + + if (node) + { + ShaderSerializerVisitor visitor(*this); + node->Visit(visitor); + } + } + + void ShaderAstUnserializer::Node(StatementPtr& node) + { + Int32 nodeTypeInt; + m_stream >> nodeTypeInt; + + if (nodeTypeInt < static_cast(NodeType::None) || nodeTypeInt > static_cast(NodeType::Max)) + throw std::runtime_error("invalid node type"); + + NodeType nodeType = static_cast(nodeTypeInt); + switch (nodeType) + { + case NodeType::None: break; + +#define NAZARA_SHADERAST_STATEMENT(Node) case NodeType:: Node : node = std::make_unique(); break; +#include + + default: throw std::runtime_error("unexpected node type"); + } + + if (node) + { + ShaderSerializerVisitor visitor(*this); + node->Visit(visitor); + } + } + + void ShaderAstUnserializer::Type(ExpressionType& type) + { + UInt8 typeIndex; + Value(typeIndex); + + switch (typeIndex) + { + /* + if constexpr (std::is_same_v) + m_stream << UInt8(0); + else if constexpr (std::is_same_v) + { + m_stream << UInt8(1); + m_stream << UInt32(arg); + } + else if constexpr (std::is_same_v) + { + m_stream << UInt8(2); + m_stream << arg.name; + } + else if constexpr (std::is_same_v) + { + m_stream << UInt8(3); + m_stream << UInt32(arg.columnCount); + m_stream << UInt32(arg.rowCount); + m_stream << UInt32(arg.type); + } + else if constexpr (std::is_same_v) + { + m_stream << UInt8(4); + m_stream << UInt32(arg.dim); + m_stream << UInt32(arg.sampledType); + } + else if constexpr (std::is_same_v) + { + m_stream << UInt8(5); + m_stream << UInt32(arg.componentCount); + m_stream << UInt32(arg.type); + } + */ + + case 0: //< NoType + type = NoType{}; + break; + + case 1: //< PrimitiveType + { + PrimitiveType primitiveType; + Enum(primitiveType); + + type = primitiveType; + break; + } + + case 2: //< Identifier + { + std::string identifier; + Value(identifier); + + type = IdentifierType{ std::move(identifier) }; + break; + } + + case 3: //< MatrixType + { + UInt32 columnCount, rowCount; + PrimitiveType primitiveType; + Value(columnCount); + Value(rowCount); + Enum(primitiveType); + + type = MatrixType { + columnCount, + rowCount, + primitiveType + }; + break; + } + + case 4: //< SamplerType + { + ImageType dim; + PrimitiveType sampledType; + Enum(dim); + Enum(sampledType); + + type = SamplerType { + dim, + sampledType + }; + break; + } + + case 5: //< StructType + { + UInt32 structIndex; + Value(structIndex); + + type = StructType{ + structIndex + }; + break; + } + + case 6: //< UniformType + { + std::string containedType; + Value(containedType); + + type = UniformType { + IdentifierType { + containedType + } + }; + break; + } + + case 7: //< VectorType + { + UInt32 componentCount; + PrimitiveType componentType; + Value(componentCount); + Enum(componentType); + + type = VectorType{ + componentCount, + componentType + }; + break; + } + + default: + break; + } + } + + void ShaderAstUnserializer::Value(bool& val) + { + m_stream >> val; + } + + void ShaderAstUnserializer::Value(float& val) + { + m_stream >> val; + } + + void ShaderAstUnserializer::Value(std::string& val) + { + m_stream >> val; + } + + void ShaderAstUnserializer::Value(Int32& val) + { + m_stream >> val; + } + + void ShaderAstUnserializer::Value(Vector2f& val) + { + m_stream >> val; + } + + void ShaderAstUnserializer::Value(Vector3f& val) + { + m_stream >> val; + } + + void ShaderAstUnserializer::Value(Vector4f& val) + { + m_stream >> val; + } + + void ShaderAstUnserializer::Value(Vector2i32& val) + { + m_stream >> val; + } + + void ShaderAstUnserializer::Value(Vector3i32& val) + { + m_stream >> val; + } + + void ShaderAstUnserializer::Value(Vector4i32& val) + { + m_stream >> val; + } + + void ShaderAstUnserializer::Value(UInt8& val) + { + m_stream >> val; + } + + void ShaderAstUnserializer::Value(UInt16& val) + { + m_stream >> val; + } + + void ShaderAstUnserializer::Value(UInt32& val) + { + m_stream >> val; + } + + void ShaderAstUnserializer::Value(UInt64& val) + { + m_stream >> val; + } + + + ByteArray SerializeShader(StatementPtr& shader) + { + ByteArray byteArray; + ByteStream stream(&byteArray, OpenModeFlags(OpenMode::WriteOnly)); + + ShaderAstSerializer serializer(stream); + serializer.Serialize(shader); + + return byteArray; + } + + StatementPtr UnserializeShader(ByteStream& stream) + { + ShaderAstUnserializer unserializer(stream); + return unserializer.Unserialize(); + } +} + diff --git a/src/Nazara/Shader/Ast/AstStatementVisitor.cpp b/src/Nazara/Shader/Ast/AstStatementVisitor.cpp new file mode 100644 index 000000000..8d1cca01f --- /dev/null +++ b/src/Nazara/Shader/Ast/AstStatementVisitor.cpp @@ -0,0 +1,11 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz::ShaderAst +{ + AstStatementVisitor::~AstStatementVisitor() = default; +} diff --git a/src/Nazara/Shader/Ast/AstStatementVisitorExcept.cpp b/src/Nazara/Shader/Ast/AstStatementVisitorExcept.cpp new file mode 100644 index 000000000..9a4e36783 --- /dev/null +++ b/src/Nazara/Shader/Ast/AstStatementVisitorExcept.cpp @@ -0,0 +1,15 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz::ShaderAst +{ +#define NAZARA_SHADERAST_STATEMENT(Node) void StatementVisitorExcept::Visit(ShaderAst::Node& /*node*/) \ + { \ + throw std::runtime_error("unexpected " #Node " node"); \ + } +#include +} diff --git a/src/Nazara/Shader/Ast/AstUtils.cpp b/src/Nazara/Shader/Ast/AstUtils.cpp new file mode 100644 index 000000000..db9b50895 --- /dev/null +++ b/src/Nazara/Shader/Ast/AstUtils.cpp @@ -0,0 +1,108 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz::ShaderAst +{ + ExpressionCategory ShaderAstValueCategory::GetExpressionCategory(Expression& expression) + { + expression.Visit(*this); + return m_expressionCategory; + } + + void ShaderAstValueCategory::Visit(AccessIdentifierExpression& node) + { + node.expr->Visit(*this); + } + + void ShaderAstValueCategory::Visit(AccessIndexExpression& node) + { + node.expr->Visit(*this); + } + + void ShaderAstValueCategory::Visit(AssignExpression& /*node*/) + { + m_expressionCategory = ExpressionCategory::RValue; + } + + void ShaderAstValueCategory::Visit(BinaryExpression& /*node*/) + { + m_expressionCategory = ExpressionCategory::RValue; + } + + void ShaderAstValueCategory::Visit(CallFunctionExpression& /*node*/) + { + m_expressionCategory = ExpressionCategory::RValue; + } + + void ShaderAstValueCategory::Visit(CallMethodExpression& /*node*/) + { + m_expressionCategory = ExpressionCategory::RValue; + } + + void ShaderAstValueCategory::Visit(CastExpression& /*node*/) + { + m_expressionCategory = ExpressionCategory::RValue; + } + + void ShaderAstValueCategory::Visit(ConditionalExpression& node) + { + node.truePath->Visit(*this); + ExpressionCategory trueExprCategory = m_expressionCategory; + + node.falsePath->Visit(*this); + ExpressionCategory falseExprCategory = m_expressionCategory; + + if (trueExprCategory == ExpressionCategory::RValue || falseExprCategory == ExpressionCategory::RValue) + m_expressionCategory = ExpressionCategory::RValue; + else + m_expressionCategory = ExpressionCategory::LValue; + } + + void ShaderAstValueCategory::Visit(ConstantExpression& /*node*/) + { + m_expressionCategory = ExpressionCategory::RValue; + } + + void ShaderAstValueCategory::Visit(IdentifierExpression& /*node*/) + { + m_expressionCategory = ExpressionCategory::LValue; + } + + void ShaderAstValueCategory::Visit(IntrinsicExpression& /*node*/) + { + m_expressionCategory = ExpressionCategory::RValue; + } + + void ShaderAstValueCategory::Visit(SelectOptionExpression& node) + { + node.truePath->Visit(*this); + ExpressionCategory trueExprCategory = m_expressionCategory; + + node.falsePath->Visit(*this); + ExpressionCategory falseExprCategory = m_expressionCategory; + + if (trueExprCategory == ExpressionCategory::RValue || falseExprCategory == ExpressionCategory::RValue) + m_expressionCategory = ExpressionCategory::RValue; + else + m_expressionCategory = ExpressionCategory::LValue; + } + + void ShaderAstValueCategory::Visit(SwizzleExpression& node) + { + node.expression->Visit(*this); + } + + void ShaderAstValueCategory::Visit(VariableExpression& /*node*/) + { + m_expressionCategory = ExpressionCategory::LValue; + } + + void ShaderAstValueCategory::Visit(UnaryExpression& /*node*/) + { + m_expressionCategory = ExpressionCategory::RValue; + } +} diff --git a/src/Nazara/Shader/Ast/ConstantValue.cpp b/src/Nazara/Shader/Ast/ConstantValue.cpp new file mode 100644 index 000000000..b9398212b --- /dev/null +++ b/src/Nazara/Shader/Ast/ConstantValue.cpp @@ -0,0 +1,40 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz::ShaderAst +{ + ExpressionType GetExpressionType(const ConstantValue& constant) + { + return std::visit([&](auto&& arg) -> ShaderAst::ExpressionType + { + using T = std::decay_t; + + if constexpr (std::is_same_v) + return PrimitiveType::Boolean; + else if constexpr (std::is_same_v) + return PrimitiveType::Float32; + else if constexpr (std::is_same_v) + return PrimitiveType::Int32; + else if constexpr (std::is_same_v) + return PrimitiveType::UInt32; + else if constexpr (std::is_same_v) + return VectorType{ 2, PrimitiveType::Float32 }; + else if constexpr (std::is_same_v) + return VectorType{ 3, PrimitiveType::Float32 }; + else if constexpr (std::is_same_v) + return VectorType{ 4, PrimitiveType::Float32 }; + else if constexpr (std::is_same_v) + return VectorType{ 2, PrimitiveType::Int32 }; + else if constexpr (std::is_same_v) + return VectorType{ 3, PrimitiveType::Int32 }; + else if constexpr (std::is_same_v) + return VectorType{ 4, PrimitiveType::Int32 }; + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, constant); + } +} diff --git a/src/Nazara/Shader/Ast/Nodes.cpp b/src/Nazara/Shader/Ast/Nodes.cpp new file mode 100644 index 000000000..aed845fc5 --- /dev/null +++ b/src/Nazara/Shader/Ast/Nodes.cpp @@ -0,0 +1,32 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include + +namespace Nz::ShaderAst +{ + Node::~Node() = default; + +#define NAZARA_SHADERAST_NODE(Node) NodeType Node::GetType() const \ + { \ + return NodeType:: Node; \ + } +#include + +#define NAZARA_SHADERAST_EXPRESSION(Node) void Node::Visit(AstExpressionVisitor& visitor) \ + {\ + visitor.Visit(*this); \ + } + +#define NAZARA_SHADERAST_STATEMENT(Node) void Node::Visit(AstStatementVisitor& visitor) \ + {\ + visitor.Visit(*this); \ + } + +#include +} diff --git a/src/Nazara/Shader/Ast/SanitizeVisitor.cpp b/src/Nazara/Shader/Ast/SanitizeVisitor.cpp new file mode 100644 index 000000000..0bc674a19 --- /dev/null +++ b/src/Nazara/Shader/Ast/SanitizeVisitor.cpp @@ -0,0 +1,1416 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz::ShaderAst +{ + namespace + { + struct AstError + { + std::string errMsg; + }; + + template + std::unique_ptr static_unique_pointer_cast(std::unique_ptr&& ptr) + { + return std::unique_ptr(static_cast(ptr.release())); + } + } + + struct SanitizeVisitor::Context + { + struct FunctionData + { + std::optional stageType; + Bitset<> calledFunctions; + DeclareFunctionStatement* statement; + FunctionFlags flags; + }; + + Options options; + std::array entryFunctions = {}; + std::unordered_set declaredExternalVar; + std::unordered_set usedBindingIndexes; + FunctionData* currentFunction = nullptr; + }; + + StatementPtr SanitizeVisitor::Sanitize(const StatementPtr& nodePtr, const Options& options, std::string* error) + { + StatementPtr clone; + + Context currentContext; + currentContext.options = options; + + m_context = ¤tContext; + CallOnExit resetContext([&] { m_context = nullptr; }); + + PushScope(); //< Global scope + { + RegisterIntrinsic("cross", IntrinsicType::CrossProduct); + RegisterIntrinsic("dot", IntrinsicType::DotProduct); + RegisterIntrinsic("length", IntrinsicType::Length); + RegisterIntrinsic("max", IntrinsicType::Max); + RegisterIntrinsic("min", IntrinsicType::Min); + RegisterIntrinsic("pow", IntrinsicType::Pow); + + // Collect function name and their types + if (nodePtr->GetType() == NodeType::MultiStatement) + { + const MultiStatement& multiStatement = static_cast(*nodePtr); + for (auto& statementPtr : multiStatement.statements) + { + if (statementPtr->GetType() == NodeType::DeclareFunctionStatement) + DeclareFunction(static_cast(statementPtr.get())); + } + } + else if (nodePtr->GetType() == NodeType::DeclareFunctionStatement) + DeclareFunction(static_cast(nodePtr.get())); + + try + { + clone = AstCloner::Clone(nodePtr); + } + catch (const AstError& err) + { + if (!error) + throw std::runtime_error(err.errMsg); + + *error = err.errMsg; + } + + ResolveFunctions(); + } + PopScope(); + + return clone; + } + + ExpressionPtr SanitizeVisitor::Clone(AccessIdentifierExpression& node) + { + if (node.identifiers.empty()) + throw AstError{ "AccessIdentifierExpression must have at least one identifier" }; + + ExpressionPtr indexedExpr = CloneExpression(MandatoryExpr(node.expr)); + for (std::size_t i = 0; i < node.identifiers.size(); ++i) + { + const std::string& identifier = node.identifiers[i]; + + const ExpressionType& exprType = GetExpressionType(*indexedExpr); + if (IsStructType(exprType)) + { + // Transform to AccessIndexExpression + AccessIndexExpression* accessIndexPtr; + if (indexedExpr->GetType() != NodeType::AccessIndexExpression) + { + std::unique_ptr accessIndex = std::make_unique(); + accessIndex->expr = std::move(indexedExpr); + + accessIndexPtr = accessIndex.get(); + indexedExpr = std::move(accessIndex); + } + else + accessIndexPtr = static_cast(indexedExpr.get()); + + std::size_t structIndex = ResolveStruct(exprType); + assert(structIndex < m_structs.size()); + const StructDescription& s = m_structs[structIndex]; + + auto it = std::find_if(s.members.begin(), s.members.end(), [&](const auto& field) { return field.name == identifier; }); + if (it == s.members.end()) + throw AstError{ "unknown field " + identifier }; + + accessIndexPtr->indices.push_back(ShaderBuilder::Constant(Int32(std::distance(s.members.begin(), it)))); + accessIndexPtr->cachedExpressionType = ResolveType(it->type); + } + else if (IsVectorType(exprType)) + { + // Swizzle expression + const VectorType& swizzledVec = std::get(exprType); + + auto swizzle = std::make_unique(); + swizzle->expression = std::move(indexedExpr); + + if (node.identifiers.size() - i != 1) + throw AstError{ "invalid swizzle" }; + + const std::string& swizzleStr = node.identifiers[i]; + if (swizzleStr.empty() || swizzleStr.size() > swizzle->components.size()) + throw AstError{ "invalid swizzle" }; + + swizzle->componentCount = swizzleStr.size(); + + if (swizzle->componentCount > 1) + swizzle->cachedExpressionType = VectorType{ swizzle->componentCount, swizzledVec.type }; + else + swizzle->cachedExpressionType = swizzledVec.type; + + for (std::size_t j = 0; j < swizzle->componentCount; ++j) + { + switch (swizzleStr[j]) + { + case 'r': + case 'x': + case 's': + swizzle->components[j] = SwizzleComponent::First; + break; + + case 'g': + case 'y': + case 't': + swizzle->components[j] = SwizzleComponent::Second; + break; + + case 'b': + case 'z': + case 'p': + swizzle->components[j] = SwizzleComponent::Third; + break; + + case 'a': + case 'w': + case 'q': + swizzle->components[j] = SwizzleComponent::Fourth; + break; + } + } + + indexedExpr = std::move(swizzle); + } + else + throw AstError{ "unexpected type (only struct and vectors can be indexed with identifiers)" }; //< TODO: Add support for arrays + } + + return indexedExpr; + } + + ExpressionPtr SanitizeVisitor::Clone(AccessIndexExpression& node) + { + MandatoryExpr(node.expr); + for (auto& index : node.indices) + MandatoryExpr(index); + + auto clone = static_unique_pointer_cast(AstCloner::Clone(node)); + Validate(*clone); + + return clone; + } + + ExpressionPtr SanitizeVisitor::Clone(AssignExpression& node) + { + MandatoryExpr(node.left); + MandatoryExpr(node.right); + + if (GetExpressionCategory(*node.left) != ExpressionCategory::LValue) + throw AstError{ "Assignation is only possible with a l-value" }; + + auto clone = static_unique_pointer_cast(AstCloner::Clone(node)); + + TypeMustMatch(clone->left, clone->right); + clone->cachedExpressionType = GetExpressionType(*clone->right); + + return clone; + } + + ExpressionPtr SanitizeVisitor::Clone(BinaryExpression& node) + { + auto clone = static_unique_pointer_cast(AstCloner::Clone(node)); + + const ExpressionType& leftExprType = GetExpressionType(MandatoryExpr(clone->left)); + if (!IsPrimitiveType(leftExprType) && !IsMatrixType(leftExprType) && !IsVectorType(leftExprType)) + throw AstError{ "left expression type does not support binary operation" }; + + const ExpressionType& rightExprType = GetExpressionType(MandatoryExpr(clone->right)); + if (!IsPrimitiveType(rightExprType) && !IsMatrixType(rightExprType) && !IsVectorType(rightExprType)) + throw AstError{ "right expression type does not support binary operation" }; + + if (IsPrimitiveType(leftExprType)) + { + PrimitiveType leftType = std::get(leftExprType); + switch (clone->op) + { + case BinaryType::CompGe: + case BinaryType::CompGt: + case BinaryType::CompLe: + case BinaryType::CompLt: + if (leftType == PrimitiveType::Boolean) + throw AstError{ "this operation is not supported for booleans" }; + + TypeMustMatch(clone->left, clone->right); + + clone->cachedExpressionType = PrimitiveType::Boolean; + break; + + case BinaryType::Add: + case BinaryType::CompEq: + case BinaryType::CompNe: + case BinaryType::Subtract: + TypeMustMatch(clone->left, clone->right); + + clone->cachedExpressionType = leftExprType; + break; + + case BinaryType::Multiply: + case BinaryType::Divide: + { + switch (leftType) + { + case PrimitiveType::Float32: + case PrimitiveType::Int32: + case PrimitiveType::UInt32: + { + if (IsMatrixType(rightExprType)) + { + TypeMustMatch(leftType, std::get(rightExprType).type); + clone->cachedExpressionType = rightExprType; + } + else if (IsPrimitiveType(rightExprType)) + { + TypeMustMatch(leftType, rightExprType); + clone->cachedExpressionType = leftExprType; + } + else if (IsVectorType(rightExprType)) + { + TypeMustMatch(leftType, std::get(rightExprType).type); + clone->cachedExpressionType = rightExprType; + } + else + throw AstError{ "incompatible types" }; + + break; + } + + case PrimitiveType::Boolean: + throw AstError{ "this operation is not supported for booleans" }; + + default: + throw AstError{ "incompatible types" }; + } + } + } + } + else if (IsMatrixType(leftExprType)) + { + const MatrixType& leftType = std::get(leftExprType); + switch (clone->op) + { + case BinaryType::CompGe: + case BinaryType::CompGt: + case BinaryType::CompLe: + case BinaryType::CompLt: + case BinaryType::CompEq: + case BinaryType::CompNe: + TypeMustMatch(clone->left, clone->right); + clone->cachedExpressionType = PrimitiveType::Boolean; + break; + + case BinaryType::Add: + case BinaryType::Subtract: + TypeMustMatch(clone->left, clone->right); + clone->cachedExpressionType = leftExprType; + break; + + case BinaryType::Multiply: + case BinaryType::Divide: + { + if (IsMatrixType(rightExprType)) + { + TypeMustMatch(leftExprType, rightExprType); + clone->cachedExpressionType = leftExprType; //< FIXME + } + else if (IsPrimitiveType(rightExprType)) + { + TypeMustMatch(leftType.type, rightExprType); + clone->cachedExpressionType = leftExprType; + } + else if (IsVectorType(rightExprType)) + { + const VectorType& rightType = std::get(rightExprType); + TypeMustMatch(leftType.type, rightType.type); + + if (leftType.columnCount != rightType.componentCount) + throw AstError{ "incompatible types" }; + + clone->cachedExpressionType = rightExprType; + } + else + throw AstError{ "incompatible types" }; + } + } + } + else if (IsVectorType(leftExprType)) + { + const VectorType& leftType = std::get(leftExprType); + switch (clone->op) + { + case BinaryType::CompGe: + case BinaryType::CompGt: + case BinaryType::CompLe: + case BinaryType::CompLt: + case BinaryType::CompEq: + case BinaryType::CompNe: + TypeMustMatch(clone->left, clone->right); + clone->cachedExpressionType = PrimitiveType::Boolean; + break; + + case BinaryType::Add: + case BinaryType::Subtract: + TypeMustMatch(clone->left, clone->right); + clone->cachedExpressionType = leftExprType; + break; + + case BinaryType::Multiply: + case BinaryType::Divide: + { + if (IsPrimitiveType(rightExprType)) + { + TypeMustMatch(leftType.type, rightExprType); + clone->cachedExpressionType = leftExprType; + } + else if (IsVectorType(rightExprType)) + { + TypeMustMatch(leftType, rightExprType); + clone->cachedExpressionType = rightExprType; + } + else + throw AstError{ "incompatible types" }; + } + } + } + + return clone; + } + + ExpressionPtr SanitizeVisitor::Clone(CallFunctionExpression& node) + { + if (!m_context->currentFunction) + throw AstError{ "function calls must happen inside a function" }; + + auto clone = std::make_unique(); + + clone->parameters.reserve(node.parameters.size()); + for (std::size_t i = 0; i < node.parameters.size(); ++i) + clone->parameters.push_back(CloneExpression(node.parameters[i])); + + std::size_t targetFuncIndex; + if (std::holds_alternative(node.targetFunction)) + { + const std::string& functionName = std::get(node.targetFunction); + + const Identifier* identifier = FindIdentifier(functionName); + if (identifier) + { + if (identifier->type == Identifier::Type::Intrinsic) + { + // Intrinsic function call + std::vector parameters; + parameters.reserve(node.parameters.size()); + + for (const auto& param : node.parameters) + parameters.push_back(CloneExpression(param)); + + auto intrinsic = ShaderBuilder::Intrinsic(m_intrinsics[identifier->index], std::move(parameters)); + Validate(*intrinsic); + + return intrinsic; + } + else + { + // Regular function call + if (identifier->type != Identifier::Type::Function) + throw AstError{ "function expected" }; + + clone->targetFunction = identifier->index; + targetFuncIndex = identifier->index; + } + } + else + { + // Identifier not found, maybe the function is declared later + auto it = std::find_if(m_functions.begin(), m_functions.end(), [&](const auto& funcData) { return funcData.node->name == functionName; }); + if (it == m_functions.end()) + throw AstError{ "function " + functionName + " does not exist" }; + + targetFuncIndex = std::distance(m_functions.begin(), it); + + clone->targetFunction = targetFuncIndex; + } + } + else + targetFuncIndex = std::get(node.targetFunction); + + m_context->currentFunction->calledFunctions.UnboundedSet(targetFuncIndex); + + Validate(*clone, m_functions[targetFuncIndex].node); + + return clone; + } + + ExpressionPtr SanitizeVisitor::Clone(CastExpression& node) + { + auto clone = static_unique_pointer_cast(AstCloner::Clone(node)); + + clone->cachedExpressionType = clone->targetType; + clone->targetType = ResolveType(clone->targetType); + + //FIXME: Make proper rules + if (IsMatrixType(clone->targetType) && clone->expressions.front()) + { + const ExpressionType& exprType = GetExpressionType(*clone->expressions.front()); + if (IsMatrixType(exprType) && !clone->expressions[1]) + { + return clone; + } + } + + auto GetComponentCount = [](const ExpressionType& exprType) -> std::size_t + { + if (IsVectorType(exprType)) + return std::get(exprType).componentCount; + else + { + assert(IsPrimitiveType(exprType)); + return 1; + } + }; + + std::size_t componentCount = 0; + std::size_t requiredComponents = GetComponentCount(clone->targetType); + + for (auto& exprPtr : clone->expressions) + { + if (!exprPtr) + break; + + const ExpressionType& exprType = GetExpressionType(*exprPtr); + if (!IsPrimitiveType(exprType) && !IsVectorType(exprType)) + throw AstError{ "incompatible type" }; + + componentCount += GetComponentCount(exprType); + } + + if (componentCount != requiredComponents) + throw AstError{ "component count doesn't match required component count" }; + + return clone; + } + + ExpressionPtr SanitizeVisitor::Clone(ConditionalExpression& node) + { + MandatoryExpr(node.truePath); + MandatoryExpr(node.falsePath); + + auto clone = static_unique_pointer_cast(AstCloner::Clone(node)); + + const ExpressionType& leftExprType = GetExpressionType(*clone->truePath); + if (leftExprType != GetExpressionType(*clone->falsePath)) + throw AstError{ "true path type must match false path type" }; + + clone->cachedExpressionType = leftExprType; + + return clone; + } + + ExpressionPtr SanitizeVisitor::Clone(ConstantExpression& node) + { + auto clone = static_unique_pointer_cast(AstCloner::Clone(node)); + clone->cachedExpressionType = GetExpressionType(clone->value); + + return clone; + } + + ExpressionPtr SanitizeVisitor::Clone(IdentifierExpression& node) + { + assert(m_context); + + const Identifier* identifier = FindIdentifier(node.identifier); + if (!identifier) + throw AstError{ "unknown identifier " + node.identifier }; + + if (identifier->type != Identifier::Type::Variable) + throw AstError{ "expected variable identifier" }; + + // Replace IdentifierExpression by VariableExpression + auto varExpr = std::make_unique(); + varExpr->cachedExpressionType = m_variableTypes[identifier->index]; + varExpr->variableId = identifier->index; + + return varExpr; + } + + ExpressionPtr SanitizeVisitor::Clone(IntrinsicExpression& node) + { + auto clone = static_unique_pointer_cast(AstCloner::Clone(node)); + Validate(*clone); + + return clone; + } + + ExpressionPtr SanitizeVisitor::Clone(SelectOptionExpression& node) + { + MandatoryExpr(node.truePath); + MandatoryExpr(node.falsePath); + + auto condExpr = std::make_unique(); + condExpr->truePath = CloneExpression(node.truePath); + condExpr->falsePath = CloneExpression(node.falsePath); + + const Identifier* identifier = FindIdentifier(node.optionName); + if (!identifier) + throw AstError{ "unknown option " + node.optionName }; + + if (identifier->type != Identifier::Type::Option) + throw AstError{ "expected option identifier" }; + + condExpr->optionIndex = identifier->index; + + const ExpressionType& leftExprType = GetExpressionType(*condExpr->truePath); + if (leftExprType != GetExpressionType(*condExpr->falsePath)) + throw AstError{ "true path type must match false path type" }; + + condExpr->cachedExpressionType = leftExprType; + + return condExpr; + } + + ExpressionPtr SanitizeVisitor::Clone(SwizzleExpression& node) + { + if (node.componentCount > 4) + throw AstError{ "Cannot swizzle more than four elements" }; + + MandatoryExpr(node.expression); + + auto clone = static_unique_pointer_cast(AstCloner::Clone(node)); + + const ExpressionType& exprType = GetExpressionType(*clone->expression); + if (!IsPrimitiveType(exprType) && !IsVectorType(exprType)) + throw AstError{ "Cannot swizzle this type" }; + + PrimitiveType baseType; + if (IsPrimitiveType(exprType)) + baseType = std::get(exprType); + else + baseType = std::get(exprType).type; + + if (clone->componentCount > 1) + { + clone->cachedExpressionType = VectorType{ + clone->componentCount, + baseType + }; + } + else + clone->cachedExpressionType = baseType; + + return clone; + } + + ExpressionPtr SanitizeVisitor::Clone(UnaryExpression& node) + { + auto clone = static_unique_pointer_cast(AstCloner::Clone(node)); + + const ExpressionType& exprType = GetExpressionType(MandatoryExpr(clone->expression)); + + switch (node.op) + { + case UnaryType::LogicalNot: + { + if (exprType != ExpressionType(PrimitiveType::Boolean)) + throw AstError{ "logical not is only supported on booleans" }; + + break; + } + + case UnaryType::Minus: + case UnaryType::Plus: + { + ShaderAst::PrimitiveType basicType; + if (IsPrimitiveType(exprType)) + basicType = std::get(exprType); + else if (IsVectorType(exprType)) + basicType = std::get(exprType).type; + else + throw AstError{ "plus and minus unary expressions are only supported on primitive/vectors types" }; + + if (basicType != PrimitiveType::Float32 && basicType != PrimitiveType::Int32 && basicType != PrimitiveType::UInt32) + throw AstError{ "plus and minus unary expressions are only supported on floating points and integers types" }; + + break; + } + } + + clone->cachedExpressionType = exprType; + + return clone; + } + + StatementPtr SanitizeVisitor::Clone(BranchStatement& node) + { + auto clone = std::make_unique(); + clone->condStatements.reserve(node.condStatements.size()); + + for (auto& cond : node.condStatements) + { + PushScope(); + + auto& condStatement = clone->condStatements.emplace_back(); + condStatement.condition = CloneExpression(MandatoryExpr(cond.condition)); + + const ExpressionType& condType = GetExpressionType(*condStatement.condition); + if (!IsPrimitiveType(condType) || std::get(condType) != PrimitiveType::Boolean) + throw AstError{ "branch expressions must resolve to boolean type" }; + + condStatement.statement = CloneStatement(MandatoryStatement(cond.statement)); + + PopScope(); + } + + if (node.elseStatement) + { + PushScope(); + clone->elseStatement = CloneStatement(node.elseStatement); + PopScope(); + } + + return clone; + } + + StatementPtr SanitizeVisitor::Clone(ConditionalStatement& node) + { + MandatoryStatement(node.statement); + + PushScope(); + + auto clone = static_unique_pointer_cast(AstCloner::Clone(node)); + + PopScope(); + + return clone; + } + + StatementPtr SanitizeVisitor::Clone(DeclareExternalStatement& node) + { + assert(m_context); + + for (const auto& extVar : node.externalVars) + { + if (extVar.bindingIndex) + { + unsigned int bindingIndex = extVar.bindingIndex.value(); + if (m_context->usedBindingIndexes.find(bindingIndex) != m_context->usedBindingIndexes.end()) + throw AstError{ "Binding #" + std::to_string(bindingIndex) + " is already in use" }; + + m_context->usedBindingIndexes.insert(bindingIndex); + } + + if (m_context->declaredExternalVar.find(extVar.name) != m_context->declaredExternalVar.end()) + throw AstError{ "External variable " + extVar.name + " is already declared" }; + + m_context->declaredExternalVar.insert(extVar.name); + } + + auto clone = static_unique_pointer_cast(AstCloner::Clone(node)); + for (auto& extVar : clone->externalVars) + { + SanitizeIdentifier(extVar.name); + + extVar.type = ResolveType(extVar.type); + + ExpressionType varType; + if (IsUniformType(extVar.type)) + varType = std::get(std::get(extVar.type).containedType); + else if (IsSamplerType(extVar.type)) + varType = extVar.type; + else + throw AstError{ "External variable " + extVar.name + " is of wrong type: only uniform and sampler are allowed in external blocks" }; + + std::size_t varIndex = RegisterVariable(extVar.name, std::move(varType)); + if (!clone->varIndex) + clone->varIndex = varIndex; //< First external variable index is node variable index + } + + return clone; + } + + StatementPtr SanitizeVisitor::Clone(DeclareFunctionStatement& node) + { + if (node.entryStage) + { + ShaderStageType stageType = *node.entryStage; + + if (m_context->entryFunctions[UnderlyingCast(stageType)]) + throw AstError{ "the same entry type has been defined multiple times" }; + + m_context->entryFunctions[UnderlyingCast(stageType)] = &node; + + if (node.parameters.size() > 1) + throw AstError{ "entry functions can either take one struct parameter or no parameter" }; + + if (stageType != ShaderStageType::Fragment) + { + if (node.depthWrite.has_value()) + throw AstError{ "only fragment entry-points can have the depth_write attribute" }; + + if (node.earlyFragmentTests.has_value()) + throw AstError{ "only functions with entry(frag) attribute can have the early_fragments_tests attribute" }; + } + } + + auto clone = std::make_unique(); + clone->depthWrite = node.depthWrite; + clone->earlyFragmentTests = node.earlyFragmentTests; + clone->entryStage = node.entryStage; + clone->name = node.name; + clone->optionName = node.optionName; + clone->parameters = node.parameters; + clone->returnType = ResolveType(node.returnType); + + SanitizeIdentifier(clone->name); + + Context::FunctionData tempFuncData; + tempFuncData.stageType = node.entryStage; + + m_context->currentFunction = &tempFuncData; + + PushScope(); + { + for (auto& parameter : clone->parameters) + { + parameter.type = ResolveType(parameter.type); + std::size_t varIndex = RegisterVariable(parameter.name, parameter.type); + if (!clone->varIndex) + clone->varIndex = varIndex; //< First parameter variable index is node variable index + + SanitizeIdentifier(parameter.name); + } + + clone->statements.reserve(node.statements.size()); + for (auto& statement : node.statements) + clone->statements.push_back(CloneStatement(MandatoryStatement(statement))); + } + PopScope(); + + m_context->currentFunction = nullptr; + + if (clone->earlyFragmentTests.has_value() && *clone->earlyFragmentTests) + { + //TODO: warning and disable early fragment tests + throw AstError{ "discard is not compatible with early fragment tests" }; + } + + if (!clone->optionName.empty()) + { + const Identifier* identifier = FindIdentifier(node.optionName); + if (!identifier) + throw AstError{ "unknown option " + node.optionName }; + + if (identifier->type != Identifier::Type::Option) + throw AstError{ "expected option identifier" }; + + std::size_t optionIndex = identifier->index; + + return ShaderBuilder::ConditionalStatement(optionIndex, std::move(clone)); + } + + auto it = std::find_if(m_functions.begin(), m_functions.end(), [&](const auto& funcData) { return funcData.node == &node; }); + assert(it != m_functions.end()); + assert(!it->defined); + + std::size_t funcIndex = std::distance(m_functions.begin(), it); + + clone->funcIndex = funcIndex; + + auto& funcData = RegisterFunction(funcIndex); + funcData.flags = tempFuncData.flags; + + for (std::size_t i = tempFuncData.calledFunctions.FindFirst(); i != tempFuncData.calledFunctions.npos; i = tempFuncData.calledFunctions.FindNext(i)) + { + assert(i < m_functions.size()); + auto& targetFunc = m_functions[i]; + targetFunc.calledByFunctions.UnboundedSet(funcIndex); + } + + return clone; + } + + StatementPtr SanitizeVisitor::Clone(DeclareOptionStatement& node) + { + auto clone = static_unique_pointer_cast(AstCloner::Clone(node)); + clone->optType = ResolveType(clone->optType); + + if (clone->initialValue && clone->optType != GetExpressionType(*clone->initialValue)) + throw AstError{ "option " + clone->optName + " initial expression must be of the same type than the option" }; + + clone->optIndex = RegisterOption(clone->optName, clone->optType); + + if (m_context->options.removeOptionDeclaration) + return ShaderBuilder::NoOp(); + + return clone; + } + + StatementPtr SanitizeVisitor::Clone(DeclareStructStatement& node) + { + std::unordered_set declaredMembers; + + for (auto& member : node.description.members) + { + if (declaredMembers.find(member.name) != declaredMembers.end()) + throw AstError{ "struct member " + member.name + " found multiple time" }; + + declaredMembers.insert(member.name); + } + + auto clone = static_unique_pointer_cast(AstCloner::Clone(node)); + + for (auto& member : clone->description.members) + member.type = ResolveType(member.type); + + clone->structIndex = RegisterStruct(clone->description.name, clone->description); + + SanitizeIdentifier(clone->description.name); + + return clone; + } + + StatementPtr SanitizeVisitor::Clone(DeclareVariableStatement& node) + { + auto clone = static_unique_pointer_cast(AstCloner::Clone(node)); + if (IsNoType(clone->varType)) + { + if (!clone->initialExpression) + throw AstError{ "variable must either have a type or an initial value" }; + + clone->varType = ResolveType(GetExpressionType(*clone->initialExpression)); + } + else + clone->varType = ResolveType(clone->varType); + + clone->varIndex = RegisterVariable(clone->varName, clone->varType); + + SanitizeIdentifier(clone->varName); + + return clone; + } + + StatementPtr SanitizeVisitor::Clone(DiscardStatement& node) + { + if (!m_context->currentFunction) + throw AstError{ "discard can only be used inside a function" }; + + m_context->currentFunction->flags |= FunctionFlag::DoesDiscard; + + return AstCloner::Clone(node); + } + + StatementPtr SanitizeVisitor::Clone(ExpressionStatement& node) + { + MandatoryExpr(node.expression); + + return AstCloner::Clone(node); + } + + StatementPtr SanitizeVisitor::Clone(MultiStatement& node) + { + for (auto& statement : node.statements) + MandatoryStatement(statement); + + PushScope(); + + auto clone = static_unique_pointer_cast(AstCloner::Clone(node)); + + PopScope(); + + return clone; + } + + Expression& SanitizeVisitor::MandatoryExpr(ExpressionPtr& node) + { + if (!node) + throw AstError{ "Invalid expression" }; + + return *node; + } + + Statement& SanitizeVisitor::MandatoryStatement(StatementPtr& node) + { + if (!node) + throw AstError{ "Invalid statement" }; + + return *node; + } + + void SanitizeVisitor::PushScope() + { + m_scopeSizes.push_back(m_identifiersInScope.size()); + } + + void SanitizeVisitor::PopScope() + { + assert(!m_scopeSizes.empty()); + m_identifiersInScope.resize(m_scopeSizes.back()); + m_scopeSizes.pop_back(); + } + + std::size_t SanitizeVisitor::DeclareFunction(DeclareFunctionStatement* funcDecl) + { + std::size_t functionIndex = m_functions.size(); + auto& funcData = m_functions.emplace_back(); + funcData.node = funcDecl; + + return functionIndex; + } + + void SanitizeVisitor::PropagateFunctionFlags(std::size_t funcIndex, FunctionFlags flags, Bitset<>& seen) + { + assert(funcIndex < m_functions.size()); + auto& funcData = m_functions[funcIndex]; + assert(funcData.defined); + + funcData.flags |= flags; + + for (std::size_t i = funcData.calledByFunctions.FindFirst(); i != funcData.calledByFunctions.npos; i = funcData.calledByFunctions.FindNext(i)) + PropagateFunctionFlags(i, funcData.flags, seen); + } + + auto SanitizeVisitor::RegisterFunction(std::size_t functionIndex) -> FunctionData& + { + assert(m_functions.size() >= functionIndex); + auto& funcData = m_functions[functionIndex]; + assert(!funcData.defined); + funcData.defined = true; + + if (auto* identifier = FindIdentifier(funcData.node->name)) + { + bool duplicate = true; + + // Functions cannot be declared twice, except for entry ones if their stages are different + if (funcData.node->entryStage && identifier->type == Identifier::Type::Function) + { + auto& otherFunction = m_functions[identifier->index]; + if (funcData.node->entryStage != otherFunction.node->entryStage) + duplicate = false; + } + + if (duplicate) + throw AstError{ funcData.node->name + " is already used" }; + } + + m_identifiersInScope.push_back({ + funcData.node->name, + functionIndex, + Identifier::Type::Function + }); + + return funcData; + } + + std::size_t SanitizeVisitor::RegisterIntrinsic(std::string name, IntrinsicType type) + { + if (FindIdentifier(name)) + throw AstError{ name + " is already used" }; + + std::size_t intrinsicIndex = m_intrinsics.size(); + m_intrinsics.push_back(type); + + m_identifiersInScope.push_back({ + std::move(name), + intrinsicIndex, + Identifier::Type::Intrinsic + }); + + return intrinsicIndex; + } + + std::size_t SanitizeVisitor::RegisterOption(std::string name, ExpressionType type) + { + if (FindIdentifier(name)) + throw AstError{ name + " is already used" }; + + std::size_t optionIndex = m_options.size(); + m_options.emplace_back(std::move(type)); + + m_identifiersInScope.push_back({ + std::move(name), + optionIndex, + Identifier::Type::Option + }); + + return optionIndex; + } + + std::size_t SanitizeVisitor::RegisterStruct(std::string name, StructDescription description) + { + if (FindIdentifier(name)) + throw AstError{ name + " is already used" }; + + std::size_t structIndex = m_structs.size(); + m_structs.emplace_back(std::move(description)); + + m_identifiersInScope.push_back({ + std::move(name), + structIndex, + Identifier::Type::Struct + }); + + return structIndex; + } + + std::size_t SanitizeVisitor::RegisterVariable(std::string name, ExpressionType type) + { + // Allow variable shadowing + if (auto* identifier = FindIdentifier(name); identifier && identifier->type != Identifier::Type::Variable) + throw AstError{ name + " is already used" }; + + std::size_t varIndex = m_variableTypes.size(); + m_variableTypes.emplace_back(std::move(type)); + + m_identifiersInScope.push_back({ + std::move(name), + varIndex, + Identifier::Type::Variable + }); + + return varIndex; + } + + void SanitizeVisitor::ResolveFunctions() + { + // Once every function is known, we can propagate flags + + Bitset<> seen; + for (std::size_t funcIndex = 0; funcIndex < m_functions.size(); ++funcIndex) + { + auto& funcData = m_functions[funcIndex]; + + PropagateFunctionFlags(funcIndex, funcData.flags, seen); + seen.Clear(); + } + + for (const FunctionData& funcData : m_functions) + { + if (funcData.flags.Test(ShaderAst::FunctionFlag::DoesDiscard) && funcData.node->entryStage && *funcData.node->entryStage != ShaderStageType::Fragment) + throw AstError{ "discard can only be used in the fragment stage" }; + } + } + + std::size_t SanitizeVisitor::ResolveStruct(const ExpressionType& exprType) + { + return std::visit([&](auto&& arg) -> std::size_t + { + using T = std::decay_t; + + if constexpr (std::is_same_v || std::is_same_v || std::is_same_v) + return ResolveStruct(arg); + else if constexpr (std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v) + { + throw AstError{ "expression is not a structure" }; + } + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, exprType); + } + + std::size_t SanitizeVisitor::ResolveStruct(const IdentifierType& identifierType) + { + const Identifier* identifier = FindIdentifier(identifierType.name); + if (!identifier) + throw AstError{ "unknown identifier " + identifierType.name }; + + if (identifier->type != Identifier::Type::Struct) + throw AstError{ identifierType.name + " is not a struct" }; + + return identifier->index; + } + + std::size_t SanitizeVisitor::ResolveStruct(const StructType& structType) + { + return structType.structIndex; + } + + std::size_t SanitizeVisitor::ResolveStruct(const UniformType& uniformType) + { + return std::visit([&](auto&& arg) -> std::size_t + { + using T = std::decay_t; + + if constexpr (std::is_same_v || std::is_same_v) + return ResolveStruct(arg); + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, uniformType.containedType); + } + + ExpressionType SanitizeVisitor::ResolveType(const ExpressionType& exprType) + { + return std::visit([&](auto&& arg) -> ExpressionType + { + using T = std::decay_t; + + if constexpr (std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v) + { + return exprType; + } + else if constexpr (std::is_same_v) + { + const Identifier* identifier = FindIdentifier(arg.name); + if (!identifier) + throw AstError{ "unknown identifier " + arg.name }; + + if (identifier->type != Identifier::Type::Struct) + throw AstError{ "expected type identifier" }; + + return StructType{ identifier->index }; + } + else if constexpr (std::is_same_v) + { + return std::visit([&](auto&& containedArg) + { + ExpressionType resolvedType = ResolveType(containedArg); + assert(std::holds_alternative(resolvedType)); + + return UniformType{ std::get(resolvedType) }; + }, arg.containedType); + } + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, exprType); + } + + void SanitizeVisitor::SanitizeIdentifier(std::string& identifier) + { + // Append _ until the identifier is no longer found + while (m_context->options.reservedIdentifiers.find(identifier) != m_context->options.reservedIdentifiers.end()) + { + do + { + identifier += "_"; + } + while (FindIdentifier(identifier) != nullptr); + } + } + + void SanitizeVisitor::Validate(AccessIndexExpression& node) + { + if (node.indices.empty()) + throw AstError{ "AccessIndexExpression must have at least one index" }; + + for (auto& index : node.indices) + { + const ShaderAst::ExpressionType& indexType = GetExpressionType(*index); + if (!IsPrimitiveType(indexType) || std::get(indexType) != PrimitiveType::Int32) + throw AstError{ "AccessIndex expects Int32 indices" }; + } + + ExpressionType exprType = GetExpressionType(*node.expr); + for (std::size_t i = 0; i < node.indices.size(); ++i) + { + if (IsStructType(exprType)) + { + auto& indexExpr = node.indices[i]; + + const ShaderAst::ExpressionType& indexType = GetExpressionType(*indexExpr); + if (indexExpr->GetType() != NodeType::ConstantExpression) + throw AstError{ "struct can only be accessed with constant indices" }; + + ConstantExpression& constantExpr = static_cast(*indexExpr); + + Int32 index = std::get(constantExpr.value); + + std::size_t structIndex = ResolveStruct(exprType); + assert(structIndex < m_structs.size()); + const StructDescription& s = m_structs[structIndex]; + + exprType = ResolveType(s.members[index].type); + } + else if (IsMatrixType(exprType)) + { + // Matrix index (ex: mat[2]) + const MatrixType& matrixType = std::get(exprType); + + //TODO: Handle row-major matrices + exprType = VectorType{ matrixType.rowCount, matrixType.type }; + } + else if (IsVectorType(exprType)) + { + // Swizzle expression with one component (ex: vec[2]) + const VectorType& swizzledVec = std::get(exprType); + + exprType = swizzledVec.type; + } + else + throw AstError{ "unexpected type (only struct, vectors and matrices can be indexed)" }; //< TODO: Add support for arrays + } + + node.cachedExpressionType = std::move(exprType); + } + + void SanitizeVisitor::Validate(CallFunctionExpression& node, const DeclareFunctionStatement* referenceDeclaration) + { + if (referenceDeclaration->entryStage) + throw AstError{ referenceDeclaration->name + " is an entry function which cannot be called by the program" }; + + for (std::size_t i = 0; i < node.parameters.size(); ++i) + { + if (GetExpressionType(*node.parameters[i]) != referenceDeclaration->parameters[i].type) + throw AstError{ "function " + referenceDeclaration->name + " parameter " + std::to_string(i) + " type mismatch" }; + } + + if (node.parameters.size() != referenceDeclaration->parameters.size()) + throw AstError{ "function " + referenceDeclaration->name + " expected " + std::to_string(referenceDeclaration->parameters.size()) + " parameters, got " + std::to_string(node.parameters.size()) }; + + node.cachedExpressionType = referenceDeclaration->returnType; + } + + void SanitizeVisitor::Validate(IntrinsicExpression& node) + { + // Parameter validation + switch (node.intrinsic) + { + case IntrinsicType::CrossProduct: + case IntrinsicType::DotProduct: + case IntrinsicType::Max: + case IntrinsicType::Min: + case IntrinsicType::Pow: + { + if (node.parameters.size() != 2) + throw AstError { "Expected two parameters" }; + + for (auto& param : node.parameters) + MandatoryExpr(param); + + const ExpressionType& type = GetExpressionType(*node.parameters.front()); + + for (std::size_t i = 1; i < node.parameters.size(); ++i) + { + if (type != GetExpressionType(*node.parameters[i])) + throw AstError{ "All type must match" }; + } + + break; + } + + case IntrinsicType::Length: + { + if (node.parameters.size() != 1) + throw AstError{ "Expected only one parameters" }; + + for (auto& param : node.parameters) + MandatoryExpr(param); + + const ExpressionType& type = GetExpressionType(*node.parameters.front()); + if (!IsVectorType(type)) + throw AstError{ "Expected a vector" }; + + break; + } + + case IntrinsicType::SampleTexture: + { + if (node.parameters.size() != 2) + throw AstError{ "Expected two parameters" }; + + for (auto& param : node.parameters) + MandatoryExpr(param); + + if (!IsSamplerType(GetExpressionType(*node.parameters[0]))) + throw AstError{ "First parameter must be a sampler" }; + + if (!IsVectorType(GetExpressionType(*node.parameters[1]))) + throw AstError{ "Second parameter must be a vector" }; + + break; + } + } + + // Return type attribution + switch (node.intrinsic) + { + case IntrinsicType::CrossProduct: + { + const ExpressionType& type = GetExpressionType(*node.parameters.front()); + if (type != ExpressionType{ VectorType{ 3, PrimitiveType::Float32 } }) + throw AstError{ "CrossProduct only works with vec3 expressions" }; + + node.cachedExpressionType = type; + break; + } + + case IntrinsicType::DotProduct: + case IntrinsicType::Length: + { + ExpressionType type = GetExpressionType(*node.parameters.front()); + if (!IsVectorType(type)) + throw AstError{ "DotProduct expects vector types" }; + + node.cachedExpressionType = std::get(type).type; + break; + } + + case IntrinsicType::Max: + case IntrinsicType::Min: + { + const ExpressionType& type = GetExpressionType(*node.parameters.front()); + if (!IsPrimitiveType(type) && !IsVectorType(type)) + throw AstError{ "max and min only work with primitive and vector types" }; + + if ((IsPrimitiveType(type) && std::get(type) == PrimitiveType::Boolean) || + (IsVectorType(type) && std::get(type).type == PrimitiveType::Boolean)) + throw AstError{ "max and min do not work with booleans" }; + + node.cachedExpressionType = type; + break; + } + + case IntrinsicType::Pow: + { + const ExpressionType& type = GetExpressionType(*node.parameters.front()); + if (!IsPrimitiveType(type) && !IsVectorType(type)) + throw AstError{ "pow only works with primitive and vector types" }; + + if ((IsPrimitiveType(type) && std::get(type) != PrimitiveType::Float32) || + (IsVectorType(type) && std::get(type).type != PrimitiveType::Float32)) + throw AstError{ "pow only works with floating-point primitive or vectors" }; + + node.cachedExpressionType = type; + break; + } + + case IntrinsicType::SampleTexture: + { + node.cachedExpressionType = VectorType{ 4, std::get(GetExpressionType(*node.parameters.front())).sampledType }; + break; + } + } + } + + void SanitizeVisitor::TypeMustMatch(ExpressionPtr& left, ExpressionPtr& right) + { + return TypeMustMatch(GetExpressionType(*left), GetExpressionType(*right)); + } + + void SanitizeVisitor::TypeMustMatch(const ExpressionType& left, const ExpressionType& right) + { + if (left != right) + throw AstError{ "Left expression type must match right expression type" }; + } +} diff --git a/src/Nazara/Shader/GlslWriter.cpp b/src/Nazara/Shader/GlslWriter.cpp index ccea40fe7..9312cc55e 100644 --- a/src/Nazara/Shader/GlslWriter.cpp +++ b/src/Nazara/Shader/GlslWriter.cpp @@ -4,10 +4,16 @@ #include #include +#include #include +#include #include -#include -#include +#include +#include +#include +#include +#include +#include #include #include @@ -15,54 +21,362 @@ namespace Nz { namespace { - struct AstAdapter : ShaderAstCloner + static const char* s_flipYUniformName = "_NzFlipYValue"; + static const char* s_inputPrefix = "_NzIn_"; + static const char* s_outputPrefix = "_NzOut_"; + static const char* s_outputVarName = "_nzOutput"; + + template const T& Retrieve(const std::unordered_map& map, std::size_t id) { - void Visit(ShaderNodes::AssignOp& node) override + auto it = map.find(id); + assert(it != map.end()); + return it->second; + } + + struct PreVisitor : ShaderAst::AstRecursiveVisitor + { + using AstRecursiveVisitor::Visit; + + void Visit(ShaderAst::CallFunctionExpression& node) override { - if (!flipYPosition) - return ShaderAstCloner::Visit(node); + AstRecursiveVisitor::Visit(node); - if (node.left->GetType() != ShaderNodes::NodeType::Identifier) - return ShaderAstCloner::Visit(node); - - const auto& identifier = static_cast(*node.left); - if (identifier.var->GetType() != ShaderNodes::VariableType::BuiltinVariable) - return ShaderAstCloner::Visit(node); - - const auto& builtinVar = static_cast(*identifier.var); - if (builtinVar.entry != ShaderNodes::BuiltinEntry::VertexPosition) - return ShaderAstCloner::Visit(node); - - auto fixYConstant = ShaderBuilder::Constant(Nz::Vector4f(1.f, -1.f, 1.f, 1.f)); - auto mulFix = ShaderBuilder::Multiply(CloneExpression(node.right), fixYConstant); - - PushExpression(ShaderNodes::AssignOp::Build(node.op, CloneExpression(node.left), mulFix)); + assert(currentFunction); + currentFunction->calledFunctions.UnboundedSet(std::get(node.targetFunction)); } - bool flipYPosition = false; + void Visit(ShaderAst::ConditionalStatement& node) override + { + if (TestBit(enabledOptions, node.optionIndex)) + node.statement->Visit(*this); + } + + void Visit(ShaderAst::DeclareFunctionStatement& node) override + { + // Dismiss function if it's an entry point of another type than the one selected + if (node.entryStage) + { + if (selectedStage) + { + ShaderStageType stage = *node.entryStage; + if (stage != *selectedStage) + return; + + assert(!entryPoint); + entryPoint = &node; + } + else + { + if (entryPoint) + throw std::runtime_error("multiple entry point functions found, this is not allowed in GLSL, please select one"); + + entryPoint = &node; + } + } + + assert(node.funcIndex); + assert(functions.find(node.funcIndex.value()) == functions.end()); + FunctionData& funcData = functions[node.funcIndex.value()]; + funcData.name = node.name; + funcData.node = &node; + + currentFunction = &funcData; + + AstRecursiveVisitor::Visit(node); + + currentFunction = nullptr; + } + + struct FunctionData + { + std::string name; + Bitset<> calledFunctions; + ShaderAst::DeclareFunctionStatement* node; + }; + + FunctionData* currentFunction = nullptr; + + std::optional selectedStage; + std::unordered_map functions; + ShaderAst::DeclareFunctionStatement* entryPoint = nullptr; + UInt64 enabledOptions = 0; + }; + + struct Builtin + { + std::string identifier; + ShaderStageTypeFlags stageFlags; + }; + + std::unordered_map s_builtinMapping = { + { ShaderAst::BuiltinEntry::FragCoord, { "gl_FragCoord", ShaderStageType::Fragment } }, + { ShaderAst::BuiltinEntry::FragDepth, { "gl_FragDepth", ShaderStageType::Fragment } }, + { ShaderAst::BuiltinEntry::VertexPosition, { "gl_Position", ShaderStageType::Vertex } } }; } - GlslWriter::GlslWriter() : - m_currentState(nullptr) + + struct GlslWriter::State { - } + struct InOutField + { + std::string memberName; + std::string targetName; + }; - std::string GlslWriter::Generate(const ShaderAst& shader) + std::optional stage; + std::stringstream stream; + std::unordered_map structs; + std::unordered_map variableNames; + std::vector inputFields; + std::vector outputFields; + Bitset<> declaredFunctions; + PreVisitor previsitor; + const States* states = nullptr; + UInt64 enabledOptions = 0; + bool isInEntryPoint = false; + unsigned int indentLevel = 0; + }; + + std::string GlslWriter::Generate(std::optional shaderStage, ShaderAst::StatementPtr& shader, const States& states) { - std::string error; - if (!ValidateShader(shader, &error)) - throw std::runtime_error("Invalid shader AST: " + error); - - m_context.shader = &shader; - State state; + state.enabledOptions = states.enabledOptions; + state.stage = shaderStage; + m_currentState = &state; CallOnExit onExit([this]() { m_currentState = nullptr; }); + // Always sanitize for reserved identifiers + ShaderAst::SanitizeVisitor::Options options; + options.reservedIdentifiers = { + // All reserved GLSL keywords as of GLSL ES 3.2 + "active", "asm", "atomic_uint", "attribute", "bool", "break", "buffer", "bvec2", "bvec3", "bvec4", "case", "cast", "centroid", "class", "coherent", "common", "const", "continue", "default", "discard", "dmat2", "dmat2x2", "dmat2x3", "dmat2x4", "dmat3", "dmat3x2", "dmat3x3", "dmat3x4", "dmat4", "dmat4x2", "dmat4x3", "dmat4x4", "do", "double", "dvec2", "dvec3", "dvec4", "else", "enum", "extern", "external", "false", "filter", "fixed", "flat", "float", "for", "fvec2", "fvec3", "fvec4", "goto", "half", "highp", "hvec2", "hvec3", "hvec4", "if", "iimage1D", "iimage1DArray", "iimage2D", "iimage2DArray", "iimage2DMS", "iimage2DMSArray", "iimage2DRect", "iimage3D", "iimageBuffer", "iimageCube", "iimageCubeArray", "image1D", "image1DArray", "image2D", "image2DArray", "image2DMS", "image2DMSArray", "image2DRect", "image3D", "imageBuffer", "imageCube", "imageCubeArray", "in", "inline", "inout", "input", "int", "interface", "invariant", "isampler1D", "isampler1DArray", "isampler2D", "isampler2DArray", "isampler2DMS", "isampler2DMSArray", "isampler2DRect", "isampler3D", "isamplerBuffer", "isamplerCube", "isamplerCubeArray", "isubpassInput", "isubpassInputMS", "itexture2D", "itexture2DArray", "itexture2DMS", "itexture2DMSArray", "itexture3D", "itextureBuffer", "itextureCube", "itextureCubeArray", "ivec2", "ivec3", "ivec4", "layout", "long", "lowp", "mat2", "mat2x2", "mat2x3", "mat2x4", "mat3", "mat3x2", "mat3x3", "mat3x4", "mat4", "mat4x2", "mat4x3", "mat4x4", "mediump", "namespace", "noinline", "noperspective", "out", "output", "partition", "patch", "precise", "precision", "public", "readonly", "resource", "restrict", "return", "sample", "sampler", "sampler1D", "sampler1DArray", "sampler1DArrayShadow", "sampler1DShadow", "sampler2D", "sampler2DArray", "sampler2DArrayShadow", "sampler2DMS", "sampler2DMSArray", "sampler2DRect", "sampler2DRectShadow", "sampler2DShadow", "sampler3D", "sampler3DRect", "samplerBuffer", "samplerCube", "samplerCubeArray", "samplerCubeArrayShadow", "samplerCubeShadow", "samplerShadow", "shared", "short", "sizeof", "smooth", "static", "struct", "subpassInput", "subpassInputMS", "subroutine", "superp", "switch", "template", "texture2D", "texture2DArray", "texture2DMS", "texture2DMSArray", "texture3D", "textureBuffer", "textureCube", "textureCubeArray", "this", "true", "typedef", "uimage1D", "uimage1DArray", "uimage2D", "uimage2DArray", "uimage2DMS", "uimage2DMSArray", "uimage2DRect", "uimage3D", "uimageBuffer", "uimageCube", "uimageCubeArray", "uint", "uniform", "union", "unsigned", "usampler1D", "usampler1DArray", "usampler2D", "usampler2DArray", "usampler2DMS", "usampler2DMSArray", "usampler2DRect", "usampler3D", "usamplerBuffer", "usamplerCube", "usamplerCubeArray", "using", "usubpassInput", "usubpassInputMS", "utexture2D", "utexture2DArray", "utexture2DMS", "utexture2DMSArray", "utexture3D", "utextureBuffer", "utextureCube", "utextureCubeArray", "uvec2", "uvec3", "uvec4", "varying", "vec2", "vec3", "vec4", "void", "volatile", "while", "writeonly" + }; + + ShaderAst::StatementPtr sanitizedAst = ShaderAst::Sanitize(shader, options); + + ShaderAst::StatementPtr* targetAstPtr = &sanitizedAst; + + ShaderAst::StatementPtr optimizedAst; + if (states.optimize) + { + optimizedAst = ShaderAst::Optimize(*targetAstPtr); + targetAstPtr = &optimizedAst; + } + + ShaderAst::StatementPtr& targetAst = *targetAstPtr; + + state.previsitor.enabledOptions = states.enabledOptions; + state.previsitor.selectedStage = shaderStage; + targetAst->Visit(state.previsitor); + + AppendHeader(); + + targetAst->Visit(*this); + + return state.stream.str(); + } + + void GlslWriter::SetEnv(Environment environment) + { + m_environment = std::move(environment); + } + + const char* GlslWriter::GetFlipYUniformName() + { + return s_flipYUniformName; + } + + void GlslWriter::Append(const ShaderAst::ExpressionType& type) + { + std::visit([&](auto&& arg) + { + Append(arg); + }, type); + } + + void GlslWriter::Append(ShaderAst::BuiltinEntry builtin) + { + switch (builtin) + { + case ShaderAst::BuiltinEntry::FragCoord: + Append("gl_FragCoord"); + break; + + case ShaderAst::BuiltinEntry::FragDepth: + Append("gl_FragDepth"); + break; + + case ShaderAst::BuiltinEntry::VertexPosition: + Append("gl_Position"); + break; + } + } + + void GlslWriter::Append(const ShaderAst::IdentifierType& /*identifierType*/) + { + throw std::runtime_error("unexpected identifier type"); + } + + void GlslWriter::Append(const ShaderAst::MatrixType& matrixType) + { + if (matrixType.columnCount == matrixType.rowCount) + { + Append("mat"); + Append(matrixType.columnCount); + } + else + { + Append("mat"); + Append(matrixType.columnCount); + Append("x"); + Append(matrixType.rowCount); + } + } + + void GlslWriter::Append(ShaderAst::PrimitiveType type) + { + switch (type) + { + case ShaderAst::PrimitiveType::Boolean: return Append("bool"); + case ShaderAst::PrimitiveType::Float32: return Append("float"); + case ShaderAst::PrimitiveType::Int32: return Append("ivec2"); + case ShaderAst::PrimitiveType::UInt32: return Append("uint"); + } + } + + void GlslWriter::Append(const ShaderAst::SamplerType& samplerType) + { + switch (samplerType.sampledType) + { + case ShaderAst::PrimitiveType::Boolean: + case ShaderAst::PrimitiveType::Float32: + break; + + case ShaderAst::PrimitiveType::Int32: Append("i"); break; + case ShaderAst::PrimitiveType::UInt32: Append("u"); break; + } + + Append("sampler"); + + switch (samplerType.dim) + { + case ImageType::E1D: Append("1D"); break; + case ImageType::E1D_Array: Append("1DArray"); break; + case ImageType::E2D: Append("2D"); break; + case ImageType::E2D_Array: Append("2DArray"); break; + case ImageType::E3D: Append("3D"); break; + case ImageType::Cubemap: Append("Cube"); break; + } + } + + void GlslWriter::Append(const ShaderAst::StructType& structType) + { + const auto& structDesc = Retrieve(m_currentState->structs, structType.structIndex); + Append(structDesc.name); + } + + void GlslWriter::Append(const ShaderAst::UniformType& /*uniformType*/) + { + throw std::runtime_error("unexpected UniformType"); + } + + void GlslWriter::Append(const ShaderAst::VectorType& vecType) + { + switch (vecType.type) + { + case ShaderAst::PrimitiveType::Boolean: Append("b"); break; + case ShaderAst::PrimitiveType::Float32: break; + case ShaderAst::PrimitiveType::Int32: Append("i"); break; + case ShaderAst::PrimitiveType::UInt32: Append("u"); break; + } + + Append("vec"); + Append(vecType.componentCount); + } + + void GlslWriter::Append(ShaderAst::MemoryLayout layout) + { + switch (layout) + { + case ShaderAst::MemoryLayout::Std140: + Append("std140"); + break; + } + } + + void GlslWriter::Append(ShaderAst::NoType) + { + return Append("void"); + } + + template + void GlslWriter::Append(const T& param) + { + NazaraAssert(m_currentState, "This function should only be called while processing an AST"); + + m_currentState->stream << param; + } + + template + void GlslWriter::Append(const T1& firstParam, const T2& secondParam, Args&&... params) + { + Append(firstParam); + Append(secondParam, std::forward(params)...); + } + + void GlslWriter::AppendCommentSection(const std::string& section) + { + NazaraAssert(m_currentState, "This function should only be called while processing an AST"); + + std::string stars((section.size() < 33) ? (36 - section.size()) / 2 : 3, '*'); + m_currentState->stream << "/*" << stars << ' ' << section << ' ' << stars << "*/"; + AppendLine(); + } + + void GlslWriter::AppendFunctionDeclaration(const ShaderAst::DeclareFunctionStatement& node, bool forward) + { + Append(node.returnType, " ", node.name, "("); + + bool first = true; + for (const auto& parameter : node.parameters) + { + if (!first) + Append(", "); + + first = false; + + Append(parameter.type, " ", parameter.name); + } + AppendLine((forward) ? ");" : ")"); + } + + void GlslWriter::AppendField(std::size_t structIndex, const ShaderAst::ExpressionPtr* memberIndices, std::size_t remainingMembers) + { + const auto& structDesc = Retrieve(m_currentState->structs, structIndex); + + assert((*memberIndices)->GetType() == ShaderAst::NodeType::ConstantExpression); + auto& constantValue = static_cast(**memberIndices); + Int32 index = std::get(constantValue.value); + + const auto& member = structDesc.members[index]; + + Append("."); + Append(member.name); + + if (remainingMembers > 1) + { + assert(IsStructType(member.type)); + AppendField(std::get(member.type).structIndex, memberIndices + 1, remainingMembers - 1); + } + } + + void GlslWriter::AppendHeader() + { unsigned int glslVersion; if (m_environment.glES) { @@ -111,14 +425,14 @@ namespace Nz if (!m_environment.glES && m_environment.extCallback) { // GL_ARB_shading_language_420pack (required for layout(binding = X)) - if (glslVersion < 420 && HasExplicitBinding(shader)) + if (glslVersion < 420) { if (m_environment.extCallback("GL_ARB_shading_language_420pack")) requiredExtensions.emplace_back("GL_ARB_shading_language_420pack"); } // GL_ARB_separate_shader_objects (required for layout(location = X)) - if (glslVersion < 410 && HasExplicitLocation(shader)) + if (glslVersion < 410) { if (m_environment.extCallback("GL_ARB_separate_shader_objects")) requiredExtensions.emplace_back("GL_ARB_separate_shader_objects"); @@ -142,183 +456,6 @@ namespace Nz AppendLine("#endif"); AppendLine(); } - - // Structures - /*if (shader.GetStructCount() > 0) - { - AppendCommentSection("Structures"); - for (const auto& s : shader.GetStructs()) - { - Append("struct "); - AppendLine(s.name); - AppendLine("{"); - for (const auto& m : s.members) - { - Append("\t"); - Append(m.type); - Append(" "); - Append(m.name); - AppendLine(";"); - } - AppendLine("};"); - AppendLine(); - } - }*/ - - // Global variables (uniforms, input and outputs) - const char* inKeyword = (glslVersion >= 130) ? "in" : "varying"; - const char* outKeyword = (glslVersion >= 130) ? "out" : "varying"; - - DeclareVariables(shader, shader.GetUniforms(), "uniform", "Uniforms"); - DeclareVariables(shader, shader.GetInputs(), inKeyword, "Inputs"); - DeclareVariables(shader, shader.GetOutputs(), outKeyword, "Outputs"); - - std::size_t functionCount = shader.GetFunctionCount(); - if (functionCount > 1) - { - AppendCommentSection("Prototypes"); - for (const auto& func : shader.GetFunctions()) - { - if (func.name != "main") - { - AppendFunctionPrototype(func); - AppendLine(";"); - } - } - } - - for (const auto& func : shader.GetFunctions()) - AppendFunction(func); - - return state.stream.str(); - } - - void GlslWriter::SetEnv(Environment environment) - { - m_environment = std::move(environment); - } - - void GlslWriter::Append(ShaderExpressionType type) - { - std::visit([&](auto&& arg) - { - Append(arg); - }, type); - } - - void GlslWriter::Append(ShaderNodes::BuiltinEntry builtin) - { - switch (builtin) - { - case ShaderNodes::BuiltinEntry::VertexPosition: - Append("gl_Position"); - break; - } - } - - void GlslWriter::Append(ShaderNodes::BasicType type) - { - switch (type) - { - case ShaderNodes::BasicType::Boolean: return Append("bool"); - case ShaderNodes::BasicType::Float1: return Append("float"); - case ShaderNodes::BasicType::Float2: return Append("vec2"); - case ShaderNodes::BasicType::Float3: return Append("vec3"); - case ShaderNodes::BasicType::Float4: return Append("vec4"); - case ShaderNodes::BasicType::Int1: return Append("int"); - case ShaderNodes::BasicType::Int2: return Append("ivec2"); - case ShaderNodes::BasicType::Int3: return Append("ivec3"); - case ShaderNodes::BasicType::Int4: return Append("ivec4"); - case ShaderNodes::BasicType::Mat4x4: return Append("mat4"); - case ShaderNodes::BasicType::Sampler2D: return Append("sampler2D"); - case ShaderNodes::BasicType::UInt1: return Append("uint"); - case ShaderNodes::BasicType::UInt2: return Append("uvec2"); - case ShaderNodes::BasicType::UInt3: return Append("uvec3"); - case ShaderNodes::BasicType::UInt4: return Append("uvec4"); - case ShaderNodes::BasicType::Void: return Append("void"); - } - } - - void GlslWriter::Append(ShaderNodes::MemoryLayout layout) - { - switch (layout) - { - case ShaderNodes::MemoryLayout::Std140: - Append("std140"); - break; - } - } - - void GlslWriter::AppendCommentSection(const std::string& section) - { - NazaraAssert(m_currentState, "This function should only be called while processing an AST"); - - std::string stars((section.size() < 33) ? (36 - section.size()) / 2 : 3, '*'); - m_currentState->stream << "/*" << stars << ' ' << section << ' ' << stars << "*/"; - AppendLine(); - } - - void GlslWriter::AppendField(const std::string& structName, std::size_t* memberIndex, std::size_t remainingMembers) - { - const auto& structs = m_context.shader->GetStructs(); - auto it = std::find_if(structs.begin(), structs.end(), [&](const auto& s) { return s.name == structName; }); - assert(it != structs.end()); - - const ShaderAst::Struct& s = *it; - assert(*memberIndex < s.members.size()); - - const auto& member = s.members[*memberIndex]; - Append("."); - Append(member.name); - - if (remainingMembers > 1) - { - assert(IsStructType(member.type)); - AppendField(std::get(member.type), memberIndex + 1, remainingMembers - 1); - } - } - - void GlslWriter::AppendFunction(const ShaderAst::Function& func) - { - NazaraAssert(!m_context.currentFunction, "A function is already being processed"); - NazaraAssert(m_currentState, "This function should only be called while processing an AST"); - - AppendFunctionPrototype(func); - - m_context.currentFunction = &func; - CallOnExit onExit([this] () - { - m_context.currentFunction = nullptr; - }); - - EnterScope(); - { - AstAdapter adapter; - adapter.flipYPosition = m_environment.flipYPosition; - - Visit(adapter.Clone(func.statement)); - } - LeaveScope(); - } - - void GlslWriter::AppendFunctionPrototype(const ShaderAst::Function& func) - { - Append(func.returnType); - - Append(" "); - Append(func.name); - - Append("("); - for (std::size_t i = 0; i < func.parameters.size(); ++i) - { - if (i != 0) - Append(", "); - - Append(func.parameters[i].type); - Append(" "); - Append(func.parameters[i].name); - } - Append(")\n"); } void GlslWriter::AppendLine(const std::string& txt) @@ -328,6 +465,27 @@ namespace Nz m_currentState->stream << txt << '\n' << std::string(m_currentState->indentLevel, '\t'); } + template + void GlslWriter::AppendLine(Args&&... params) + { + (Append(std::forward(params)), ...); + AppendLine(); + } + + void GlslWriter::AppendStatementList(std::vector& statements) + { + bool first = true; + for (const ShaderAst::StatementPtr& statement : statements) + { + if (!first && statement->GetType() != ShaderAst::NodeType::NoOpStatement) + AppendLine(); + + statement->Visit(*this); + + first = false; + } + } + void GlslWriter::EnterScope() { NazaraAssert(m_currentState, "This function should only be called while processing an AST"); @@ -336,53 +494,202 @@ namespace Nz AppendLine("{"); } - void GlslWriter::LeaveScope() + void GlslWriter::LeaveScope(bool skipLine) { NazaraAssert(m_currentState, "This function should only be called while processing an AST"); m_currentState->indentLevel--; AppendLine(); - AppendLine("}"); + + if (skipLine) + AppendLine("}"); + else + Append("}"); } - void GlslWriter::Visit(ShaderNodes::ExpressionPtr& expr, bool encloseIfRequired) + void GlslWriter::HandleEntryPoint(ShaderAst::DeclareFunctionStatement& node) { - bool enclose = encloseIfRequired && (expr->GetExpressionCategory() != ShaderNodes::ExpressionCategory::LValue); + if (node.entryStage == ShaderStageType::Fragment && node.earlyFragmentTests && *node.earlyFragmentTests) + { + if ((m_environment.glES && m_environment.glMajorVersion >= 3 && m_environment.glMinorVersion >= 1) || (!m_environment.glES && m_environment.glMajorVersion >= 4 && m_environment.glMinorVersion >= 2) || m_environment.extCallback("GL_ARB_shader_image_load_store")) + { + AppendLine("layout(early_fragment_tests) in;"); + AppendLine(); + } + } + + HandleInOut(); + AppendLine("void main()"); + EnterScope(); + { + if (!m_currentState->inputFields.empty()) + { + assert(node.varIndex); + assert(!node.parameters.empty()); + + auto& parameter = node.parameters.front(); + const std::string& varName = parameter.name; + RegisterVariable(*node.varIndex, varName); + + assert(IsStructType(parameter.type)); + std::size_t structIndex = std::get(parameter.type).structIndex; + const ShaderAst::StructDescription& structDesc = Retrieve(m_currentState->structs, structIndex); + + AppendLine(structDesc.name, " ", varName, ";"); + for (const auto& [memberName, targetName] : m_currentState->inputFields) + AppendLine(varName, ".", memberName, " = ", targetName, ";"); + + AppendLine(); + } + + // Output struct is handled on return node + m_currentState->isInEntryPoint = true; + + AppendStatementList(node.statements); + + m_currentState->isInEntryPoint = false; + } + LeaveScope(); + } + + void GlslWriter::HandleInOut() + { + auto AppendInOut = [this](const ShaderAst::StructDescription& structDesc, std::vector& fields, const char* keyword, const char* targetPrefix) + { + for (const auto& member : structDesc.members) + { + if (member.builtin) + { + auto it = s_builtinMapping.find(member.builtin.value()); + assert(it != s_builtinMapping.end()); + + const Builtin& builtin = it->second; + if (m_currentState->stage && !builtin.stageFlags.Test(*m_currentState->stage)) + continue; //< This builtin is not active in this stage, skip it + + fields.push_back({ + member.name, + builtin.identifier + }); + } + else if (member.locationIndex) + { + Append("layout(location = "); + Append(*member.locationIndex); + Append(") "); + Append(keyword); + Append(" "); + Append(member.type); + Append(" "); + Append(targetPrefix); + Append(member.name); + AppendLine(";"); + + fields.push_back({ + member.name, + targetPrefix + member.name + }); + } + } + AppendLine(); + }; + + const ShaderAst::DeclareFunctionStatement& node = *m_currentState->previsitor.entryPoint; + + const ShaderAst::StructDescription* inputStruct = nullptr; + + if (!node.parameters.empty()) + { + assert(node.parameters.size() == 1); + auto& parameter = node.parameters.front(); + assert(std::holds_alternative(parameter.type)); + + std::size_t inputStructIndex = std::get(parameter.type).structIndex; + inputStruct = &Retrieve(m_currentState->structs, inputStructIndex); + + AppendCommentSection("Inputs"); + AppendInOut(*inputStruct, m_currentState->inputFields, "in", s_inputPrefix); + } + + if (m_currentState->stage == ShaderStageType::Vertex && m_environment.flipYPosition) + { + AppendLine("uniform float ", s_flipYUniformName, ";"); + AppendLine(); + } + + if (!IsNoType(node.returnType)) + { + assert(std::holds_alternative(node.returnType)); + std::size_t outputStructIndex = std::get(node.returnType).structIndex; + + const ShaderAst::StructDescription& outputStruct = Retrieve(m_currentState->structs, outputStructIndex); + + AppendCommentSection("Outputs"); + AppendInOut(outputStruct, m_currentState->outputFields, "out", s_outputPrefix); + } + } + + void GlslWriter::RegisterStruct(std::size_t structIndex, ShaderAst::StructDescription desc) + { + assert(m_currentState->structs.find(structIndex) == m_currentState->structs.end()); + m_currentState->structs.emplace(structIndex, std::move(desc)); + } + + void GlslWriter::RegisterVariable(std::size_t varIndex, std::string varName) + { + assert(m_currentState->variableNames.find(varIndex) == m_currentState->variableNames.end()); + m_currentState->variableNames.emplace(varIndex, std::move(varName)); + } + + void GlslWriter::Visit(ShaderAst::ExpressionPtr& expr, bool encloseIfRequired) + { + bool enclose = encloseIfRequired && (GetExpressionCategory(*expr) != ShaderAst::ExpressionCategory::LValue); if (enclose) Append("("); - ShaderAstVisitor::Visit(expr); + expr->Visit(*this); if (enclose) Append(")"); } - void GlslWriter::Visit(ShaderNodes::AccessMember& node) + void GlslWriter::Visit(ShaderAst::AccessIndexExpression& node) { - Visit(node.structExpr, true); + Visit(node.expr, true); - const ShaderExpressionType& exprType = node.structExpr->GetExpressionType(); - assert(IsStructType(exprType)); + const ShaderAst::ExpressionType& exprType = GetExpressionType(*node.expr); - AppendField(std::get(exprType), node.memberIndices.data(), node.memberIndices.size()); + // For structs, convert indices to field names + if (IsStructType(exprType)) + AppendField(std::get(exprType).structIndex, node.indices.data(), node.indices.size()); + else + { + // Array access + for (ShaderAst::ExpressionPtr& expr : node.indices) + { + Append("["); + Visit(expr); + Append("]"); + } + } } - void GlslWriter::Visit(ShaderNodes::AssignOp& node) + void GlslWriter::Visit(ShaderAst::AssignExpression& node) { - Visit(node.left); + node.left->Visit(*this); switch (node.op) { - case ShaderNodes::AssignType::Simple: + case ShaderAst::AssignType::Simple: Append(" = "); break; } - Visit(node.right); + node.right->Visit(*this); } - void GlslWriter::Visit(ShaderNodes::Branch& node) + void GlslWriter::Visit(ShaderAst::BranchStatement& node) { bool first = true; for (const auto& statement : node.condStatements) @@ -391,11 +698,11 @@ namespace Nz Append("else "); Append("if ("); - Visit(statement.condition); + statement.condition->Visit(*this); AppendLine(")"); EnterScope(); - Visit(statement.statement); + statement.statement->Visit(*this); LeaveScope(); first = false; @@ -406,62 +713,85 @@ namespace Nz AppendLine("else"); EnterScope(); - Visit(node.elseStatement); + node.elseStatement->Visit(*this); LeaveScope(); } } - void GlslWriter::Visit(ShaderNodes::BinaryOp& node) + void GlslWriter::Visit(ShaderAst::BinaryExpression& node) { Visit(node.left, true); switch (node.op) { - case ShaderNodes::BinaryType::Add: - Append(" + "); - break; - case ShaderNodes::BinaryType::Substract: - Append(" - "); - break; - case ShaderNodes::BinaryType::Multiply: - Append(" * "); - break; - case ShaderNodes::BinaryType::Divide: - Append(" / "); - break; - case ShaderNodes::BinaryType::Equality: - Append(" == "); - break; + case ShaderAst::BinaryType::Add: Append(" + "); break; + case ShaderAst::BinaryType::Subtract: Append(" - "); break; + case ShaderAst::BinaryType::Multiply: Append(" * "); break; + case ShaderAst::BinaryType::Divide: Append(" / "); break; + + case ShaderAst::BinaryType::CompEq: Append(" == "); break; + case ShaderAst::BinaryType::CompGe: Append(" >= "); break; + case ShaderAst::BinaryType::CompGt: Append(" > "); break; + case ShaderAst::BinaryType::CompLe: Append(" <= "); break; + case ShaderAst::BinaryType::CompLt: Append(" < "); break; + case ShaderAst::BinaryType::CompNe: Append(" != "); break; } Visit(node.right, true); } - void GlslWriter::Visit(ShaderNodes::BuiltinVariable& var) + void GlslWriter::Visit(ShaderAst::CallFunctionExpression& node) { - Append(var.entry); - } + assert(std::holds_alternative(node.targetFunction)); + const std::string& targetName = Retrieve(m_currentState->previsitor.functions, std::get(node.targetFunction)).name; - void GlslWriter::Visit(ShaderNodes::Cast& node) - { - Append(node.exprType); - Append("("); - - for (std::size_t i = 0; node.expressions[i]; ++i) + Append(targetName, "("); + for (std::size_t i = 0; i < node.parameters.size(); ++i) { if (i != 0) + Append(", "); + + node.parameters[i]->Visit(*this); + } + Append(")"); + } + + void GlslWriter::Visit(ShaderAst::CastExpression& node) + { + Append(node.targetType); + Append("("); + + bool first = true; + for (const auto& exprPtr : node.expressions) + { + if (!exprPtr) + break; + + if (!first) m_currentState->stream << ", "; - const auto& exprPtr = node.expressions[i]; - NazaraAssert(exprPtr, "Invalid expression"); - - Visit(exprPtr); + exprPtr->Visit(*this); + first = false; } Append(")"); } - void GlslWriter::Visit(ShaderNodes::Constant& node) + void GlslWriter::Visit(ShaderAst::ConditionalExpression& node) + { + if (TestBit(m_currentState->enabledOptions, node.optionIndex)) + Visit(node.truePath); + else + Visit(node.falsePath); + } + + void GlslWriter::Visit(ShaderAst::ConditionalStatement& node) + { + if (TestBit(m_currentState->enabledOptions, node.optionIndex)) + node.statement->Visit(*this); + } + + void GlslWriter::Visit(ShaderAst::ConstantExpression& node) { std::visit([&](auto&& arg) { @@ -485,51 +815,218 @@ namespace Nz }, node.value); } - void GlslWriter::Visit(ShaderNodes::DeclareVariable& node) + void GlslWriter::Visit(ShaderAst::DeclareExternalStatement& node) { - assert(node.variable->GetType() == ShaderNodes::VariableType::LocalVariable); + assert(node.varIndex); + std::size_t varIndex = *node.varIndex; - const auto& localVar = static_cast(*node.variable); - - Append(localVar.type); - Append(" "); - Append(localVar.name); - if (node.expression) + for (const auto& externalVar : node.externalVars) { - Append(" = "); - Visit(node.expression); + bool isStd140 = false; + if (IsUniformType(externalVar.type)) + { + auto& uniform = std::get(externalVar.type); + assert(std::holds_alternative(uniform.containedType)); + + std::size_t structIndex = std::get(uniform.containedType).structIndex; + auto& structInfo = Retrieve(m_currentState->structs, structIndex); + isStd140 = structInfo.layout == StructLayout::Std140; + } + + if (externalVar.bindingIndex) + { + Append("layout(binding = "); + Append(*externalVar.bindingIndex); + if (isStd140) + Append(", std140"); + + Append(") uniform "); + + if (IsUniformType(externalVar.type)) + { + Append("_NzBinding_"); + AppendLine(externalVar.name); + + EnterScope(); + { + auto& uniform = std::get(externalVar.type); + assert(std::holds_alternative(uniform.containedType)); + + std::size_t structIndex = std::get(uniform.containedType).structIndex; + auto& structDesc = Retrieve(m_currentState->structs, structIndex); + + bool first = true; + for (const auto& member : structDesc.members) + { + if (!first) + AppendLine(); + + first = false; + + Append(member.type); + Append(" "); + Append(member.name); + Append(";"); + } + } + LeaveScope(false); + } + else + Append(externalVar.type); + + Append(" "); + Append(externalVar.name); + AppendLine(";"); + + if (IsUniformType(externalVar.type)) + AppendLine(); + } + + RegisterVariable(varIndex++, externalVar.name); + } + } + + void GlslWriter::Visit(ShaderAst::DeclareFunctionStatement& node) + { + NazaraAssert(m_currentState, "This function should only be called while processing an AST"); + + if (node.entryStage && m_currentState->previsitor.entryPoint != &node) + return; //< Ignore other entry points + + assert(node.funcIndex); + auto& funcData = Retrieve(m_currentState->previsitor.functions, node.funcIndex.value()); + + // Declare functions called by this function which aren't already defined + bool hasPredeclaration = false; + for (std::size_t i = funcData.calledFunctions.FindFirst(); i != funcData.calledFunctions.npos; i = funcData.calledFunctions.FindNext(i)) + { + if (!m_currentState->declaredFunctions.UnboundedTest(i)) + { + hasPredeclaration = true; + + auto& targetFunc = Retrieve(m_currentState->previsitor.functions, i); + AppendFunctionDeclaration(*targetFunc.node, true); + + m_currentState->declaredFunctions.UnboundedSet(i); + } } + if (hasPredeclaration) + AppendLine(); + + if (node.entryStage) + return HandleEntryPoint(node); + + std::optional varIndexOpt = node.varIndex; + + for (const auto& parameter : node.parameters) + { + assert(varIndexOpt); + std::size_t& varIndex = *varIndexOpt; + RegisterVariable(varIndex++, parameter.name); + } + + AppendFunctionDeclaration(node); + EnterScope(); + { + AppendStatementList(node.statements); + } + LeaveScope(); + + m_currentState->declaredFunctions.UnboundedSet(node.funcIndex.value()); + } + + void GlslWriter::Visit(ShaderAst::DeclareOptionStatement& /*node*/) + { + /* nothing to do */ + } + + void GlslWriter::Visit(ShaderAst::DeclareStructStatement& node) + { + assert(node.structIndex); + RegisterStruct(*node.structIndex, node.description); + + Append("struct "); + AppendLine(node.description.name); + EnterScope(); + { + bool first = true; + for (const auto& member : node.description.members) + { + if (!first) + AppendLine(); + + first = false; + + Append(member.type); + Append(" "); + Append(member.name); + Append(";"); + } + } + LeaveScope(false); AppendLine(";"); } - void GlslWriter::Visit(ShaderNodes::ExpressionStatement& node) + void GlslWriter::Visit(ShaderAst::DeclareVariableStatement& node) { - Visit(node.expression); + assert(node.varIndex); + RegisterVariable(*node.varIndex, node.varName); + + Append(node.varType); + Append(" "); + Append(node.varName); + if (node.initialExpression) + { + Append(" = "); + node.initialExpression->Visit(*this); + } + Append(";"); } - void GlslWriter::Visit(ShaderNodes::Identifier& node) + void GlslWriter::Visit(ShaderAst::DiscardStatement& /*node*/) { - Visit(node.var); + Append("discard;"); } - void GlslWriter::Visit(ShaderNodes::InputVariable& var) + void GlslWriter::Visit(ShaderAst::ExpressionStatement& node) { - Append(var.name); + node.expression->Visit(*this); + Append(";"); } - - void GlslWriter::Visit(ShaderNodes::IntrinsicCall& node) + + void GlslWriter::Visit(ShaderAst::IntrinsicExpression& node) { switch (node.intrinsic) { - case ShaderNodes::IntrinsicType::CrossProduct: + case ShaderAst::IntrinsicType::CrossProduct: Append("cross"); break; - case ShaderNodes::IntrinsicType::DotProduct: + case ShaderAst::IntrinsicType::DotProduct: Append("dot"); break; + + case ShaderAst::IntrinsicType::Length: + Append("length"); + break; + + case ShaderAst::IntrinsicType::Max: + Append("max"); + break; + + case ShaderAst::IntrinsicType::Min: + Append("min"); + break; + + case ShaderAst::IntrinsicType::Pow: + Append("pow"); + break; + + case ShaderAst::IntrinsicType::SampleTexture: + Append("texture"); + break; } Append("("); @@ -538,96 +1035,141 @@ namespace Nz if (i != 0) Append(", "); - Visit(node.parameters[i]); + node.parameters[i]->Visit(*this); } Append(")"); } - void GlslWriter::Visit(ShaderNodes::LocalVariable& var) + void GlslWriter::Visit(ShaderAst::MultiStatement& node) { - Append(var.name); + AppendStatementList(node.statements); } - void GlslWriter::Visit(ShaderNodes::ParameterVariable& var) + void GlslWriter::Visit(ShaderAst::NoOpStatement& /*node*/) { - Append(var.name); + /* nothing to do */ } - void GlslWriter::Visit(ShaderNodes::OutputVariable& var) + void GlslWriter::Visit(ShaderAst::ReturnStatement& node) { - Append(var.name); - } - - void GlslWriter::Visit(ShaderNodes::Sample2D& node) - { - Append("texture("); - Visit(node.sampler); - Append(", "); - Visit(node.coordinates); - Append(")"); - } - - void GlslWriter::Visit(ShaderNodes::StatementBlock& node) - { - bool first = true; - for (const ShaderNodes::StatementPtr& statement : node.statements) + if (m_currentState->isInEntryPoint) { - if (!first) + assert(node.returnExpr); + + const ShaderAst::ExpressionType& returnType = GetExpressionType(*node.returnExpr); + assert(IsStructType(returnType)); + std::size_t structIndex = std::get(returnType).structIndex; + const ShaderAst::StructDescription& structDesc = Retrieve(m_currentState->structs, structIndex); + + std::string outputStructVarName; + if (node.returnExpr->GetType() == ShaderAst::NodeType::VariableExpression) + outputStructVarName = Retrieve(m_currentState->variableNames, static_cast(*node.returnExpr).variableId); + else + { AppendLine(); + Append(structDesc.name, " ", s_outputVarName, " = "); + node.returnExpr->Visit(*this); + AppendLine(";"); - Visit(statement); + outputStructVarName = s_outputVarName; + } - first = false; + AppendLine(); + + for (const auto& [name, targetName] : m_currentState->outputFields) + { + bool isOutputPosition = (m_currentState->stage == ShaderStageType::Vertex && m_environment.flipYPosition && targetName == "gl_Position"); + + Append(targetName, " = ", outputStructVarName, ".", name); + if (isOutputPosition) + Append(" * vec4(1.0, ", s_flipYUniformName, ", 1.0, 1.0)"); + + AppendLine(";"); + } + + Append("return;"); //< TODO: Don't return if it's the last statement of the function + } + else + { + if (node.returnExpr) + { + Append("return "); + node.returnExpr->Visit(*this); + Append(";"); + } + else + Append("return;"); } } - void GlslWriter::Visit(ShaderNodes::SwizzleOp& node) + void GlslWriter::Visit(ShaderAst::SwizzleExpression& node) { - Visit(node.expression); + Visit(node.expression, true); Append("."); for (std::size_t i = 0; i < node.componentCount; ++i) { switch (node.components[i]) { - case ShaderNodes::SwizzleComponent::First: + case ShaderAst::SwizzleComponent::First: Append("x"); break; - case ShaderNodes::SwizzleComponent::Second: + case ShaderAst::SwizzleComponent::Second: Append("y"); break; - case ShaderNodes::SwizzleComponent::Third: + case ShaderAst::SwizzleComponent::Third: Append("z"); break; - case ShaderNodes::SwizzleComponent::Fourth: + case ShaderAst::SwizzleComponent::Fourth: Append("w"); break; } } } - void GlslWriter::Visit(ShaderNodes::UniformVariable& var) + void GlslWriter::Visit(ShaderAst::VariableExpression& node) { - Append(var.name); + const std::string& varName = Retrieve(m_currentState->variableNames, node.variableId); + Append(varName); } - bool GlslWriter::HasExplicitBinding(const ShaderAst& shader) + void GlslWriter::Visit(ShaderAst::UnaryExpression& node) { - for (const auto& uniform : shader.GetUniforms()) + switch (node.op) + { + case ShaderAst::UnaryType::LogicalNot: + Append("!"); + break; + + case ShaderAst::UnaryType::Minus: + Append("-"); + break; + + case ShaderAst::UnaryType::Plus: + Append("+"); + break; + } + + Visit(node.expression); + } + + bool GlslWriter::HasExplicitBinding(ShaderAst::StatementPtr& shader) + { + /*for (const auto& uniform : shader.GetUniforms()) { if (uniform.bindingIndex.has_value()) return true; - } + }*/ return false; } - bool GlslWriter::HasExplicitLocation(const ShaderAst& shader) + bool GlslWriter::HasExplicitLocation(ShaderAst::StatementPtr& shader) { - for (const auto& input : shader.GetInputs()) + /*for (const auto& input : shader.GetInputs()) { if (input.locationIndex.has_value()) return true; @@ -637,7 +1179,7 @@ namespace Nz { if (output.locationIndex.has_value()) return true; - } + }*/ return false; } diff --git a/src/Nazara/Shader/LangWriter.cpp b/src/Nazara/Shader/LangWriter.cpp new file mode 100644 index 000000000..cfa1e7a50 --- /dev/null +++ b/src/Nazara/Shader/LangWriter.cpp @@ -0,0 +1,842 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + namespace + { + template const T& Retrieve(const std::unordered_map& map, std::size_t id) + { + auto it = map.find(id); + assert(it != map.end()); + return it->second; + } + } + + struct LangWriter::BindingAttribute + { + std::optional bindingIndex; + + inline bool HasValue() const { return bindingIndex.has_value(); } + }; + + struct LangWriter::BuiltinAttribute + { + std::optional builtin; + + inline bool HasValue() const { return builtin.has_value(); } + }; + + struct LangWriter::DepthWriteAttribute + { + std::optional writeMode; + + inline bool HasValue() const { return writeMode.has_value(); } + }; + + struct LangWriter::EarlyFragmentTestsAttribute + { + std::optional earlyFragmentTests; + + inline bool HasValue() const { return earlyFragmentTests.has_value(); } + }; + + struct LangWriter::EntryAttribute + { + std::optional stageType; + + inline bool HasValue() const { return stageType.has_value(); } + }; + + struct LangWriter::LayoutAttribute + { + std::optional layout; + + inline bool HasValue() const { return layout.has_value(); } + }; + + struct LangWriter::LocationAttribute + { + std::optional locationIndex; + + inline bool HasValue() const { return locationIndex.has_value(); } + }; + + struct LangWriter::State + { + const States* states = nullptr; + std::stringstream stream; + std::unordered_map optionNames; + std::unordered_map structs; + std::unordered_map variableNames; + bool isInEntryPoint = false; + unsigned int indentLevel = 0; + }; + + std::string LangWriter::Generate(ShaderAst::StatementPtr& shader, const States& states) + { + State state; + m_currentState = &state; + CallOnExit onExit([this]() + { + m_currentState = nullptr; + }); + + ShaderAst::SanitizeVisitor::Options options; + options.removeOptionDeclaration = false; + + ShaderAst::StatementPtr sanitizedAst = ShaderAst::Sanitize(shader, options); + + AppendHeader(); + + sanitizedAst->Visit(*this); + + return state.stream.str(); + } + + void LangWriter::SetEnv(Environment environment) + { + m_environment = std::move(environment); + } + + void LangWriter::Append(const ShaderAst::ExpressionType& type) + { + std::visit([&](auto&& arg) + { + Append(arg); + }, type); + } + + void LangWriter::Append(const ShaderAst::IdentifierType& /*identifierType*/) + { + throw std::runtime_error("unexpected identifier type"); + } + + void LangWriter::Append(const ShaderAst::MatrixType& matrixType) + { + if (matrixType.columnCount == matrixType.rowCount) + { + Append("mat"); + Append(matrixType.columnCount); + } + else + { + Append("mat"); + Append(matrixType.columnCount); + Append("x"); + Append(matrixType.rowCount); + } + + Append("<", matrixType.type, ">"); + } + + void LangWriter::Append(ShaderAst::PrimitiveType type) + { + switch (type) + { + case ShaderAst::PrimitiveType::Boolean: return Append("bool"); + case ShaderAst::PrimitiveType::Float32: return Append("f32"); + case ShaderAst::PrimitiveType::Int32: return Append("i32"); + case ShaderAst::PrimitiveType::UInt32: return Append("ui32"); + } + } + + void LangWriter::Append(const ShaderAst::SamplerType& samplerType) + { + Append("sampler"); + + switch (samplerType.dim) + { + case ImageType::E1D: Append("1D"); break; + case ImageType::E1D_Array: Append("1DArray"); break; + case ImageType::E2D: Append("2D"); break; + case ImageType::E2D_Array: Append("2DArray"); break; + case ImageType::E3D: Append("3D"); break; + case ImageType::Cubemap: Append("Cube"); break; + } + + Append("<", samplerType.sampledType, ">"); + } + + void LangWriter::Append(const ShaderAst::StructType& structType) + { + const auto& structDesc = Retrieve(m_currentState->structs, structType.structIndex); + Append(structDesc.name); + } + + void LangWriter::Append(const ShaderAst::UniformType& uniformType) + { + Append("uniform<"); + std::visit([&](auto&& arg) + { + Append(arg); + }, uniformType.containedType); + Append(">"); + } + + void LangWriter::Append(const ShaderAst::VectorType& vecType) + { + Append("vec", vecType.componentCount, "<", vecType.type, ">"); + } + + void LangWriter::Append(ShaderAst::NoType) + { + return Append("()"); + } + + template + void LangWriter::Append(const T& param) + { + NazaraAssert(m_currentState, "This function should only be called while processing an AST"); + + m_currentState->stream << param; + } + + template + void LangWriter::Append(const T1& firstParam, const T2& secondParam, Args&&... params) + { + Append(firstParam); + Append(secondParam, std::forward(params)...); + } + + template + void LangWriter::AppendAttributes(bool appendLine, Args&&... params) + { + bool hasAnyAttribute = (params.HasValue() || ...); + if (!hasAnyAttribute) + return; + + Append("["); + (AppendAttribute(params), ...); + Append("]"); + + if (appendLine) + AppendLine(); + else + Append(" "); + } + + void LangWriter::AppendAttribute(BindingAttribute binding) + { + if (!binding.HasValue()) + return; + + Append("binding(", *binding.bindingIndex, ")"); + } + + void LangWriter::AppendAttribute(BuiltinAttribute builtin) + { + if (!builtin.HasValue()) + return; + + switch (*builtin.builtin) + { + case ShaderAst::BuiltinEntry::FragCoord: + Append("builtin(fragcoord)"); + break; + + case ShaderAst::BuiltinEntry::FragDepth: + Append("builtin(fragdepth)"); + break; + + case ShaderAst::BuiltinEntry::VertexPosition: + Append("builtin(position)"); + break; + } + } + + void LangWriter::AppendAttribute(DepthWriteAttribute depthWrite) + { + if (!depthWrite.HasValue()) + return; + + switch (*depthWrite.writeMode) + { + case ShaderAst::DepthWriteMode::Greater: + Append("depth_write(greater)"); + break; + + case ShaderAst::DepthWriteMode::Less: + Append("depth_write(less)"); + break; + + case ShaderAst::DepthWriteMode::Replace: + Append("depth_write(replace)"); + break; + + case ShaderAst::DepthWriteMode::Unchanged: + Append("depth_write(unchanged)"); + break; + } + } + + void LangWriter::AppendAttribute(EarlyFragmentTestsAttribute earlyFragmentTests) + { + if (!earlyFragmentTests.HasValue()) + return; + + if (*earlyFragmentTests.earlyFragmentTests) + Append("early_fragment_tests(on)"); + else + Append("early_fragment_tests(off)"); + } + + void LangWriter::AppendAttribute(EntryAttribute entry) + { + if (!entry.HasValue()) + return; + + switch (*entry.stageType) + { + case ShaderStageType::Fragment: + Append("entry(frag)"); + break; + + case ShaderStageType::Vertex: + Append("entry(vert)"); + break; + } + } + + void LangWriter::AppendAttribute(LayoutAttribute entry) + { + if (!entry.HasValue()) + return; + + switch (*entry.layout) + { + case StructLayout::Std140: + Append("layout(std140)"); + break; + } + } + + void LangWriter::AppendAttribute(LocationAttribute location) + { + if (!location.HasValue()) + return; + + Append("location(", *location.locationIndex, ")"); + } + + void LangWriter::AppendCommentSection(const std::string& section) + { + NazaraAssert(m_currentState, "This function should only be called while processing an AST"); + + std::string stars((section.size() < 33) ? (36 - section.size()) / 2 : 3, '*'); + m_currentState->stream << "/*" << stars << ' ' << section << ' ' << stars << "*/"; + AppendLine(); + } + + void LangWriter::AppendField(std::size_t structIndex, const ShaderAst::ExpressionPtr* memberIndices, std::size_t remainingMembers) + { + const auto& structDesc = Retrieve(m_currentState->structs, structIndex); + + assert((*memberIndices)->GetType() == ShaderAst::NodeType::ConstantExpression); + auto& constantValue = static_cast(**memberIndices); + Int32 index = std::get(constantValue.value); + + const auto& member = structDesc.members[index]; + + Append("."); + Append(member.name); + + if (remainingMembers > 1) + { + assert(IsStructType(member.type)); + AppendField(std::get(member.type).structIndex, memberIndices + 1, remainingMembers - 1); + } + } + + void LangWriter::AppendLine(const std::string& txt) + { + NazaraAssert(m_currentState, "This function should only be called while processing an AST"); + + m_currentState->stream << txt << '\n' << std::string(m_currentState->indentLevel, '\t'); + } + + template + void LangWriter::AppendLine(Args&&... params) + { + (Append(std::forward(params)), ...); + AppendLine(); + } + + void LangWriter::AppendStatementList(std::vector& statements) + { + bool first = true; + for (const ShaderAst::StatementPtr& statement : statements) + { + if (!first && statement->GetType() != ShaderAst::NodeType::NoOpStatement) + AppendLine(); + + statement->Visit(*this); + + first = false; + } + } + + void LangWriter::EnterScope() + { + NazaraAssert(m_currentState, "This function should only be called while processing an AST"); + + m_currentState->indentLevel++; + AppendLine("{"); + } + + void LangWriter::LeaveScope(bool skipLine) + { + NazaraAssert(m_currentState, "This function should only be called while processing an AST"); + + m_currentState->indentLevel--; + AppendLine(); + + if (skipLine) + AppendLine("}"); + else + Append("}"); + } + + void LangWriter::RegisterOption(std::size_t optionIndex, std::string optionName) + { + assert(m_currentState->optionNames.find(optionIndex) == m_currentState->optionNames.end()); + m_currentState->optionNames.emplace(optionIndex, std::move(optionName)); + } + + void LangWriter::RegisterStruct(std::size_t structIndex, ShaderAst::StructDescription desc) + { + assert(m_currentState->structs.find(structIndex) == m_currentState->structs.end()); + m_currentState->structs.emplace(structIndex, std::move(desc)); + } + + void LangWriter::RegisterVariable(std::size_t varIndex, std::string varName) + { + assert(m_currentState->variableNames.find(varIndex) == m_currentState->variableNames.end()); + m_currentState->variableNames.emplace(varIndex, std::move(varName)); + } + + void LangWriter::Visit(ShaderAst::ExpressionPtr& expr, bool encloseIfRequired) + { + bool enclose = encloseIfRequired && (GetExpressionCategory(*expr) != ShaderAst::ExpressionCategory::LValue); + + if (enclose) + Append("("); + + expr->Visit(*this); + + if (enclose) + Append(")"); + } + + void LangWriter::Visit(ShaderAst::AccessIndexExpression& node) + { + Visit(node.expr, true); + + const ShaderAst::ExpressionType& exprType = GetExpressionType(*node.expr); + + // For structs, convert indices to field names + if (IsStructType(exprType)) + AppendField(std::get(exprType).structIndex, node.indices.data(), node.indices.size()); + else + { + // Array access + for (ShaderAst::ExpressionPtr& expr : node.indices) + { + Append("["); + Visit(expr); + Append("]"); + } + } + } + + void LangWriter::Visit(ShaderAst::AssignExpression& node) + { + node.left->Visit(*this); + + switch (node.op) + { + case ShaderAst::AssignType::Simple: + Append(" = "); + break; + } + + node.right->Visit(*this); + } + + void LangWriter::Visit(ShaderAst::BranchStatement& node) + { + bool first = true; + for (const auto& statement : node.condStatements) + { + if (!first) + Append("else "); + + Append("if ("); + statement.condition->Visit(*this); + AppendLine(")"); + + EnterScope(); + statement.statement->Visit(*this); + LeaveScope(); + + first = false; + } + + if (node.elseStatement) + { + AppendLine("else"); + + EnterScope(); + node.elseStatement->Visit(*this); + LeaveScope(); + } + } + + void LangWriter::Visit(ShaderAst::BinaryExpression& node) + { + Visit(node.left, true); + + switch (node.op) + { + case ShaderAst::BinaryType::Add: Append(" + "); break; + case ShaderAst::BinaryType::Subtract: Append(" - "); break; + case ShaderAst::BinaryType::Multiply: Append(" * "); break; + case ShaderAst::BinaryType::Divide: Append(" / "); break; + + case ShaderAst::BinaryType::CompEq: Append(" == "); break; + case ShaderAst::BinaryType::CompGe: Append(" >= "); break; + case ShaderAst::BinaryType::CompGt: Append(" > "); break; + case ShaderAst::BinaryType::CompLe: Append(" <= "); break; + case ShaderAst::BinaryType::CompLt: Append(" < "); break; + case ShaderAst::BinaryType::CompNe: Append(" != "); break; + } + + Visit(node.right, true); + } + + void LangWriter::Visit(ShaderAst::CastExpression& node) + { + Append(node.targetType); + Append("("); + + bool first = true; + for (const auto& exprPtr : node.expressions) + { + if (!exprPtr) + break; + + if (!first) + m_currentState->stream << ", "; + + exprPtr->Visit(*this); + first = false; + } + + Append(")"); + } + + void LangWriter::Visit(ShaderAst::ConditionalExpression& node) + { + Append("select_opt(", Retrieve(m_currentState->optionNames, node.optionIndex), ", "); + node.truePath->Visit(*this); + Append(", "); + node.falsePath->Visit(*this); + Append(")"); + } + + void LangWriter::Visit(ShaderAst::ConditionalStatement& node) + { + Append("[opt(", Retrieve(m_currentState->optionNames, node.optionIndex), ")]"); + node.statement->Visit(*this); + } + + void LangWriter::Visit(ShaderAst::ConstantExpression& node) + { + std::visit([&](auto&& arg) + { + using T = std::decay_t; + + if constexpr (std::is_same_v) + Append((arg) ? "true" : "false"); + else if constexpr (std::is_same_v || std::is_same_v || std::is_same_v) + Append(std::to_string(arg)); + else if constexpr (std::is_same_v) + Append("vec2(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ")"); + else if constexpr (std::is_same_v) + Append("vec2(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ")"); + else if constexpr (std::is_same_v) + Append("vec3(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ", " + std::to_string(arg.z) + ")"); + else if constexpr (std::is_same_v) + Append("vec3(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ", " + std::to_string(arg.z) + ")"); + else if constexpr (std::is_same_v) + Append("vec4(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ", " + std::to_string(arg.z) + ", " + std::to_string(arg.w) + ")"); + else if constexpr (std::is_same_v) + Append("vec4(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ", " + std::to_string(arg.z) + ", " + std::to_string(arg.w) + ")"); + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, node.value); + } + + void LangWriter::Visit(ShaderAst::DeclareExternalStatement& node) + { + assert(node.varIndex); + std::size_t varIndex = *node.varIndex; + + AppendLine("external"); + EnterScope(); + + bool first = true; + for (const auto& externalVar : node.externalVars) + { + if (!first) + AppendLine(","); + + first = false; + + AppendAttributes(false, BindingAttribute{ externalVar.bindingIndex }); + Append(externalVar.name, ": ", externalVar.type); + + RegisterVariable(varIndex++, externalVar.name); + } + + LeaveScope(); + } + + void LangWriter::Visit(ShaderAst::DeclareFunctionStatement& node) + { + NazaraAssert(m_currentState, "This function should only be called while processing an AST"); + + std::optional varIndexOpt = node.varIndex; + + AppendAttributes(true, EntryAttribute{ node.entryStage }, EarlyFragmentTestsAttribute{ node.earlyFragmentTests }, DepthWriteAttribute{ node.depthWrite }); + Append("fn ", node.name, "("); + for (std::size_t i = 0; i < node.parameters.size(); ++i) + { + if (i != 0) + Append(", "); + + Append(node.parameters[i].name); + Append(": "); + Append(node.parameters[i].type); + + assert(varIndexOpt); + std::size_t& varIndex = *varIndexOpt; + RegisterVariable(varIndex++, node.parameters[i].name); + } + Append(")"); + if (!IsNoType(node.returnType)) + Append(" -> ", node.returnType); + + AppendLine(); + EnterScope(); + { + AppendStatementList(node.statements); + } + LeaveScope(); + } + + void LangWriter::Visit(ShaderAst::DeclareOptionStatement& node) + { + assert(node.optIndex); + RegisterOption(*node.optIndex, node.optName); + + Append("option ", node.optName, ": ", node.optType); + if (node.initialValue) + { + Append(" = "); + node.initialValue->Visit(*this); + } + + Append(";"); + } + + void LangWriter::Visit(ShaderAst::DeclareStructStatement& node) + { + assert(node.structIndex); + RegisterStruct(*node.structIndex, node.description); + + AppendAttributes(true, LayoutAttribute{ node.description.layout }); + Append("struct "); + AppendLine(node.description.name); + EnterScope(); + { + bool first = true; + for (const auto& member : node.description.members) + { + if (!first) + AppendLine(","); + + first = false; + + AppendAttributes(false, LocationAttribute{ member.locationIndex }, BuiltinAttribute{ member.builtin }); + Append(member.name, ": ", member.type); + } + } + LeaveScope(); + } + + void LangWriter::Visit(ShaderAst::DeclareVariableStatement& node) + { + assert(node.varIndex); + RegisterVariable(*node.varIndex, node.varName); + + Append("let ", node.varName, ": ", node.varType); + if (node.initialExpression) + { + Append(" = "); + node.initialExpression->Visit(*this); + } + + Append(";"); + } + + void LangWriter::Visit(ShaderAst::DiscardStatement& /*node*/) + { + Append("discard;"); + } + + void LangWriter::Visit(ShaderAst::ExpressionStatement& node) + { + node.expression->Visit(*this); + Append(";"); + } + + void LangWriter::Visit(ShaderAst::IntrinsicExpression& node) + { + bool method = false; + switch (node.intrinsic) + { + case ShaderAst::IntrinsicType::CrossProduct: + Append("cross"); + break; + + case ShaderAst::IntrinsicType::DotProduct: + Append("dot"); + break; + + case ShaderAst::IntrinsicType::Length: + Append("length"); + break; + + case ShaderAst::IntrinsicType::Max: + Append("max"); + break; + + case ShaderAst::IntrinsicType::Min: + Append("min"); + break; + + case ShaderAst::IntrinsicType::SampleTexture: + assert(!node.parameters.empty()); + Visit(node.parameters.front(), true); + Append(".Sample"); + method = true; + break; + } + + Append("("); + for (std::size_t i = (method) ? 1 : 0; i < node.parameters.size(); ++i) + { + if (i != 0) + Append(", "); + + node.parameters[i]->Visit(*this); + } + Append(")"); + } + + void LangWriter::Visit(ShaderAst::MultiStatement& node) + { + AppendStatementList(node.statements); + } + + void LangWriter::Visit(ShaderAst::NoOpStatement& /*node*/) + { + /* nothing to do */ + } + + void LangWriter::Visit(ShaderAst::ReturnStatement& node) + { + if (node.returnExpr) + { + Append("return "); + node.returnExpr->Visit(*this); + Append(";"); + } + else + Append("return;"); + } + + void LangWriter::Visit(ShaderAst::SwizzleExpression& node) + { + Visit(node.expression, true); + Append("."); + + for (std::size_t i = 0; i < node.componentCount; ++i) + { + switch (node.components[i]) + { + case ShaderAst::SwizzleComponent::First: + Append("x"); + break; + + case ShaderAst::SwizzleComponent::Second: + Append("y"); + break; + + case ShaderAst::SwizzleComponent::Third: + Append("z"); + break; + + case ShaderAst::SwizzleComponent::Fourth: + Append("w"); + break; + } + } + } + + void LangWriter::Visit(ShaderAst::VariableExpression& node) + { + const std::string& varName = Retrieve(m_currentState->variableNames, node.variableId); + Append(varName); + } + + void LangWriter::Visit(ShaderAst::UnaryExpression& node) + { + switch (node.op) + { + case ShaderAst::UnaryType::LogicalNot: + Append("!"); + break; + + case ShaderAst::UnaryType::Minus: + Append("-"); + break; + + case ShaderAst::UnaryType::Plus: + Append("+"); + break; + } + + node.expression->Visit(*this); + } + + void LangWriter::AppendHeader() + { + // Nothing yet + } +} diff --git a/src/Nazara/Shader/ShaderAst.cpp b/src/Nazara/Shader/ShaderAst.cpp deleted file mode 100644 index 236a5e28f..000000000 --- a/src/Nazara/Shader/ShaderAst.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include - -namespace Nz -{ - void ShaderAst::AddFunction(std::string name, ShaderNodes::StatementPtr statement, std::vector parameters, ShaderNodes::BasicType returnType) - { - auto& functionEntry = m_functions.emplace_back(); - functionEntry.name = std::move(name); - functionEntry.parameters = std::move(parameters); - functionEntry.returnType = returnType; - functionEntry.statement = std::move(statement); - } - - void ShaderAst::AddInput(std::string name, ShaderExpressionType type, std::optional locationIndex) - { - auto& inputEntry = m_inputs.emplace_back(); - inputEntry.name = std::move(name); - inputEntry.locationIndex = std::move(locationIndex); - inputEntry.type = std::move(type); - } - - void ShaderAst::AddOutput(std::string name, ShaderExpressionType type, std::optional locationIndex) - { - auto& outputEntry = m_outputs.emplace_back(); - outputEntry.name = std::move(name); - outputEntry.locationIndex = std::move(locationIndex); - outputEntry.type = std::move(type); - } - - void ShaderAst::AddStruct(std::string name, std::vector members) - { - auto& structEntry = m_structs.emplace_back(); - structEntry.name = std::move(name); - structEntry.members = std::move(members); - } - - void ShaderAst::AddUniform(std::string name, ShaderExpressionType type, std::optional bindingIndex, std::optional memoryLayout) - { - auto& uniformEntry = m_uniforms.emplace_back(); - uniformEntry.bindingIndex = std::move(bindingIndex); - uniformEntry.memoryLayout = std::move(memoryLayout); - uniformEntry.name = std::move(name); - uniformEntry.type = std::move(type); - } -} diff --git a/src/Nazara/Shader/ShaderAstCloner.cpp b/src/Nazara/Shader/ShaderAstCloner.cpp deleted file mode 100644 index 90c7c909d..000000000 --- a/src/Nazara/Shader/ShaderAstCloner.cpp +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include -#include - -namespace Nz -{ - ShaderNodes::StatementPtr ShaderAstCloner::Clone(const ShaderNodes::StatementPtr& statement) - { - ShaderAstVisitor::Visit(statement); - - if (!m_expressionStack.empty() || !m_variableStack.empty() || m_statementStack.size() != 1) - throw std::runtime_error("An error occurred during clone"); - - return PopStatement(); - } - - ShaderNodes::ExpressionPtr ShaderAstCloner::CloneExpression(const ShaderNodes::ExpressionPtr& expr) - { - if (!expr) - return nullptr; - - ShaderAstVisitor::Visit(expr); - return PopExpression(); - } - - ShaderNodes::StatementPtr ShaderAstCloner::CloneStatement(const ShaderNodes::StatementPtr& statement) - { - if (!statement) - return nullptr; - - ShaderAstVisitor::Visit(statement); - return PopStatement(); - } - - ShaderNodes::VariablePtr ShaderAstCloner::CloneVariable(const ShaderNodes::VariablePtr& variable) - { - if (!variable) - return nullptr; - - ShaderVarVisitor::Visit(variable); - return PopVariable(); - } - - void ShaderAstCloner::Visit(ShaderNodes::AccessMember& node) - { - PushExpression(ShaderNodes::AccessMember::Build(CloneExpression(node.structExpr), node.memberIndices, node.exprType)); - } - - void ShaderAstCloner::Visit(ShaderNodes::AssignOp& node) - { - PushExpression(ShaderNodes::AssignOp::Build(node.op, CloneExpression(node.left), CloneExpression(node.right))); - } - - void ShaderAstCloner::Visit(ShaderNodes::BinaryOp& node) - { - PushExpression(ShaderNodes::BinaryOp::Build(node.op, CloneExpression(node.left), CloneExpression(node.right))); - } - - void ShaderAstCloner::Visit(ShaderNodes::Branch& node) - { - std::vector condStatements; - condStatements.reserve(node.condStatements.size()); - - for (auto& cond : node.condStatements) - { - auto& condStatement = condStatements.emplace_back(); - condStatement.condition = CloneExpression(cond.condition); - condStatement.statement = CloneStatement(cond.statement); - } - - PushStatement(ShaderNodes::Branch::Build(std::move(condStatements), CloneStatement(node.elseStatement))); - } - - void ShaderAstCloner::Visit(ShaderNodes::Cast& node) - { - std::size_t expressionCount = 0; - std::array expressions; - for (auto& expr : node.expressions) - { - if (!expr) - break; - - expressions[expressionCount] = CloneExpression(expr); - expressionCount++; - } - - PushExpression(ShaderNodes::Cast::Build(node.exprType, expressions.data(), expressionCount)); - } - - void ShaderAstCloner::Visit(ShaderNodes::Constant& node) - { - PushExpression(ShaderNodes::Constant::Build(node.value)); - } - - void ShaderAstCloner::Visit(ShaderNodes::DeclareVariable& node) - { - PushStatement(ShaderNodes::DeclareVariable::Build(CloneVariable(node.variable), CloneExpression(node.expression))); - } - - void ShaderAstCloner::Visit(ShaderNodes::ExpressionStatement& node) - { - PushStatement(ShaderNodes::ExpressionStatement::Build(CloneExpression(node.expression))); - } - - void ShaderAstCloner::Visit(ShaderNodes::Identifier& node) - { - PushExpression(ShaderNodes::Identifier::Build(CloneVariable(node.var))); - } - - void ShaderAstCloner::Visit(ShaderNodes::IntrinsicCall& node) - { - std::vector parameters; - parameters.reserve(node.parameters.size()); - - for (auto& parameter : node.parameters) - parameters.push_back(CloneExpression(parameter)); - - PushExpression(ShaderNodes::IntrinsicCall::Build(node.intrinsic, std::move(parameters))); - } - - void ShaderAstCloner::Visit(ShaderNodes::Sample2D& node) - { - PushExpression(ShaderNodes::Sample2D::Build(CloneExpression(node.sampler), CloneExpression(node.coordinates))); - } - - void ShaderAstCloner::Visit(ShaderNodes::StatementBlock& node) - { - std::vector statements; - statements.reserve(node.statements.size()); - - for (auto& statement : node.statements) - statements.push_back(CloneStatement(statement)); - - PushStatement(ShaderNodes::StatementBlock::Build(std::move(statements))); - } - - void ShaderAstCloner::Visit(ShaderNodes::SwizzleOp& node) - { - PushExpression(ShaderNodes::SwizzleOp::Build(CloneExpression(node.expression), node.components.data(), node.componentCount)); - } - - void ShaderAstCloner::Visit(ShaderNodes::BuiltinVariable& var) - { - PushVariable(ShaderNodes::BuiltinVariable::Build(var.entry, var.type)); - } - - void ShaderAstCloner::Visit(ShaderNodes::InputVariable& var) - { - PushVariable(ShaderNodes::InputVariable::Build(var.name, var.type)); - } - - void ShaderAstCloner::Visit(ShaderNodes::LocalVariable& var) - { - PushVariable(ShaderNodes::LocalVariable::Build(var.name, var.type)); - } - - void ShaderAstCloner::Visit(ShaderNodes::OutputVariable& var) - { - PushVariable(ShaderNodes::OutputVariable::Build(var.name, var.type)); - } - - void ShaderAstCloner::Visit(ShaderNodes::ParameterVariable& var) - { - PushVariable(ShaderNodes::ParameterVariable::Build(var.name, var.type)); - } - - void ShaderAstCloner::Visit(ShaderNodes::UniformVariable& var) - { - PushVariable(ShaderNodes::UniformVariable::Build(var.name, var.type)); - } - - void ShaderAstCloner::PushExpression(ShaderNodes::ExpressionPtr expression) - { - m_expressionStack.emplace_back(std::move(expression)); - } - - void ShaderAstCloner::PushStatement(ShaderNodes::StatementPtr statement) - { - m_statementStack.emplace_back(std::move(statement)); - } - - void ShaderAstCloner::PushVariable(ShaderNodes::VariablePtr variable) - { - m_variableStack.emplace_back(std::move(variable)); - } - - ShaderNodes::ExpressionPtr ShaderAstCloner::PopExpression() - { - assert(!m_expressionStack.empty()); - - ShaderNodes::ExpressionPtr expr = std::move(m_expressionStack.back()); - m_expressionStack.pop_back(); - - return expr; - } - - ShaderNodes::StatementPtr ShaderAstCloner::PopStatement() - { - assert(!m_statementStack.empty()); - - ShaderNodes::StatementPtr expr = std::move(m_statementStack.back()); - m_statementStack.pop_back(); - - return expr; - } - - ShaderNodes::VariablePtr ShaderAstCloner::PopVariable() - { - assert(!m_variableStack.empty()); - - ShaderNodes::VariablePtr var = std::move(m_variableStack.back()); - m_variableStack.pop_back(); - - return var; - } -} diff --git a/src/Nazara/Shader/ShaderAstRecursiveVisitor.cpp b/src/Nazara/Shader/ShaderAstRecursiveVisitor.cpp deleted file mode 100644 index 98fdbfee6..000000000 --- a/src/Nazara/Shader/ShaderAstRecursiveVisitor.cpp +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include - -namespace Nz -{ - void ShaderAstRecursiveVisitor::Visit(ShaderNodes::AccessMember& node) - { - Visit(node.structExpr); - } - - void ShaderAstRecursiveVisitor::Visit(ShaderNodes::AssignOp& node) - { - Visit(node.left); - Visit(node.right); - } - - void ShaderAstRecursiveVisitor::Visit(ShaderNodes::BinaryOp& node) - { - Visit(node.left); - Visit(node.right); - } - - void ShaderAstRecursiveVisitor::Visit(ShaderNodes::Branch& node) - { - for (auto& cond : node.condStatements) - { - Visit(cond.condition); - Visit(cond.statement); - } - - if (node.elseStatement) - Visit(node.elseStatement); - } - - void ShaderAstRecursiveVisitor::Visit(ShaderNodes::Cast& node) - { - for (auto& expr : node.expressions) - { - if (!expr) - break; - - Visit(expr); - } - } - - void ShaderAstRecursiveVisitor::Visit(ShaderNodes::Constant& /*node*/) - { - /* Nothing to do */ - } - - void ShaderAstRecursiveVisitor::Visit(ShaderNodes::DeclareVariable& node) - { - if (node.expression) - Visit(node.expression); - } - - void ShaderAstRecursiveVisitor::Visit(ShaderNodes::ExpressionStatement& node) - { - Visit(node.expression); - } - - void ShaderAstRecursiveVisitor::Visit(ShaderNodes::Identifier& /*node*/) - { - /* Nothing to do */ - } - - void ShaderAstRecursiveVisitor::Visit(ShaderNodes::IntrinsicCall& node) - { - for (auto& param : node.parameters) - Visit(param); - } - - void ShaderAstRecursiveVisitor::Visit(ShaderNodes::Sample2D& node) - { - Visit(node.sampler); - Visit(node.coordinates); - } - - void ShaderAstRecursiveVisitor::Visit(ShaderNodes::StatementBlock& node) - { - for (auto& statement : node.statements) - Visit(statement); - } - - void ShaderAstRecursiveVisitor::Visit(ShaderNodes::SwizzleOp& node) - { - Visit(node.expression); - } -} diff --git a/src/Nazara/Shader/ShaderAstSerializer.cpp b/src/Nazara/Shader/ShaderAstSerializer.cpp deleted file mode 100644 index 4e767540b..000000000 --- a/src/Nazara/Shader/ShaderAstSerializer.cpp +++ /dev/null @@ -1,781 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include -#include -#include - -namespace Nz -{ - namespace - { - constexpr UInt32 s_magicNumber = 0x4E534852; - constexpr UInt32 s_currentVersion = 1; - - class ShaderSerializerVisitor : public ShaderAstVisitor, public ShaderVarVisitor - { - public: - ShaderSerializerVisitor(ShaderAstSerializerBase& serializer) : - m_serializer(serializer) - { - } - - void Visit(ShaderNodes::AccessMember& node) override - { - Serialize(node); - } - - void Visit(ShaderNodes::AssignOp& node) override - { - Serialize(node); - } - - void Visit(ShaderNodes::BinaryOp& node) override - { - Serialize(node); - } - - void Visit(ShaderNodes::Branch& node) override - { - Serialize(node); - } - - void Visit(ShaderNodes::Cast& node) override - { - Serialize(node); - } - - void Visit(ShaderNodes::Constant& node) override - { - Serialize(node); - } - - void Visit(ShaderNodes::DeclareVariable& node) override - { - Serialize(node); - } - - void Visit(ShaderNodes::ExpressionStatement& node) override - { - Serialize(node); - } - - void Visit(ShaderNodes::Identifier& node) override - { - Serialize(node); - } - - void Visit(ShaderNodes::IntrinsicCall& node) override - { - Serialize(node); - } - - void Visit(ShaderNodes::Sample2D& node) override - { - Serialize(node); - } - - void Visit(ShaderNodes::StatementBlock& node) override - { - Serialize(node); - } - - void Visit(ShaderNodes::SwizzleOp& node) override - { - Serialize(node); - } - - - void Visit(ShaderNodes::BuiltinVariable& var) override - { - Serialize(var); - } - - void Visit(ShaderNodes::InputVariable& var) override - { - Serialize(var); - } - - void Visit(ShaderNodes::LocalVariable& var) override - { - Serialize(var); - } - - void Visit(ShaderNodes::OutputVariable& var) override - { - Serialize(var); - } - - void Visit(ShaderNodes::ParameterVariable& var) override - { - Serialize(var); - } - - void Visit(ShaderNodes::UniformVariable& var) override - { - Serialize(var); - } - - private: - template - void Serialize(const T& node) - { - // I know const_cast is evil but I don't have a better solution here (it's not used to write) - m_serializer.Serialize(const_cast(node)); - } - - ShaderAstSerializerBase& m_serializer; - }; - } - - void ShaderAstSerializerBase::Serialize(ShaderNodes::AccessMember& node) - { - Node(node.structExpr); - Type(node.exprType); - - Container(node.memberIndices); - for (std::size_t& index : node.memberIndices) - SizeT(index); - } - - void ShaderAstSerializerBase::Serialize(ShaderNodes::AssignOp& node) - { - Enum(node.op); - Node(node.left); - Node(node.right); - } - - void ShaderAstSerializerBase::Serialize(ShaderNodes::BinaryOp& node) - { - Enum(node.op); - Node(node.left); - Node(node.right); - } - - void ShaderAstSerializerBase::Serialize(ShaderNodes::Branch& node) - { - Container(node.condStatements); - for (auto& condStatement : node.condStatements) - { - Node(condStatement.condition); - Node(condStatement.statement); - } - - Node(node.elseStatement); - } - - void ShaderAstSerializerBase::Serialize(ShaderNodes::BuiltinVariable& node) - { - Enum(node.entry); - Type(node.type); - } - - void ShaderAstSerializerBase::Serialize(ShaderNodes::Cast& node) - { - Enum(node.exprType); - for (auto& expr : node.expressions) - Node(expr); - } - - void ShaderAstSerializerBase::Serialize(ShaderNodes::Constant& node) - { - UInt32 typeIndex; - if (IsWriting()) - typeIndex = UInt32(node.value.index()); - - Value(typeIndex); - - // Waiting for template lambda in C++20 - auto SerializeValue = [&](auto dummyType) - { - using T = std::decay_t; - - auto& value = (IsWriting()) ? std::get(node.value) : node.value.emplace(); - Value(value); - }; - - static_assert(std::variant_size_v == 10); - switch (typeIndex) - { - case 0: SerializeValue(bool()); break; - case 1: SerializeValue(float()); break; - case 2: SerializeValue(Int32()); break; - case 3: SerializeValue(UInt32()); break; - case 4: SerializeValue(Vector2f()); break; - case 5: SerializeValue(Vector3f()); break; - case 6: SerializeValue(Vector4f()); break; - case 7: SerializeValue(Vector2i32()); break; - case 8: SerializeValue(Vector3i32()); break; - case 9: SerializeValue(Vector4i32()); break; - default: throw std::runtime_error("unexpected data type"); - } - } - - void ShaderAstSerializerBase::Serialize(ShaderNodes::DeclareVariable& node) - { - Variable(node.variable); - Node(node.expression); - } - - void ShaderAstSerializerBase::Serialize(ShaderNodes::ExpressionStatement& node) - { - Node(node.expression); - } - - void ShaderAstSerializerBase::Serialize(ShaderNodes::Identifier& node) - { - Variable(node.var); - } - - void ShaderAstSerializerBase::Serialize(ShaderNodes::IntrinsicCall& node) - { - Enum(node.intrinsic); - Container(node.parameters); - for (auto& param : node.parameters) - Node(param); - } - - void ShaderAstSerializerBase::Serialize(ShaderNodes::NamedVariable& node) - { - Value(node.name); - Type(node.type); - } - - void ShaderAstSerializerBase::Serialize(ShaderNodes::Sample2D& node) - { - Node(node.sampler); - Node(node.coordinates); - } - - void ShaderAstSerializerBase::Serialize(ShaderNodes::StatementBlock& node) - { - Container(node.statements); - for (auto& statement : node.statements) - Node(statement); - } - - void ShaderAstSerializerBase::Serialize(ShaderNodes::SwizzleOp& node) - { - SizeT(node.componentCount); - Node(node.expression); - - for (std::size_t i = 0; i < node.componentCount; ++i) - Enum(node.components[i]); - } - - - void ShaderAstSerializer::Serialize(const ShaderAst& shader) - { - m_stream << s_magicNumber << s_currentVersion; - - m_stream << UInt32(shader.GetStage()); - - auto SerializeType = [&](const ShaderExpressionType& type) - { - std::visit([&](auto&& arg) - { - using T = std::decay_t; - if constexpr (std::is_same_v) - { - m_stream << UInt8(0); - m_stream << UInt32(arg); - } - else if constexpr (std::is_same_v) - { - m_stream << UInt8(1); - m_stream << arg; - } - else - static_assert(AlwaysFalse::value, "non-exhaustive visitor"); - }, type); - }; - - auto SerializeInputOutput = [&](auto& inout) - { - m_stream << UInt32(inout.size()); - for (const auto& data : inout) - { - m_stream << data.name; - SerializeType(data.type); - - m_stream << data.locationIndex.has_value(); - if (data.locationIndex) - m_stream << UInt32(data.locationIndex.value()); - } - }; - - m_stream << UInt32(shader.GetStructCount()); - for (const auto& s : shader.GetStructs()) - { - m_stream << s.name; - m_stream << UInt32(s.members.size()); - for (const auto& member : s.members) - { - m_stream << member.name; - SerializeType(member.type); - } - } - - SerializeInputOutput(shader.GetInputs()); - SerializeInputOutput(shader.GetOutputs()); - - m_stream << UInt32(shader.GetUniformCount()); - for (const auto& uniform : shader.GetUniforms()) - { - m_stream << uniform.name; - SerializeType(uniform.type); - - m_stream << uniform.bindingIndex.has_value(); - if (uniform.bindingIndex) - m_stream << UInt32(uniform.bindingIndex.value()); - - m_stream << uniform.memoryLayout.has_value(); - if (uniform.memoryLayout) - m_stream << UInt32(uniform.memoryLayout.value()); - } - - m_stream << UInt32(shader.GetFunctionCount()); - for (const auto& func : shader.GetFunctions()) - { - m_stream << func.name << UInt32(func.returnType); - - m_stream << UInt32(func.parameters.size()); - for (const auto& param : func.parameters) - { - m_stream << param.name; - SerializeType(param.type); - } - - Node(func.statement); - } - - m_stream.FlushBits(); - } - - bool ShaderAstSerializer::IsWriting() const - { - return true; - } - - void ShaderAstSerializer::Node(ShaderNodes::NodePtr& node) - { - ShaderNodes::NodeType nodeType = (node) ? node->GetType() : ShaderNodes::NodeType::None; - m_stream << static_cast(nodeType); - - if (node) - { - ShaderSerializerVisitor visitor(*this); - node->Visit(visitor); - } - } - - void ShaderAstSerializer::Type(ShaderExpressionType& type) - { - std::visit([&](auto&& arg) - { - using T = std::decay_t; - if constexpr (std::is_same_v) - { - m_stream << UInt8(0); - m_stream << UInt32(arg); - } - else if constexpr (std::is_same_v) - { - m_stream << UInt8(1); - m_stream << arg; - } - else - static_assert(AlwaysFalse::value, "non-exhaustive visitor"); - }, type); - } - - void ShaderAstSerializer::Node(const ShaderNodes::NodePtr& node) - { - Node(const_cast(node)); //< Yes const_cast is ugly but it won't be used for writing - } - - void ShaderAstSerializer::Value(bool& val) - { - m_stream << val; - } - - void ShaderAstSerializer::Value(float& val) - { - m_stream << val; - } - - void ShaderAstSerializer::Value(std::string& val) - { - m_stream << val; - } - - void ShaderAstSerializer::Value(Int32& val) - { - m_stream << val; - } - - void ShaderAstSerializer::Value(Vector2f& val) - { - m_stream << val; - } - - void ShaderAstSerializer::Value(Vector3f& val) - { - m_stream << val; - } - - void ShaderAstSerializer::Value(Vector4f& val) - { - m_stream << val; - } - - void ShaderAstSerializer::Value(Vector2i32& val) - { - m_stream << val; - } - - void ShaderAstSerializer::Value(Vector3i32& val) - { - m_stream << val; - } - - void ShaderAstSerializer::Value(Vector4i32& val) - { - m_stream << val; - } - - void ShaderAstSerializer::Value(UInt8& val) - { - m_stream << val; - } - - void ShaderAstSerializer::Value(UInt16& val) - { - m_stream << val; - } - - void ShaderAstSerializer::Value(UInt32& val) - { - m_stream << val; - } - - void ShaderAstSerializer::Value(UInt64& val) - { - m_stream << val; - } - - void ShaderAstSerializer::Variable(ShaderNodes::VariablePtr& var) - { - ShaderNodes::VariableType nodeType = (var) ? var->GetType() : ShaderNodes::VariableType::None; - m_stream << static_cast(nodeType); - - if (var) - { - ShaderSerializerVisitor visitor(*this); - var->Visit(visitor); - } - } - - ShaderAst ShaderAstUnserializer::Unserialize() - { - UInt32 magicNumber; - UInt32 version; - m_stream >> magicNumber; - if (magicNumber != s_magicNumber) - throw std::runtime_error("invalid shader file"); - - m_stream >> version; - if (version > s_currentVersion) - throw std::runtime_error("unsupported version"); - - UInt32 shaderStage; - m_stream >> shaderStage; - - ShaderAst shader(static_cast(shaderStage)); - - UInt32 structCount; - m_stream >> structCount; - for (UInt32 i = 0; i < structCount; ++i) - { - std::string structName; - std::vector members; - - Value(structName); - Container(members); - - for (auto& member : members) - { - Value(member.name); - Type(member.type); - } - - shader.AddStruct(std::move(structName), std::move(members)); - } - - UInt32 inputCount; - m_stream >> inputCount; - for (UInt32 i = 0; i < inputCount; ++i) - { - std::string inputName; - ShaderExpressionType inputType; - std::optional location; - - Value(inputName); - Type(inputType); - OptVal(location); - - shader.AddInput(std::move(inputName), std::move(inputType), location); - } - - UInt32 outputCount; - m_stream >> outputCount; - for (UInt32 i = 0; i < outputCount; ++i) - { - std::string outputName; - ShaderExpressionType outputType; - std::optional location; - - Value(outputName); - Type(outputType); - OptVal(location); - - shader.AddOutput(std::move(outputName), std::move(outputType), location); - } - - UInt32 uniformCount; - m_stream >> uniformCount; - for (UInt32 i = 0; i < uniformCount; ++i) - { - std::string name; - ShaderExpressionType type; - std::optional binding; - std::optional memLayout; - - Value(name); - Type(type); - OptVal(binding); - OptEnum(memLayout); - - shader.AddUniform(std::move(name), std::move(type), std::move(binding), std::move(memLayout)); - } - - UInt32 funcCount; - m_stream >> funcCount; - for (UInt32 i = 0; i < funcCount; ++i) - { - std::string name; - ShaderNodes::BasicType retType; - std::vector parameters; - - Value(name); - Enum(retType); - Container(parameters); - for (auto& param : parameters) - { - Value(param.name); - Type(param.type); - } - - ShaderNodes::NodePtr node; - Node(node); - if (!node || !node->IsStatement()) - throw std::runtime_error("functions can only have statements"); - - ShaderNodes::StatementPtr statement = std::static_pointer_cast(node); - - shader.AddFunction(std::move(name), std::move(statement), std::move(parameters), retType); - } - - return shader; - } - - bool ShaderAstUnserializer::IsWriting() const - { - return false; - } - - void ShaderAstUnserializer::Node(ShaderNodes::NodePtr& node) - { - Int32 nodeTypeInt; - m_stream >> nodeTypeInt; - - ShaderNodes::NodeType nodeType = static_cast(nodeTypeInt); - -#define HandleType(Type) case ShaderNodes::NodeType:: Type : node = std::make_shared(); break - switch (nodeType) - { - case ShaderNodes::NodeType::None: break; - - HandleType(AccessMember); - HandleType(AssignOp); - HandleType(BinaryOp); - HandleType(Branch); - HandleType(Cast); - HandleType(Constant); - HandleType(ConditionalStatement); - HandleType(DeclareVariable); - HandleType(ExpressionStatement); - HandleType(Identifier); - HandleType(IntrinsicCall); - HandleType(Sample2D); - HandleType(SwizzleOp); - HandleType(StatementBlock); - } -#undef HandleType - - if (node) - { - ShaderSerializerVisitor visitor(*this); - node->Visit(visitor); - } - } - - void ShaderAstUnserializer::Type(ShaderExpressionType& type) - { - UInt8 typeIndex; - Value(typeIndex); - - switch (typeIndex) - { - case 0: //< Primitive - { - ShaderNodes::BasicType exprType; - Enum(exprType); - - type = exprType; - break; - } - - case 1: //< Struct (name) - { - std::string structName; - Value(structName); - - type = std::move(structName); - break; - } - - default: - break; - } - } - - void ShaderAstUnserializer::Value(bool& val) - { - m_stream >> val; - } - - void ShaderAstUnserializer::Value(float& val) - { - m_stream >> val; - } - - void ShaderAstUnserializer::Value(std::string& val) - { - m_stream >> val; - } - - void ShaderAstUnserializer::Value(Int32& val) - { - m_stream >> val; - } - - void ShaderAstUnserializer::Value(Vector2f& val) - { - m_stream >> val; - } - - void ShaderAstUnserializer::Value(Vector3f& val) - { - m_stream >> val; - } - - void ShaderAstUnserializer::Value(Vector4f& val) - { - m_stream >> val; - } - - void ShaderAstUnserializer::Value(Vector2i32& val) - { - m_stream >> val; - } - - void ShaderAstUnserializer::Value(Vector3i32& val) - { - m_stream >> val; - } - - void ShaderAstUnserializer::Value(Vector4i32& val) - { - m_stream >> val; - } - - void ShaderAstUnserializer::Value(UInt8& val) - { - m_stream >> val; - } - - void ShaderAstUnserializer::Value(UInt16& val) - { - m_stream >> val; - } - - void ShaderAstUnserializer::Value(UInt32& val) - { - m_stream >> val; - } - - void ShaderAstUnserializer::Value(UInt64& val) - { - m_stream >> val; - } - - void ShaderAstUnserializer::Variable(ShaderNodes::VariablePtr& var) - { - Int32 nodeTypeInt; - m_stream >> nodeTypeInt; - - ShaderNodes::VariableType nodeType = static_cast(nodeTypeInt); - -#define HandleType(Type) case ShaderNodes::VariableType:: Type : var = std::make_shared(); break - switch (nodeType) - { - case ShaderNodes::VariableType::None: break; - - HandleType(BuiltinVariable); - HandleType(InputVariable); - HandleType(LocalVariable); - HandleType(ParameterVariable); - HandleType(OutputVariable); - HandleType(UniformVariable); - } -#undef HandleType - - if (var) - { - ShaderSerializerVisitor visitor(*this); - var->Visit(visitor); - } - } - - - ByteArray SerializeShader(const ShaderAst& shader) - { - ByteArray byteArray; - ByteStream stream(&byteArray, OpenModeFlags(OpenMode_WriteOnly)); - - ShaderAstSerializer serializer(stream); - serializer.Serialize(shader); - - return byteArray; - } - - ShaderAst UnserializeShader(ByteStream& stream) - { - ShaderAstUnserializer unserializer(stream); - return unserializer.Unserialize(); - } -} - diff --git a/src/Nazara/Shader/ShaderAstValidator.cpp b/src/Nazara/Shader/ShaderAstValidator.cpp deleted file mode 100644 index 95ae20df0..000000000 --- a/src/Nazara/Shader/ShaderAstValidator.cpp +++ /dev/null @@ -1,467 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include -#include -#include -#include -#include - -namespace Nz -{ - struct AstError - { - std::string errMsg; - }; - - struct ShaderAstValidator::Context - { - struct Local - { - std::string name; - ShaderExpressionType type; - }; - - const ShaderAst::Function* currentFunction; - std::vector declaredLocals; - std::vector blockLocalIndex; - }; - - bool ShaderAstValidator::Validate(std::string* error) - { - try - { - for (std::size_t i = 0; i < m_shader.GetFunctionCount(); ++i) - { - const auto& func = m_shader.GetFunction(i); - - Context currentContext; - currentContext.currentFunction = &func; - - m_context = ¤tContext; - CallOnExit resetContext([&] { m_context = nullptr; }); - - func.statement->Visit(*this); - } - - return true; - } - catch (const AstError& e) - { - if (error) - *error = e.errMsg; - - return false; - } - } - - const ShaderNodes::ExpressionPtr& ShaderAstValidator::MandatoryExpr(const ShaderNodes::ExpressionPtr& node) - { - MandatoryNode(node); - - return node; - } - - const ShaderNodes::NodePtr& ShaderAstValidator::MandatoryNode(const ShaderNodes::NodePtr& node) - { - if (!node) - throw AstError{ "Invalid node" }; - - return node; - } - - void ShaderAstValidator::TypeMustMatch(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right) - { - return TypeMustMatch(left->GetExpressionType(), right->GetExpressionType()); - } - - void ShaderAstValidator::TypeMustMatch(const ShaderExpressionType& left, const ShaderExpressionType& right) - { - if (left != right) - throw AstError{ "Left expression type must match right expression type" }; - } - - const ShaderAst::StructMember& ShaderAstValidator::CheckField(const std::string& structName, std::size_t* memberIndex, std::size_t remainingMembers) - { - const auto& structs = m_shader.GetStructs(); - auto it = std::find_if(structs.begin(), structs.end(), [&](const auto& s) { return s.name == structName; }); - if (it == structs.end()) - throw AstError{ "invalid structure" }; - - const ShaderAst::Struct& s = *it; - if (*memberIndex >= s.members.size()) - throw AstError{ "member index out of bounds" }; - - const auto& member = s.members[*memberIndex]; - - if (remainingMembers > 1) - { - if (!IsStructType(member.type)) - throw AstError{ "member type does not match node type" }; - - return CheckField(std::get(member.type), memberIndex + 1, remainingMembers - 1); - } - else - return member; - } - - void ShaderAstValidator::Visit(ShaderNodes::AccessMember& node) - { - const ShaderExpressionType& exprType = MandatoryExpr(node.structExpr)->GetExpressionType(); - if (!IsStructType(exprType)) - throw AstError{ "expression is not a structure" }; - - const std::string& structName = std::get(exprType); - - const auto& member = CheckField(structName, node.memberIndices.data(), node.memberIndices.size()); - if (member.type != node.exprType) - throw AstError{ "member type does not match node type" }; - } - - void ShaderAstValidator::Visit(ShaderNodes::AssignOp& node) - { - MandatoryNode(node.left); - MandatoryNode(node.right); - TypeMustMatch(node.left, node.right); - - if (node.left->GetExpressionCategory() != ShaderNodes::ExpressionCategory::LValue) - throw AstError { "Assignation is only possible with a l-value" }; - - ShaderAstRecursiveVisitor::Visit(node); - } - - void ShaderAstValidator::Visit(ShaderNodes::BinaryOp& node) - { - MandatoryNode(node.left); - MandatoryNode(node.right); - - const ShaderExpressionType& leftExprType = MandatoryExpr(node.left)->GetExpressionType(); - if (!IsBasicType(leftExprType)) - throw AstError{ "left expression type does not support binary operation" }; - - const ShaderExpressionType& rightExprType = MandatoryExpr(node.right)->GetExpressionType(); - if (!IsBasicType(rightExprType)) - throw AstError{ "right expression type does not support binary operation" }; - - ShaderNodes::BasicType leftType = std::get(leftExprType); - ShaderNodes::BasicType rightType = std::get(rightExprType); - - switch (node.op) - { - case ShaderNodes::BinaryType::Add: - case ShaderNodes::BinaryType::Equality: - case ShaderNodes::BinaryType::Substract: - TypeMustMatch(node.left, node.right); - break; - - case ShaderNodes::BinaryType::Multiply: - case ShaderNodes::BinaryType::Divide: - { - switch (leftType) - { - case ShaderNodes::BasicType::Float1: - case ShaderNodes::BasicType::Int1: - { - if (ShaderNodes::Node::GetComponentType(rightType) != leftType) - throw AstError{ "Left expression type is not compatible with right expression type" }; - - break; - } - - case ShaderNodes::BasicType::Float2: - case ShaderNodes::BasicType::Float3: - case ShaderNodes::BasicType::Float4: - case ShaderNodes::BasicType::Int2: - case ShaderNodes::BasicType::Int3: - case ShaderNodes::BasicType::Int4: - { - if (leftType != rightType && rightType != ShaderNodes::Node::GetComponentType(leftType)) - throw AstError{ "Left expression type is not compatible with right expression type" }; - - break; - } - - case ShaderNodes::BasicType::Mat4x4: - { - switch (rightType) - { - case ShaderNodes::BasicType::Float1: - case ShaderNodes::BasicType::Float4: - case ShaderNodes::BasicType::Mat4x4: - break; - - default: - TypeMustMatch(node.left, node.right); - } - - break; - } - - default: - TypeMustMatch(node.left, node.right); - } - } - } - - ShaderAstRecursiveVisitor::Visit(node); - } - - void ShaderAstValidator::Visit(ShaderNodes::Branch& node) - { - for (const auto& condStatement : node.condStatements) - { - MandatoryNode(condStatement.condition); - MandatoryNode(condStatement.statement); - } - - ShaderAstRecursiveVisitor::Visit(node); - } - - void ShaderAstValidator::Visit(ShaderNodes::Cast& node) - { - unsigned int componentCount = 0; - unsigned int requiredComponents = node.GetComponentCount(node.exprType); - for (const auto& exprPtr : node.expressions) - { - if (!exprPtr) - break; - - const ShaderExpressionType& exprType = exprPtr->GetExpressionType(); - if (!IsBasicType(exprType)) - throw AstError{ "incompatible type" }; - - componentCount += node.GetComponentCount(std::get(exprType)); - } - - if (componentCount != requiredComponents) - throw AstError{ "Component count doesn't match required component count" }; - - ShaderAstRecursiveVisitor::Visit(node); - } - - void ShaderAstValidator::Visit(ShaderNodes::Constant& /*node*/) - { - } - - void ShaderAstValidator::Visit(ShaderNodes::DeclareVariable& node) - { - assert(m_context); - - if (node.variable->GetType() != ShaderNodes::VariableType::LocalVariable) - throw AstError{ "Only local variables can be declared in a statement" }; - - const auto& localVar = static_cast(*node.variable); - - auto& local = m_context->declaredLocals.emplace_back(); - local.name = localVar.name; - local.type = localVar.type; - - ShaderAstRecursiveVisitor::Visit(node); - } - - void ShaderAstValidator::Visit(ShaderNodes::ExpressionStatement& node) - { - MandatoryNode(node.expression); - - ShaderAstRecursiveVisitor::Visit(node); - } - - void ShaderAstValidator::Visit(ShaderNodes::Identifier& node) - { - assert(m_context); - - if (!node.var) - throw AstError{ "Invalid variable" }; - - Visit(node.var); - } - - void ShaderAstValidator::Visit(ShaderNodes::IntrinsicCall& node) - { - switch (node.intrinsic) - { - case ShaderNodes::IntrinsicType::CrossProduct: - case ShaderNodes::IntrinsicType::DotProduct: - { - if (node.parameters.size() != 2) - throw AstError { "Expected 2 parameters" }; - - for (auto& param : node.parameters) - MandatoryNode(param); - - ShaderExpressionType type = node.parameters.front()->GetExpressionType(); - for (std::size_t i = 1; i < node.parameters.size(); ++i) - { - if (type != node.parameters[i]->GetExpressionType()) - throw AstError{ "All type must match" }; - } - - break; - } - } - - switch (node.intrinsic) - { - case ShaderNodes::IntrinsicType::CrossProduct: - { - if (node.parameters[0]->GetExpressionType() != ShaderExpressionType{ ShaderNodes::BasicType::Float3 }) - throw AstError{ "CrossProduct only works with Float3 expressions" }; - - break; - } - - case ShaderNodes::IntrinsicType::DotProduct: - break; - } - - ShaderAstRecursiveVisitor::Visit(node); - } - - void ShaderAstValidator::Visit(ShaderNodes::Sample2D& node) - { - if (MandatoryExpr(node.sampler)->GetExpressionType() != ShaderExpressionType{ ShaderNodes::BasicType::Sampler2D }) - throw AstError{ "Sampler must be a Sampler2D" }; - - if (MandatoryExpr(node.coordinates)->GetExpressionType() != ShaderExpressionType{ ShaderNodes::BasicType::Float2 }) - throw AstError{ "Coordinates must be a Float2" }; - - ShaderAstRecursiveVisitor::Visit(node); - } - - void ShaderAstValidator::Visit(ShaderNodes::StatementBlock& node) - { - assert(m_context); - - m_context->blockLocalIndex.push_back(m_context->declaredLocals.size()); - - for (const auto& statement : node.statements) - MandatoryNode(statement); - - assert(m_context->declaredLocals.size() >= m_context->blockLocalIndex.back()); - m_context->declaredLocals.resize(m_context->blockLocalIndex.back()); - m_context->blockLocalIndex.pop_back(); - - ShaderAstRecursiveVisitor::Visit(node); - } - - void ShaderAstValidator::Visit(ShaderNodes::SwizzleOp& node) - { - if (node.componentCount > 4) - throw AstError{ "Cannot swizzle more than four elements" }; - - const ShaderExpressionType& exprType = MandatoryExpr(node.expression)->GetExpressionType(); - if (!IsBasicType(exprType)) - throw AstError{ "Cannot swizzle this type" }; - - switch (std::get(exprType)) - { - case ShaderNodes::BasicType::Float1: - case ShaderNodes::BasicType::Float2: - case ShaderNodes::BasicType::Float3: - case ShaderNodes::BasicType::Float4: - case ShaderNodes::BasicType::Int1: - case ShaderNodes::BasicType::Int2: - case ShaderNodes::BasicType::Int3: - case ShaderNodes::BasicType::Int4: - break; - - default: - throw AstError{ "Cannot swizzle this type" }; - } - - ShaderAstRecursiveVisitor::Visit(node); - } - - void ShaderAstValidator::Visit(ShaderNodes::BuiltinVariable& var) - { - switch (var.entry) - { - case ShaderNodes::BuiltinEntry::VertexPosition: - if (!IsBasicType(var.type) || - std::get(var.type) != ShaderNodes::BasicType::Float4) - throw AstError{ "Builtin is not of the expected type" }; - - break; - - default: - break; - } - } - - void ShaderAstValidator::Visit(ShaderNodes::InputVariable& var) - { - for (std::size_t i = 0; i < m_shader.GetInputCount(); ++i) - { - const auto& input = m_shader.GetInput(i); - if (input.name == var.name) - { - TypeMustMatch(input.type, var.type); - return; - } - } - - throw AstError{ "Input not found" }; - } - - void ShaderAstValidator::Visit(ShaderNodes::LocalVariable& var) - { - const auto& vars = m_context->declaredLocals; - - auto it = std::find_if(vars.begin(), vars.end(), [&](const auto& v) { return v.name == var.name; }); - if (it == vars.end()) - throw AstError{ "Local variable not found in this block" }; - - TypeMustMatch(it->type, var.type); - } - - void ShaderAstValidator::Visit(ShaderNodes::OutputVariable& var) - { - for (std::size_t i = 0; i < m_shader.GetOutputCount(); ++i) - { - const auto& input = m_shader.GetOutput(i); - if (input.name == var.name) - { - TypeMustMatch(input.type, var.type); - return; - } - } - - throw AstError{ "Output not found" }; - } - - void ShaderAstValidator::Visit(ShaderNodes::ParameterVariable& var) - { - assert(m_context->currentFunction); - - const auto& parameters = m_context->currentFunction->parameters; - - auto it = std::find_if(parameters.begin(), parameters.end(), [&](const auto& parameter) { return parameter.name == var.name; }); - if (it == parameters.end()) - throw AstError{ "Parameter not found in function" }; - - TypeMustMatch(it->type, var.type); - } - - void ShaderAstValidator::Visit(ShaderNodes::UniformVariable& var) - { - for (std::size_t i = 0; i < m_shader.GetUniformCount(); ++i) - { - const auto& uniform = m_shader.GetUniform(i); - if (uniform.name == var.name) - { - TypeMustMatch(uniform.type, var.type); - return; - } - } - - throw AstError{ "Uniform not found" }; - } - - bool ValidateShader(const ShaderAst& shader, std::string* error) - { - ShaderAstValidator validator(shader); - return validator.Validate(error); - } -} diff --git a/src/Nazara/Shader/ShaderAstVisitor.cpp b/src/Nazara/Shader/ShaderAstVisitor.cpp deleted file mode 100644 index 53325c9ca..000000000 --- a/src/Nazara/Shader/ShaderAstVisitor.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include - -namespace Nz -{ - ShaderAstVisitor::~ShaderAstVisitor() = default; - - void ShaderAstVisitor::EnableCondition(const std::string& name, bool cond) - { - if (cond) - m_conditions.insert(name); - else - m_conditions.erase(name); - } - - bool ShaderAstVisitor::IsConditionEnabled(const std::string& name) const - { - return m_conditions.count(name) != 0; - } - - void ShaderAstVisitor::Visit(const ShaderNodes::NodePtr& node) - { - node->Visit(*this); - } -} diff --git a/src/Nazara/Shader/ShaderAstVisitorExcept.cpp b/src/Nazara/Shader/ShaderAstVisitorExcept.cpp deleted file mode 100644 index 419d073bb..000000000 --- a/src/Nazara/Shader/ShaderAstVisitorExcept.cpp +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include -#include - -namespace Nz -{ - void ShaderAstVisitorExcept::Visit(ShaderNodes::AccessMember& /*node*/) - { - throw std::runtime_error("unhandled AccessMember node"); - } - - void ShaderAstVisitorExcept::Visit(ShaderNodes::AssignOp& /*node*/) - { - throw std::runtime_error("unhandled AssignOp node"); - } - - void ShaderAstVisitorExcept::Visit(ShaderNodes::BinaryOp& /*node*/) - { - throw std::runtime_error("unhandled AccessMember node"); - } - - void ShaderAstVisitorExcept::Visit(ShaderNodes::Branch& /*node*/) - { - throw std::runtime_error("unhandled Branch node"); - } - - void ShaderAstVisitorExcept::Visit(ShaderNodes::Cast& /*node*/) - { - throw std::runtime_error("unhandled Cast node"); - } - - void ShaderAstVisitorExcept::Visit(ShaderNodes::Constant& /*node*/) - { - throw std::runtime_error("unhandled Constant node"); - } - - void ShaderAstVisitorExcept::Visit(ShaderNodes::DeclareVariable& /*node*/) - { - throw std::runtime_error("unhandled DeclareVariable node"); - } - - void ShaderAstVisitorExcept::Visit(ShaderNodes::ExpressionStatement& /*node*/) - { - throw std::runtime_error("unhandled ExpressionStatement node"); - } - - void ShaderAstVisitorExcept::Visit(ShaderNodes::Identifier& /*node*/) - { - throw std::runtime_error("unhandled Identifier node"); - } - - void ShaderAstVisitorExcept::Visit(ShaderNodes::IntrinsicCall& /*node*/) - { - throw std::runtime_error("unhandled IntrinsicCall node"); - } - - void ShaderAstVisitorExcept::Visit(ShaderNodes::Sample2D& /*node*/) - { - throw std::runtime_error("unhandled Sample2D node"); - } - - void ShaderAstVisitorExcept::Visit(ShaderNodes::StatementBlock& /*node*/) - { - throw std::runtime_error("unhandled StatementBlock node"); - } - - void ShaderAstVisitorExcept::Visit(ShaderNodes::SwizzleOp& /*node*/) - { - throw std::runtime_error("unhandled SwizzleOp node"); - } -} diff --git a/src/Nazara/Shader/ShaderLangLexer.cpp b/src/Nazara/Shader/ShaderLangLexer.cpp new file mode 100644 index 000000000..91343bc04 --- /dev/null +++ b/src/Nazara/Shader/ShaderLangLexer.cpp @@ -0,0 +1,384 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz::ShaderLang +{ + namespace + { + class ForceCLocale + { + public: + ForceCLocale() + { + m_previousLocale = std::locale::global(std::locale::classic()); + } + + ~ForceCLocale() + { + std::locale::global(m_previousLocale); + } + + private: + std::locale m_previousLocale; + }; + } + + std::vector Tokenize(const std::string_view& str) + { + // Can't use std::from_chars for double, thanks to libc++ and libstdc++ developers for being lazy + ForceCLocale forceCLocale; + + std::unordered_map reservedKeywords = { + { "external", TokenType::External }, + { "false", TokenType::BoolFalse }, + { "fn", TokenType::FunctionDeclaration }, + { "let", TokenType::Let }, + { "option", TokenType::Option }, + { "return", TokenType::Return }, + { "select_opt", TokenType::SelectOpt }, + { "struct", TokenType::Struct }, + { "true", TokenType::BoolTrue } + }; + + std::size_t currentPos = 0; + + auto Peek = [&](std::size_t advance = 1) -> char + { + if (currentPos + advance < str.size() && str[currentPos + advance] != '\0') + return str[currentPos + advance]; + else + return char(-1); + }; + + auto IsAlphaNum = [&](const char c) + { + return std::isalnum(c) || c == '_'; + }; + + unsigned int lineNumber = 0; + std::size_t lastLineFeed = 0; + std::vector tokens; + + for (;;) + { + char c = Peek(0); + + Token token; + token.column = static_cast(currentPos - lastLineFeed); + token.line = lineNumber; + + if (c == -1) + { + token.type = TokenType::EndOfStream; + tokens.push_back(std::move(token)); + break; + } + + std::optional tokenType; + switch (c) + { + case ' ': + case '\t': + case '\r': + break; //< Ignore blank spaces + + case '\n': + { + lineNumber++; + lastLineFeed = currentPos; + break; + } + + case '-': + { + if (Peek() == '>') + { + currentPos++; + tokenType = TokenType::FunctionReturn; + break; + } + + tokenType = TokenType::Minus; + break; + } + + case '/': + { + char next = Peek(); + if (next == '/') + { + // Line comment + do + { + currentPos++; + next = Peek(); + } + while (next != -1 && next != '\n'); + } + else if (next == '*') + { + // Block comment + do + { + currentPos++; + next = Peek(); + + if (next == '*') + { + currentPos++; + if (Peek() == '/') + { + currentPos++; + break; + } + } + else if (next == '\n') + { + lineNumber++; + lastLineFeed = currentPos + 1; + } + } + while (next != -1); + } + else + tokenType = TokenType::Divide; + + break; + } + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + bool floatingPoint = false; + + std::size_t start = currentPos; + char next = Peek(); + + if (next == 'x' || next == 'X') + currentPos++; + + for (;;) + { + next = Peek(); + + if (!isdigit(next)) + { + if (next != '.') + break; + + if (floatingPoint) + break; + + floatingPoint = true; + } + + currentPos++; + } + + if (floatingPoint) + { + tokenType = TokenType::FloatingPointValue; + + std::string valueStr(str.substr(start, currentPos - start + 1)); + + const char* ptr = valueStr.c_str(); + + char* end; + double value = std::strtod(ptr, &end); + if (end != &ptr[valueStr.size()]) + throw BadNumber{}; + + token.data = value; + } + else + { + tokenType = TokenType::IntegerValue; + + long long value; + std::from_chars_result r = std::from_chars(&str[start], &str[currentPos + 1], value); + if (r.ptr != &str[currentPos + 1]) + { + if (r.ec == std::errc::result_out_of_range) + throw NumberOutOfRange{}; + + throw BadNumber{}; + } + + token.data = value; + } + + break; + } + + case '=': + { + char next = Peek(); + if (next == '=') + { + currentPos++; + tokenType = TokenType::Equal; + } + else + tokenType = TokenType::Assign; + + break; + } + + case '<': + { + char next = Peek(); + if (next == '=') + { + currentPos++; + tokenType = TokenType::LessThanEqual; + } + else + tokenType = TokenType::LessThan; + + break; + } + + case '>': + { + char next = Peek(); + if (next == '=') + { + currentPos++; + tokenType = TokenType::GreatherThanEqual; + } + else + tokenType = TokenType::GreatherThan; + + break; + } + + case '+': tokenType = TokenType::Plus; break; + case '*': tokenType = TokenType::Multiply; break; + case ':': tokenType = TokenType::Colon; break; + case ';': tokenType = TokenType::Semicolon; break; + case '.': tokenType = TokenType::Dot; break; + case ',': tokenType = TokenType::Comma; break; + case '{': tokenType = TokenType::OpenCurlyBracket; break; + case '}': tokenType = TokenType::ClosingCurlyBracket; break; + case '(': tokenType = TokenType::OpenParenthesis; break; + case ')': tokenType = TokenType::ClosingParenthesis; break; + case '[': tokenType = TokenType::OpenSquareBracket; break; + case ']': tokenType = TokenType::ClosingSquareBracket; break; + + default: + { + if (IsAlphaNum(c)) + { + std::size_t start = currentPos; + + while (IsAlphaNum(Peek())) + currentPos++; + + std::string identifier(str.substr(start, currentPos - start + 1)); + if (auto it = reservedKeywords.find(identifier); it == reservedKeywords.end()) + { + tokenType = TokenType::Identifier; + token.data = std::move(identifier); + } + else + tokenType = it->second; + + break; + } + else + throw UnrecognizedToken{}; + } + } + + if (tokenType) + { + token.type = *tokenType; + + tokens.push_back(std::move(token)); + } + + currentPos++; + } + + return tokens; + } + + const char* ToString(TokenType tokenType) + { + switch (tokenType) + { +#define NAZARA_SHADERLANG_TOKEN(X) case TokenType:: X: return #X; + +#include + } + + return ""; + } + + std::string ToString(const std::vector& tokens, bool pretty) + { + if (tokens.empty()) + return {}; + + unsigned int lastLineNumber = tokens.front().line; + + std::stringstream ss; + bool empty = true; + + for (const Token& token : tokens) + { + if (token.line != lastLineNumber && pretty) + { + lastLineNumber = token.line; + if (!empty) + ss << '\n'; + } + else if (!empty) + ss << ' '; + + ss << ToString(token.type); + switch (token.type) + { + case TokenType::FloatingPointValue: + ss << "(" << std::get(token.data) << ")"; + break; + + case TokenType::Identifier: + ss << "(" << std::get(token.data) << ")"; + break; + + case TokenType::IntegerValue: + ss << "(" << std::get(token.data) << ")"; + break; + + default: + break; + } + + empty = false; + } + + ss << '\n'; + + return std::move(ss).str(); + } +} diff --git a/src/Nazara/Shader/ShaderLangParser.cpp b/src/Nazara/Shader/ShaderLangParser.cpp new file mode 100644 index 000000000..9fbd9e8f1 --- /dev/null +++ b/src/Nazara/Shader/ShaderLangParser.cpp @@ -0,0 +1,1149 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include + +namespace Nz::ShaderLang +{ + namespace + { + std::unordered_map s_depthWriteModes = { + { "greater", ShaderAst::DepthWriteMode::Greater }, + { "less", ShaderAst::DepthWriteMode::Less }, + { "replace", ShaderAst::DepthWriteMode::Replace }, + { "unchanged", ShaderAst::DepthWriteMode::Unchanged }, + }; + + std::unordered_map s_identifierToBasicType = { + { "bool", ShaderAst::PrimitiveType::Boolean }, + { "i32", ShaderAst::PrimitiveType::Int32 }, + { "f32", ShaderAst::PrimitiveType::Float32 }, + { "u32", ShaderAst::PrimitiveType::UInt32 } + }; + + std::unordered_map s_identifierToAttributeType = { + { "binding", ShaderAst::AttributeType::Binding }, + { "builtin", ShaderAst::AttributeType::Builtin }, + { "depth_write", ShaderAst::AttributeType::DepthWrite }, + { "early_fragment_tests", ShaderAst::AttributeType::EarlyFragmentTests }, + { "entry", ShaderAst::AttributeType::Entry }, + { "layout", ShaderAst::AttributeType::Layout }, + { "location", ShaderAst::AttributeType::Location }, + { "opt", ShaderAst::AttributeType::Option }, + }; + + std::unordered_map s_entryPoints = { + { "frag", ShaderStageType::Fragment }, + { "vert", ShaderStageType::Vertex }, + }; + + std::unordered_map s_builtinMapping = { + { "fragcoord", ShaderAst::BuiltinEntry::FragCoord }, + { "fragdepth", ShaderAst::BuiltinEntry::FragDepth }, + { "position", ShaderAst::BuiltinEntry::VertexPosition } + }; + + std::unordered_map s_layoutMapping = { + { "std140", StructLayout::Std140 } + }; + + template + std::optional BoundCast(U val) + { + if (val < std::numeric_limits::min() || val > std::numeric_limits::max()) + return std::nullopt; + + return static_cast(val); + } + } + + ShaderAst::StatementPtr Parser::Parse(const std::vector& tokens) + { + Context context; + context.tokenCount = tokens.size(); + context.tokens = tokens.data(); + + context.root = std::make_unique(); + + m_context = &context; + + std::vector attributes; + + EnterScope(); + + bool reachedEndOfStream = false; + while (!reachedEndOfStream) + { + const Token& nextToken = Peek(); + switch (nextToken.type) + { + case TokenType::EndOfStream: + if (!attributes.empty()) + throw UnexpectedToken{}; + + reachedEndOfStream = true; + break; + + case TokenType::External: + context.root->statements.push_back(ParseExternalBlock(std::move(attributes))); + attributes.clear(); + break; + + case TokenType::OpenSquareBracket: + assert(attributes.empty()); + attributes = ParseAttributes(); + break; + + case TokenType::Option: + if (!attributes.empty()) + throw UnexpectedToken{}; + + context.root->statements.push_back(ParseOptionDeclaration()); + break; + + case TokenType::FunctionDeclaration: + context.root->statements.push_back(ParseFunctionDeclaration(std::move(attributes))); + attributes.clear(); + break; + + case TokenType::Struct: + context.root->statements.push_back(ParseStructDeclaration(std::move(attributes))); + attributes.clear(); + break; + + default: + throw UnexpectedToken{}; + } + } + + LeaveScope(); + + return std::move(context.root); + } + + const Token& Parser::Advance() + { + const Token& token = Peek(); + m_context->tokenIndex++; + + return token; + } + + void Parser::Consume(std::size_t count) + { + assert(m_context->tokenIndex + count < m_context->tokenCount); + m_context->tokenIndex += count; + } + + std::optional Parser::DecodeType(const std::string& identifier) + { + if (auto it = s_identifierToBasicType.find(identifier); it != s_identifierToBasicType.end()) + { + Consume(); + return it->second; + } + + //FIXME: Handle this better + if (identifier == "mat4") + { + Consume(); + + ShaderAst::MatrixType matrixType; + matrixType.columnCount = 4; + matrixType.rowCount = 4; + + Expect(Advance(), TokenType::LessThan); //< '<' + matrixType.type = ParsePrimitiveType(); + Expect(Advance(), TokenType::GreatherThan); //< '>' + + return matrixType; + } + else if (identifier == "mat3") + { + Consume(); + + ShaderAst::MatrixType matrixType; + matrixType.columnCount = 3; + matrixType.rowCount = 3; + + Expect(Advance(), TokenType::LessThan); //< '<' + matrixType.type = ParsePrimitiveType(); + Expect(Advance(), TokenType::GreatherThan); //< '>' + + return matrixType; + } + else if (identifier == "sampler2D") + { + Consume(); + + ShaderAst::SamplerType samplerType; + samplerType.dim = ImageType::E2D; + + Expect(Advance(), TokenType::LessThan); //< '<' + samplerType.sampledType = ParsePrimitiveType(); + Expect(Advance(), TokenType::GreatherThan); //< '>' + + return samplerType; + } + else if (identifier == "samplerCube") + { + Consume(); + + ShaderAst::SamplerType samplerType; + samplerType.dim = ImageType::Cubemap; + + Expect(Advance(), TokenType::LessThan); //< '<' + samplerType.sampledType = ParsePrimitiveType(); + Expect(Advance(), TokenType::GreatherThan); //< '>' + + return samplerType; + } + else if (identifier == "uniform") + { + Consume(); + + ShaderAst::UniformType uniformType; + + Expect(Advance(), TokenType::LessThan); //< '<' + uniformType.containedType = ShaderAst::IdentifierType{ ParseIdentifierAsName() }; + Expect(Advance(), TokenType::GreatherThan); //< '>' + + return uniformType; + } + else if (identifier == "vec2") + { + Consume(); + + ShaderAst::VectorType vectorType; + vectorType.componentCount = 2; + + Expect(Advance(), TokenType::LessThan); //< '<' + vectorType.type = ParsePrimitiveType(); + Expect(Advance(), TokenType::GreatherThan); //< '>' + + return vectorType; + } + else if (identifier == "vec3") + { + Consume(); + + ShaderAst::VectorType vectorType; + vectorType.componentCount = 3; + + Expect(Advance(), TokenType::LessThan); //< '<' + vectorType.type = ParsePrimitiveType(); + Expect(Advance(), TokenType::GreatherThan); //< '>' + + return vectorType; + } + else if (identifier == "vec4") + { + Consume(); + + ShaderAst::VectorType vectorType; + vectorType.componentCount = 4; + + Expect(Advance(), TokenType::LessThan); //< '<' + vectorType.type = ParsePrimitiveType(); + Expect(Advance(), TokenType::GreatherThan); //< '>' + + return vectorType; + } + else + return std::nullopt; + } + + void Parser::EnterScope() + { + m_context->scopeSizes.push_back(m_context->identifiersInScope.size()); + } + + const Token& Parser::Expect(const Token& token, TokenType type) + { + if (token.type != type) + throw ExpectedToken{}; + + return token; + } + + const Token& Parser::ExpectNot(const Token& token, TokenType type) + { + if (token.type == type) + throw ExpectedToken{}; + + return token; + } + + const Token& Parser::Expect(TokenType type) + { + const Token& token = Peek(); + Expect(token, type); + + return token; + } + + void Parser::LeaveScope() + { + assert(!m_context->scopeSizes.empty()); + m_context->identifiersInScope.resize(m_context->scopeSizes.back()); + m_context->scopeSizes.pop_back(); + } + + bool Parser::IsVariableInScope(const std::string_view& identifier) const + { + return std::find(m_context->identifiersInScope.rbegin(), m_context->identifiersInScope.rend(), identifier) != m_context->identifiersInScope.rend(); + } + + void Parser::RegisterVariable(std::string identifier) + { + if (IsVariableInScope(identifier)) + throw DuplicateIdentifier{ ("identifier name " + identifier + " is already taken").c_str() }; + + assert(!m_context->scopeSizes.empty()); + m_context->identifiersInScope.push_back(std::move(identifier)); + } + + const Token& Parser::Peek(std::size_t advance) + { + assert(m_context->tokenIndex + advance < m_context->tokenCount); + return m_context->tokens[m_context->tokenIndex + advance]; + } + + std::vector Parser::ParseAttributes() + { + std::vector attributes; + + Expect(Advance(), TokenType::OpenSquareBracket); + + bool expectComma = false; + for (;;) + { + const Token& t = Peek(); + ExpectNot(t, TokenType::EndOfStream); + + if (t.type == TokenType::ClosingSquareBracket) + { + // Parse [attribute1] [attribute2] the same as [attribute1, attribute2] + if (Peek(1).type == TokenType::OpenSquareBracket) + { + Consume(2); + expectComma = false; + continue; + } + + break; + } + + if (expectComma) + Expect(Advance(), TokenType::Comma); + + ShaderAst::AttributeType attributeType = ParseIdentifierAsAttributeType(); + + ShaderAst::Attribute::Param arg; + if (Peek().type == TokenType::OpenParenthesis) + { + Consume(); + + const Token& n = Peek(); + if (n.type == TokenType::Identifier) + { + arg = std::get(n.data); + Consume(); + } + else if (n.type == TokenType::IntegerValue) + { + arg = std::get(n.data); + Consume(); + } + + Expect(Advance(), TokenType::ClosingParenthesis); + } + + expectComma = true; + + attributes.push_back({ + attributeType, + std::move(arg) + }); + } + + Expect(Advance(), TokenType::ClosingSquareBracket); + + return attributes; + } + + ShaderAst::StatementPtr Parser::ParseExternalBlock(std::vector attributes) + { + if (!attributes.empty()) + throw AttributeError{ "unhandled attribute for external block" }; + + Expect(Advance(), TokenType::External); + Expect(Advance(), TokenType::OpenCurlyBracket); + + std::unique_ptr externalStatement = std::make_unique(); + + bool first = true; + for (;;) + { + if (!first) + { + const Token& nextToken = Peek(); + if (nextToken.type == TokenType::Comma) + Consume(); + else + { + Expect(nextToken, TokenType::ClosingCurlyBracket); + break; + } + } + + first = false; + + const Token& token = Peek(); + if (token.type == TokenType::ClosingCurlyBracket) + break; + + auto& extVar = externalStatement->externalVars.emplace_back(); + + if (token.type == TokenType::OpenSquareBracket) + { + for (const auto& [attributeType, arg] : ParseAttributes()) + { + switch (attributeType) + { + case ShaderAst::AttributeType::Binding: + { + if (extVar.bindingIndex) + throw AttributeError{ "attribute binding must be present once" }; + + if (!std::holds_alternative(arg)) + throw AttributeError{ "attribute binding requires a string parameter" }; + + std::optional bindingIndex = BoundCast(std::get(arg)); + if (!bindingIndex) + throw AttributeError{ "invalid binding index" }; + + extVar.bindingIndex = bindingIndex.value(); + break; + } + + default: + throw AttributeError{ "unhandled attribute for external variable" }; + } + } + } + + extVar.name = ParseIdentifierAsName(); + Expect(Advance(), TokenType::Colon); + extVar.type = ParseType(); + + RegisterVariable(extVar.name); + } + + Expect(Advance(), TokenType::ClosingCurlyBracket); + + return externalStatement; + } + + std::vector Parser::ParseFunctionBody() + { + return ParseStatementList(); + } + + ShaderAst::StatementPtr Parser::ParseFunctionDeclaration(std::vector attributes) + { + Expect(Advance(), TokenType::FunctionDeclaration); + + std::string functionName = ParseIdentifierAsName(); + + Expect(Advance(), TokenType::OpenParenthesis); + + std::vector parameters; + + bool firstParameter = true; + for (;;) + { + const Token& t = Peek(); + ExpectNot(t, TokenType::EndOfStream); + + if (t.type == TokenType::ClosingParenthesis) + break; + + if (!firstParameter) + Expect(Advance(), TokenType::Comma); + + parameters.push_back(ParseFunctionParameter()); + firstParameter = false; + } + + Expect(Advance(), TokenType::ClosingParenthesis); + + ShaderAst::ExpressionType returnType; + if (Peek().type == TokenType::FunctionReturn) + { + Consume(); + returnType = ParseType(); + } + + Expect(Advance(), TokenType::OpenCurlyBracket); + + EnterScope(); + for (const auto& parameter : parameters) + RegisterVariable(parameter.name); + + std::vector functionBody = ParseFunctionBody(); + + LeaveScope(); + + Expect(Advance(), TokenType::ClosingCurlyBracket); + + auto func = ShaderBuilder::DeclareFunction(std::move(functionName), std::move(parameters), std::move(functionBody), std::move(returnType)); + + for (const auto& [attributeType, arg] : attributes) + { + switch (attributeType) + { + case ShaderAst::AttributeType::DepthWrite: + { + if (func->depthWrite) + throw AttributeError{ "attribute depth_write can only be present once" }; + + if (!std::holds_alternative(arg)) + throw AttributeError{ "attribute entry requires a string parameter" }; + + const std::string& argStr = std::get(arg); + + auto it = s_depthWriteModes.find(argStr); + if (it == s_depthWriteModes.end()) + throw AttributeError{ ("invalid parameter " + argStr + " for depth_write attribute").c_str() }; + + func->depthWrite = it->second; + break; + } + + case ShaderAst::AttributeType::EarlyFragmentTests: + { + if (func->earlyFragmentTests) + throw AttributeError{ "attribute early_fragment_tests can only be present once" }; + + if (std::holds_alternative(arg)) + { + const std::string& argStr = std::get(arg); + if (argStr == "true" || argStr == "on") + func->earlyFragmentTests = true; + else if (argStr == "false" || argStr == "off") + func->earlyFragmentTests = false; + else + throw AttributeError{ "expected boolean value (got " + argStr + ")" }; + } + else if (std::holds_alternative(arg)) + { + // No parameter, default to true + func->earlyFragmentTests = true; + } + else + throw AttributeError{ "unexpected value for early_fragment_tests" }; + + break; + } + + case ShaderAst::AttributeType::Entry: + { + if (func->entryStage) + throw AttributeError{ "attribute entry can only be present once" }; + + if (!std::holds_alternative(arg)) + throw AttributeError{ "attribute entry requires a string parameter" }; + + const std::string& argStr = std::get(arg); + + auto it = s_entryPoints.find(argStr); + if (it == s_entryPoints.end()) + throw AttributeError{ ("invalid parameter " + argStr + " for entry attribute").c_str() }; + + func->entryStage = it->second; + break; + } + + case ShaderAst::AttributeType::Option: + { + if (!func->optionName.empty()) + throw AttributeError{ "attribute option must be present once" }; + + if (!std::holds_alternative(arg)) + throw AttributeError{ "attribute option requires a string parameter" }; + + func->optionName = std::get(arg); + break; + } + + default: + throw AttributeError{ "unhandled attribute for function" }; + } + } + + return func; + } + + ShaderAst::DeclareFunctionStatement::Parameter Parser::ParseFunctionParameter() + { + std::string parameterName = ParseIdentifierAsName(); + + Expect(Advance(), TokenType::Colon); + + ShaderAst::ExpressionType parameterType = ParseType(); + + return { parameterName, parameterType }; + } + + ShaderAst::StatementPtr Parser::ParseOptionDeclaration() + { + Expect(Advance(), TokenType::Option); + + std::string optionName = ParseIdentifierAsName(); + + Expect(Advance(), TokenType::Colon); + + ShaderAst::ExpressionType optionType = ParseType(); + + ShaderAst::ExpressionPtr initialValue; + if (Peek().type == TokenType::Assign) + { + Consume(); + + initialValue = ParseExpression(); + } + + Expect(Advance(), TokenType::Semicolon); + + return ShaderBuilder::DeclareOption(std::move(optionName), std::move(optionType), std::move(initialValue)); + } + + ShaderAst::StatementPtr Parser::ParseStructDeclaration(std::vector attributes) + { + Expect(Advance(), TokenType::Struct); + + ShaderAst::StructDescription description; + description.name = ParseIdentifierAsName(); + + for (const auto& [attributeType, attributeParam] : attributes) + { + switch (attributeType) + { + case ShaderAst::AttributeType::Layout: + { + if (description.layout) + throw AttributeError{ "attribute layout must be present once" }; + + auto it = s_layoutMapping.find(std::get(attributeParam)); + if (it == s_layoutMapping.end()) + throw AttributeError{ "unknown layout" }; + + description.layout = it->second; + break; + } + + default: + throw AttributeError{ "unexpected attribute" }; + } + } + + Expect(Advance(), TokenType::OpenCurlyBracket); + + bool first = true; + + for (;;) + { + if (!first) + { + const Token& nextToken = Peek(); + if (nextToken.type == TokenType::Comma) + Consume(); + else + { + Expect(nextToken, TokenType::ClosingCurlyBracket); + break; + } + } + + first = false; + + const Token& token = Peek(); + if (token.type == TokenType::ClosingCurlyBracket) + break; + + auto& structField = description.members.emplace_back(); + + if (token.type == TokenType::OpenSquareBracket) + { + for (const auto& [attributeType, attributeParam] : ParseAttributes()) + { + switch (attributeType) + { + case ShaderAst::AttributeType::Builtin: + { + if (structField.builtin) + throw AttributeError{ "attribute builtin must be present once" }; + + auto it = s_builtinMapping.find(std::get(attributeParam)); + + if (it == s_builtinMapping.end()) + throw AttributeError{ "unknown builtin" }; + + structField.builtin = it->second; + break; + } + + case ShaderAst::AttributeType::Location: + { + if (structField.locationIndex) + throw AttributeError{ "attribute location must be present once" }; + + structField.locationIndex = BoundCast(std::get(attributeParam)); + if (!structField.locationIndex) + throw AttributeError{ "invalid location index" }; + + break; + } + + default: + throw AttributeError{ "unexpected attribute" }; + } + } + + if (structField.builtin && structField.locationIndex) + throw AttributeError{ "A struct field cannot have both builtin and location attributes" }; + } + + structField.name = ParseIdentifierAsName(); + + Expect(Advance(), TokenType::Colon); + + structField.type = ParseType(); + } + + Expect(Advance(), TokenType::ClosingCurlyBracket); + + return ShaderBuilder::DeclareStruct(std::move(description)); + } + + ShaderAst::StatementPtr Parser::ParseReturnStatement() + { + Expect(Advance(), TokenType::Return); + + ShaderAst::ExpressionPtr expr; + if (Peek().type != TokenType::Semicolon) + expr = ParseExpression(); + + return ShaderBuilder::Return(std::move(expr)); + } + + ShaderAst::StatementPtr Parser::ParseStatement() + { + const Token& token = Peek(); + + ShaderAst::StatementPtr statement; + switch (token.type) + { + case TokenType::Let: + statement = ParseVariableDeclaration(); + break; + + case TokenType::Identifier: + statement = ShaderBuilder::ExpressionStatement(ParseVariableAssignation()); + break; + + case TokenType::Return: + statement = ParseReturnStatement(); + break; + + default: + break; + } + + Expect(Advance(), TokenType::Semicolon); + + return statement; + } + + std::vector Parser::ParseStatementList() + { + std::vector statements; + while (Peek().type != TokenType::ClosingCurlyBracket) + { + ExpectNot(Peek(), TokenType::EndOfStream); + statements.push_back(ParseStatement()); + } + + return statements; + } + + ShaderAst::ExpressionPtr Parser::ParseVariableAssignation() + { + ShaderAst::ExpressionPtr left = ParseExpression(); + Expect(Advance(), TokenType::Assign); + + ShaderAst::ExpressionPtr right = ParseExpression(); + + return ShaderBuilder::Assign(ShaderAst::AssignType::Simple, std::move(left), std::move(right)); + } + + ShaderAst::StatementPtr Parser::ParseVariableDeclaration() + { + Expect(Advance(), TokenType::Let); + + std::string variableName = ParseIdentifierAsName(); + RegisterVariable(variableName); + + ShaderAst::ExpressionType variableType = ShaderAst::NoType{}; + if (Peek().type == TokenType::Colon) + { + Expect(Advance(), TokenType::Colon); + + variableType = ParseType(); + } + + ShaderAst::ExpressionPtr expression; + if (IsNoType(variableType) || Peek().type == TokenType::Assign) + { + Expect(Advance(), TokenType::Assign); + expression = ParseExpression(); + } + + return ShaderBuilder::DeclareVariable(std::move(variableName), std::move(variableType), std::move(expression)); + } + + ShaderAst::ExpressionPtr Parser::ParseBinOpRhs(int exprPrecedence, ShaderAst::ExpressionPtr lhs) + { + for (;;) + { + TokenType currentTokenType = Peek().type; + if (currentTokenType == TokenType::EndOfStream) + throw UnexpectedToken{}; + + int tokenPrecedence = GetTokenPrecedence(currentTokenType); + if (tokenPrecedence < exprPrecedence) + return lhs; + + bool c = false; + while (currentTokenType == TokenType::Dot || currentTokenType == TokenType::OpenSquareBracket) + { + c = true; + + if (currentTokenType == TokenType::Dot) + { + std::unique_ptr accessMemberNode = std::make_unique(); + accessMemberNode->expr = std::move(lhs); + + do + { + Consume(); + + accessMemberNode->identifiers.push_back(ParseIdentifierAsName()); + } while (Peek().type == TokenType::Dot); + + // FIXME + if (!accessMemberNode->identifiers.empty() && accessMemberNode->identifiers.front() == "Sample") + { + if (Peek().type == TokenType::OpenParenthesis) + { + auto parameters = ParseParameters(); + parameters.insert(parameters.begin(), std::move(accessMemberNode->expr)); + + lhs = ShaderBuilder::Intrinsic(ShaderAst::IntrinsicType::SampleTexture, std::move(parameters)); + break; + } + } + + lhs = std::move(accessMemberNode); + } + else + { + assert(currentTokenType == TokenType::OpenSquareBracket); + + std::unique_ptr indexNode = std::make_unique(); + indexNode->expr = std::move(lhs); + + do + { + Consume(); + + indexNode->indices.push_back(ParseExpression()); + + Expect(Advance(), TokenType::ClosingSquareBracket); + } + while (Peek().type == TokenType::OpenSquareBracket); + + lhs = std::move(indexNode); + } + + currentTokenType = Peek().type; + } + + if (c) + continue; + + Consume(); + ShaderAst::ExpressionPtr rhs = ParsePrimaryExpression(); + + const Token& nextOp = Peek(); + + int nextTokenPrecedence = GetTokenPrecedence(nextOp.type); + if (tokenPrecedence < nextTokenPrecedence) + rhs = ParseBinOpRhs(tokenPrecedence + 1, std::move(rhs)); + + ShaderAst::BinaryType binaryType; + { + switch (currentTokenType) + { + case TokenType::Plus: binaryType = ShaderAst::BinaryType::Add; break; + case TokenType::Minus: binaryType = ShaderAst::BinaryType::Subtract; break; + case TokenType::Multiply: binaryType = ShaderAst::BinaryType::Multiply; break; + case TokenType::Divide: binaryType = ShaderAst::BinaryType::Divide; break; + default: throw UnexpectedToken{}; + } + } + + lhs = ShaderBuilder::Binary(binaryType, std::move(lhs), std::move(rhs)); + } + } + + ShaderAst::ExpressionPtr Parser::ParseExpression() + { + return ParseBinOpRhs(0, ParsePrimaryExpression()); + } + + ShaderAst::ExpressionPtr Parser::ParseFloatingPointExpression() + { + const Token& floatingPointToken = Expect(Advance(), TokenType::FloatingPointValue); + return ShaderBuilder::Constant(float(std::get(floatingPointToken.data))); //< FIXME + } + + ShaderAst::ExpressionPtr Parser::ParseIdentifier() + { + const Token& identifierToken = Expect(Advance(), TokenType::Identifier); + const std::string& identifier = std::get(identifierToken.data); + + return ShaderBuilder::Identifier(identifier); + } + + ShaderAst::ExpressionPtr Parser::ParseIntegerExpression() + { + const Token& integerToken = Expect(Advance(), TokenType::IntegerValue); + return ShaderBuilder::Constant(static_cast(std::get(integerToken.data))); //< FIXME + } + + std::vector Parser::ParseParameters() + { + Expect(Advance(), TokenType::OpenParenthesis); + + std::vector parameters; + bool first = true; + while (Peek().type != TokenType::ClosingParenthesis) + { + if (!first) + Expect(Advance(), TokenType::Comma); + + first = false; + parameters.push_back(ParseExpression()); + } + + Expect(Advance(), TokenType::ClosingParenthesis); + + return parameters; + } + + ShaderAst::ExpressionPtr Parser::ParseParenthesisExpression() + { + Expect(Advance(), TokenType::OpenParenthesis); + ShaderAst::ExpressionPtr expression = ParseExpression(); + Expect(Advance(), TokenType::ClosingParenthesis); + + return expression; + } + + ShaderAst::ExpressionPtr Parser::ParsePrimaryExpression() + { + const Token& token = Peek(); + switch (token.type) + { + case TokenType::BoolFalse: + Consume(); + return ShaderBuilder::Constant(false); + + case TokenType::BoolTrue: + Consume(); + return ShaderBuilder::Constant(true); + + case TokenType::FloatingPointValue: + return ParseFloatingPointExpression(); + + case TokenType::Identifier: + { + const std::string& identifier = std::get(token.data); + + // Is it a cast? + std::optional exprType = DecodeType(identifier); + if (exprType) + return ShaderBuilder::Cast(std::move(*exprType), ParseParameters()); + + if (Peek(1).type == TokenType::OpenParenthesis) + { + // Function call + Consume(); + return ShaderBuilder::CallFunction(identifier, ParseParameters()); + } + else + return ParseIdentifier(); + } + + case TokenType::IntegerValue: + return ParseIntegerExpression(); + + case TokenType::Minus: + { + Consume(); + ShaderAst::ExpressionPtr expr = ParsePrimaryExpression(); + + return ShaderBuilder::Unary(ShaderAst::UnaryType::Minus, std::move(expr)); + } + + case TokenType::Plus: + { + Consume(); + ShaderAst::ExpressionPtr expr = ParsePrimaryExpression(); + + return ShaderBuilder::Unary(ShaderAst::UnaryType::Plus, std::move(expr)); + } + + case TokenType::OpenParenthesis: + return ParseParenthesisExpression(); + + case TokenType::SelectOpt: + return ParseSelectOptExpression(); + + default: + throw UnexpectedToken{}; + } + } + + ShaderAst::ExpressionPtr Parser::ParseSelectOptExpression() + { + Expect(Advance(), TokenType::SelectOpt); + Expect(Advance(), TokenType::OpenParenthesis); + + std::string optionName = ParseIdentifierAsName(); + + Expect(Advance(), TokenType::Comma); + + ShaderAst::ExpressionPtr trueExpr = ParseExpression(); + + Expect(Advance(), TokenType::Comma); + + ShaderAst::ExpressionPtr falseExpr = ParseExpression(); + + Expect(Advance(), TokenType::ClosingParenthesis); + + return ShaderBuilder::SelectOption(std::move(optionName), std::move(trueExpr), std::move(falseExpr)); + } + + ShaderAst::AttributeType Parser::ParseIdentifierAsAttributeType() + { + const Token& identifierToken = Expect(Advance(), TokenType::Identifier); + const std::string& identifier = std::get(identifierToken.data); + + auto it = s_identifierToAttributeType.find(identifier); + if (it == s_identifierToAttributeType.end()) + throw UnknownAttribute{}; + + return it->second; + } + + const std::string& Parser::ParseIdentifierAsName() + { + const Token& identifierToken = Expect(Advance(), TokenType::Identifier); + const std::string& identifier = std::get(identifierToken.data); + + auto it = s_identifierToBasicType.find(identifier); + if (it != s_identifierToBasicType.end()) + throw ReservedKeyword{}; + + return identifier; + } + + ShaderAst::PrimitiveType Parser::ParsePrimitiveType() + { + const Token& identifierToken = Expect(Advance(), TokenType::Identifier); + const std::string& identifier = std::get(identifierToken.data); + + auto it = s_identifierToBasicType.find(identifier); + if (it == s_identifierToBasicType.end()) + throw UnknownType{}; + + return it->second; + } + + ShaderAst::ExpressionType Parser::ParseType() + { + // Handle () as no type + if (Peek().type == TokenType::OpenParenthesis) + { + Consume(); + Expect(Advance(), TokenType::ClosingParenthesis); + + return ShaderAst::NoType{}; + } + + const Token& identifierToken = Expect(Peek(), TokenType::Identifier); + const std::string& identifier = std::get(identifierToken.data); + + auto type = DecodeType(identifier); + if (!type) + { + Consume(); + return ShaderAst::IdentifierType{ identifier }; + } + + return *type; + } + + int Parser::GetTokenPrecedence(TokenType token) + { + switch (token) + { + case TokenType::Plus: return 20; + case TokenType::Divide: return 40; + case TokenType::Multiply: return 40; + case TokenType::Minus: return 20; + case TokenType::Dot: return 50; + case TokenType::OpenSquareBracket: return 50; + default: return -1; + } + } + + ShaderAst::StatementPtr Parse(const std::filesystem::path& sourcePath) + { + File file(sourcePath); + if (!file.Open(OpenMode::ReadOnly | OpenMode::Text)) + { + NazaraError("Failed to open \"" + sourcePath.generic_u8string() + '"'); + return {}; + } + + std::size_t length = static_cast(file.GetSize()); + + std::vector source(length); + if (file.Read(&source[0], length) != length) + { + NazaraError("Failed to read program file"); + return {}; + } + + return Parse(Tokenize(std::string_view(reinterpret_cast(source.data()), source.size()))); + } +} diff --git a/src/Nazara/Shader/ShaderNodes.cpp b/src/Nazara/Shader/ShaderNodes.cpp deleted file mode 100644 index bdc2897db..000000000 --- a/src/Nazara/Shader/ShaderNodes.cpp +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include -#include -#include -#include -#include - -namespace Nz::ShaderNodes -{ - Node::~Node() = default; - - ExpressionCategory Expression::GetExpressionCategory() const - { - return ExpressionCategory::RValue; - } - - void ExpressionStatement::Visit(ShaderAstVisitor& visitor) - { - visitor.Visit(*this); - } - - - void ConditionalStatement::Visit(ShaderAstVisitor& visitor) - { - if (visitor.IsConditionEnabled(conditionName)) - statement->Visit(visitor); - } - - - void StatementBlock::Visit(ShaderAstVisitor& visitor) - { - visitor.Visit(*this); - } - - - void DeclareVariable::Visit(ShaderAstVisitor& visitor) - { - visitor.Visit(*this); - } - - - ExpressionCategory Identifier::GetExpressionCategory() const - { - return ExpressionCategory::LValue; - } - - ShaderExpressionType Identifier::GetExpressionType() const - { - assert(var); - return var->type; - } - - void Identifier::Visit(ShaderAstVisitor& visitor) - { - visitor.Visit(*this); - } - - ExpressionCategory AccessMember::GetExpressionCategory() const - { - return structExpr->GetExpressionCategory(); - } - - ShaderExpressionType AccessMember::GetExpressionType() const - { - return exprType; - } - - void AccessMember::Visit(ShaderAstVisitor& visitor) - { - visitor.Visit(*this); - } - - ShaderExpressionType AssignOp::GetExpressionType() const - { - return left->GetExpressionType(); - } - - void AssignOp::Visit(ShaderAstVisitor& visitor) - { - visitor.Visit(*this); - } - - - ShaderExpressionType BinaryOp::GetExpressionType() const - { - std::optional exprType; - - switch (op) - { - case BinaryType::Add: - case BinaryType::Substract: - exprType = left->GetExpressionType(); - break; - - case BinaryType::Divide: - case BinaryType::Multiply: - { - const ShaderExpressionType& leftExprType = left->GetExpressionType(); - assert(IsBasicType(leftExprType)); - - const ShaderExpressionType& rightExprType = right->GetExpressionType(); - assert(IsBasicType(rightExprType)); - - switch (std::get(leftExprType)) - { - case BasicType::Boolean: - case BasicType::Float2: - case BasicType::Float3: - case BasicType::Float4: - case BasicType::Int2: - case BasicType::Int3: - case BasicType::Int4: - case BasicType::UInt2: - case BasicType::UInt3: - case BasicType::UInt4: - exprType = leftExprType; - break; - - case BasicType::Float1: - case BasicType::Int1: - case BasicType::Mat4x4: - case BasicType::UInt1: - exprType = rightExprType; - break; - - case BasicType::Sampler2D: - case BasicType::Void: - break; - } - - break; - } - - case BinaryType::Equality: - exprType = BasicType::Boolean; - break; - } - - NazaraAssert(exprType.has_value(), "Unhandled builtin"); - - return *exprType; - } - - void BinaryOp::Visit(ShaderAstVisitor& visitor) - { - visitor.Visit(*this); - } - - - void Branch::Visit(ShaderAstVisitor& visitor) - { - visitor.Visit(*this); - } - - - ShaderExpressionType Constant::GetExpressionType() const - { - return std::visit([&](auto&& arg) - { - using T = std::decay_t; - - if constexpr (std::is_same_v) - return ShaderNodes::BasicType::Boolean; - else if constexpr (std::is_same_v) - return ShaderNodes::BasicType::Float1; - else if constexpr (std::is_same_v) - return ShaderNodes::BasicType::Int1; - else if constexpr (std::is_same_v) - return ShaderNodes::BasicType::Int1; - else if constexpr (std::is_same_v) - return ShaderNodes::BasicType::Float2; - else if constexpr (std::is_same_v) - return ShaderNodes::BasicType::Float3; - else if constexpr (std::is_same_v) - return ShaderNodes::BasicType::Float4; - else if constexpr (std::is_same_v) - return ShaderNodes::BasicType::Int2; - else if constexpr (std::is_same_v) - return ShaderNodes::BasicType::Int3; - else if constexpr (std::is_same_v) - return ShaderNodes::BasicType::Int4; - else - static_assert(AlwaysFalse::value, "non-exhaustive visitor"); - }, value); - } - - void Constant::Visit(ShaderAstVisitor& visitor) - { - visitor.Visit(*this); - } - - ShaderExpressionType Cast::GetExpressionType() const - { - return exprType; - } - - void Cast::Visit(ShaderAstVisitor& visitor) - { - visitor.Visit(*this); - } - - - ExpressionCategory SwizzleOp::GetExpressionCategory() const - { - return expression->GetExpressionCategory(); - } - - ShaderExpressionType SwizzleOp::GetExpressionType() const - { - const ShaderExpressionType& exprType = expression->GetExpressionType(); - assert(IsBasicType(exprType)); - - return static_cast(UnderlyingCast(GetComponentType(std::get(exprType))) + componentCount - 1); - } - - void SwizzleOp::Visit(ShaderAstVisitor& visitor) - { - visitor.Visit(*this); - } - - - ShaderExpressionType Sample2D::GetExpressionType() const - { - return BasicType::Float4; - } - - void Sample2D::Visit(ShaderAstVisitor& visitor) - { - visitor.Visit(*this); - } - - - ShaderExpressionType IntrinsicCall::GetExpressionType() const - { - switch (intrinsic) - { - case IntrinsicType::CrossProduct: - return parameters.front()->GetExpressionType(); - - case IntrinsicType::DotProduct: - return BasicType::Float1; - } - - NazaraAssert(false, "Unhandled builtin"); - return BasicType::Void; - } - - void IntrinsicCall::Visit(ShaderAstVisitor& visitor) - { - visitor.Visit(*this); - } -} diff --git a/src/Nazara/Shader/ShaderVarVisitorExcept.cpp b/src/Nazara/Shader/ShaderVarVisitorExcept.cpp deleted file mode 100644 index 3629f86d1..000000000 --- a/src/Nazara/Shader/ShaderVarVisitorExcept.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include -#include - -namespace Nz -{ - void ShaderVarVisitorExcept::Visit(ShaderNodes::BuiltinVariable& /*var*/) - { - throw std::runtime_error("unhandled BuiltinVariable"); - } - - void ShaderVarVisitorExcept::Visit(ShaderNodes::InputVariable& /*var*/) - { - throw std::runtime_error("unhandled InputVariable"); - } - - void ShaderVarVisitorExcept::Visit(ShaderNodes::LocalVariable& /*var*/) - { - throw std::runtime_error("unhandled LocalVariable"); - } - - void ShaderVarVisitorExcept::Visit(ShaderNodes::OutputVariable& /*var*/) - { - throw std::runtime_error("unhandled OutputVariable"); - } - - void ShaderVarVisitorExcept::Visit(ShaderNodes::ParameterVariable& /*var*/) - { - throw std::runtime_error("unhandled ParameterVariable"); - } - - void ShaderVarVisitorExcept::Visit(ShaderNodes::UniformVariable& /*var*/) - { - throw std::runtime_error("unhandled UniformVariable"); - } -} diff --git a/src/Nazara/Shader/ShaderVariables.cpp b/src/Nazara/Shader/ShaderVariables.cpp deleted file mode 100644 index ebe520a0c..000000000 --- a/src/Nazara/Shader/ShaderVariables.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include -#include - -namespace Nz::ShaderNodes -{ - ShaderNodes::Variable::~Variable() = default; - - VariableType BuiltinVariable::GetType() const - { - return VariableType::BuiltinVariable; - } - - void BuiltinVariable::Visit(ShaderVarVisitor& visitor) - { - visitor.Visit(*this); - } - - - VariableType InputVariable::GetType() const - { - return VariableType::InputVariable; - } - - void InputVariable::Visit(ShaderVarVisitor& visitor) - { - visitor.Visit(*this); - } - - - VariableType LocalVariable::GetType() const - { - return VariableType::LocalVariable; - } - - void LocalVariable::Visit(ShaderVarVisitor& visitor) - { - visitor.Visit(*this); - } - - - VariableType OutputVariable::GetType() const - { - return VariableType::OutputVariable; - } - - void OutputVariable::Visit(ShaderVarVisitor& visitor) - { - visitor.Visit(*this); - } - - - VariableType ParameterVariable::GetType() const - { - return VariableType::ParameterVariable; - } - - void ParameterVariable::Visit(ShaderVarVisitor& visitor) - { - visitor.Visit(*this); - } - - - VariableType UniformVariable::GetType() const - { - return VariableType::UniformVariable; - } - - void UniformVariable::Visit(ShaderVarVisitor& visitor) - { - visitor.Visit(*this); - } -} diff --git a/src/Nazara/Shader/SpirvAstVisitor.cpp b/src/Nazara/Shader/SpirvAstVisitor.cpp index 4c419f987..b1980efa4 100644 --- a/src/Nazara/Shader/SpirvAstVisitor.cpp +++ b/src/Nazara/Shader/SpirvAstVisitor.cpp @@ -3,53 +3,74 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include +#include #include #include #include #include #include +#include #include namespace Nz { - UInt32 SpirvAstVisitor::EvaluateExpression(const ShaderNodes::ExpressionPtr& expr) + UInt32 SpirvAstVisitor::AllocateResultId() { - Visit(expr); + return m_writer.AllocateResultId(); + } + + UInt32 SpirvAstVisitor::EvaluateExpression(ShaderAst::ExpressionPtr& expr) + { + expr->Visit(*this); assert(m_resultIds.size() == 1); return PopResultId(); } - void SpirvAstVisitor::Visit(ShaderNodes::AccessMember& node) + auto SpirvAstVisitor::GetVariable(std::size_t varIndex) const -> const Variable& { - SpirvExpressionLoad accessMemberVisitor(m_writer); + assert(varIndex < m_variables.size()); + assert(m_variables[varIndex]); + return *m_variables[varIndex]; + } + + void SpirvAstVisitor::Visit(ShaderAst::AccessIndexExpression& node) + { + SpirvExpressionLoad accessMemberVisitor(m_writer, *this, *m_currentBlock); PushResultId(accessMemberVisitor.Evaluate(node)); } - void SpirvAstVisitor::Visit(ShaderNodes::AssignOp& node) + void SpirvAstVisitor::Visit(ShaderAst::AssignExpression& node) { UInt32 resultId = EvaluateExpression(node.right); - SpirvExpressionStore storeVisitor(m_writer); + SpirvExpressionStore storeVisitor(m_writer, *this, *m_currentBlock); storeVisitor.Store(node.left, resultId); PushResultId(resultId); } - void SpirvAstVisitor::Visit(ShaderNodes::BinaryOp& node) + void SpirvAstVisitor::Visit(ShaderAst::BinaryExpression& node) { - ShaderExpressionType resultExprType = node.GetExpressionType(); - assert(IsBasicType(resultExprType)); + auto RetrieveBaseType = [](const ShaderAst::ExpressionType& exprType) + { + if (IsPrimitiveType(exprType)) + return std::get(exprType); + else if (IsVectorType(exprType)) + return std::get(exprType).type; + else if (IsMatrixType(exprType)) + return std::get(exprType).type; + else + throw std::runtime_error("unexpected type"); + }; - const ShaderExpressionType& leftExprType = node.left->GetExpressionType(); - assert(IsBasicType(leftExprType)); + const ShaderAst::ExpressionType& resultType = GetExpressionType(node); + const ShaderAst::ExpressionType& leftType = GetExpressionType(*node.left); + const ShaderAst::ExpressionType& rightType = GetExpressionType(*node.right); - const ShaderExpressionType& rightExprType = node.right->GetExpressionType(); - assert(IsBasicType(rightExprType)); - - ShaderNodes::BasicType resultType = std::get(resultExprType); - ShaderNodes::BasicType leftType = std::get(leftExprType); - ShaderNodes::BasicType rightType = std::get(rightExprType); + ShaderAst::PrimitiveType leftTypeBase = RetrieveBaseType(leftType); + //ShaderAst::PrimitiveType rightTypeBase = RetrieveBaseType(rightType); UInt32 leftOperand = EvaluateExpression(node.left); @@ -62,207 +83,225 @@ namespace Nz { switch (node.op) { - case ShaderNodes::BinaryType::Add: + case ShaderAst::BinaryType::Add: { - switch (leftType) + switch (leftTypeBase) { - case ShaderNodes::BasicType::Float1: - case ShaderNodes::BasicType::Float2: - case ShaderNodes::BasicType::Float3: - case ShaderNodes::BasicType::Float4: - case ShaderNodes::BasicType::Mat4x4: + case ShaderAst::PrimitiveType::Float32: return SpirvOp::OpFAdd; - case ShaderNodes::BasicType::Int1: - case ShaderNodes::BasicType::Int2: - case ShaderNodes::BasicType::Int3: - case ShaderNodes::BasicType::Int4: - case ShaderNodes::BasicType::UInt1: - case ShaderNodes::BasicType::UInt2: - case ShaderNodes::BasicType::UInt3: - case ShaderNodes::BasicType::UInt4: + case ShaderAst::PrimitiveType::Int32: + case ShaderAst::PrimitiveType::UInt32: return SpirvOp::OpIAdd; - case ShaderNodes::BasicType::Boolean: - case ShaderNodes::BasicType::Sampler2D: - case ShaderNodes::BasicType::Void: + case ShaderAst::PrimitiveType::Boolean: break; } break; } - case ShaderNodes::BinaryType::Substract: + case ShaderAst::BinaryType::Subtract: { - switch (leftType) + switch (leftTypeBase) { - case ShaderNodes::BasicType::Float1: - case ShaderNodes::BasicType::Float2: - case ShaderNodes::BasicType::Float3: - case ShaderNodes::BasicType::Float4: - case ShaderNodes::BasicType::Mat4x4: + case ShaderAst::PrimitiveType::Float32: return SpirvOp::OpFSub; - case ShaderNodes::BasicType::Int1: - case ShaderNodes::BasicType::Int2: - case ShaderNodes::BasicType::Int3: - case ShaderNodes::BasicType::Int4: - case ShaderNodes::BasicType::UInt1: - case ShaderNodes::BasicType::UInt2: - case ShaderNodes::BasicType::UInt3: - case ShaderNodes::BasicType::UInt4: + case ShaderAst::PrimitiveType::Int32: + case ShaderAst::PrimitiveType::UInt32: return SpirvOp::OpISub; - case ShaderNodes::BasicType::Boolean: - case ShaderNodes::BasicType::Sampler2D: - case ShaderNodes::BasicType::Void: + case ShaderAst::PrimitiveType::Boolean: break; } break; } - case ShaderNodes::BinaryType::Divide: + case ShaderAst::BinaryType::Divide: { - switch (leftType) + switch (leftTypeBase) { - case ShaderNodes::BasicType::Float1: - case ShaderNodes::BasicType::Float2: - case ShaderNodes::BasicType::Float3: - case ShaderNodes::BasicType::Float4: - case ShaderNodes::BasicType::Mat4x4: + case ShaderAst::PrimitiveType::Float32: return SpirvOp::OpFDiv; - case ShaderNodes::BasicType::Int1: - case ShaderNodes::BasicType::Int2: - case ShaderNodes::BasicType::Int3: - case ShaderNodes::BasicType::Int4: + case ShaderAst::PrimitiveType::Int32: return SpirvOp::OpSDiv; - case ShaderNodes::BasicType::UInt1: - case ShaderNodes::BasicType::UInt2: - case ShaderNodes::BasicType::UInt3: - case ShaderNodes::BasicType::UInt4: + case ShaderAst::PrimitiveType::UInt32: return SpirvOp::OpUDiv; - case ShaderNodes::BasicType::Boolean: - case ShaderNodes::BasicType::Sampler2D: - case ShaderNodes::BasicType::Void: + case ShaderAst::PrimitiveType::Boolean: break; } break; } - case ShaderNodes::BinaryType::Equality: + case ShaderAst::BinaryType::CompEq: { - switch (leftType) + switch (leftTypeBase) { - case ShaderNodes::BasicType::Boolean: + case ShaderAst::PrimitiveType::Boolean: return SpirvOp::OpLogicalEqual; - case ShaderNodes::BasicType::Float1: - case ShaderNodes::BasicType::Float2: - case ShaderNodes::BasicType::Float3: - case ShaderNodes::BasicType::Float4: - case ShaderNodes::BasicType::Mat4x4: + case ShaderAst::PrimitiveType::Float32: return SpirvOp::OpFOrdEqual; - case ShaderNodes::BasicType::Int1: - case ShaderNodes::BasicType::Int2: - case ShaderNodes::BasicType::Int3: - case ShaderNodes::BasicType::Int4: - case ShaderNodes::BasicType::UInt1: - case ShaderNodes::BasicType::UInt2: - case ShaderNodes::BasicType::UInt3: - case ShaderNodes::BasicType::UInt4: + case ShaderAst::PrimitiveType::Int32: + case ShaderAst::PrimitiveType::UInt32: return SpirvOp::OpIEqual; + } - case ShaderNodes::BasicType::Sampler2D: - case ShaderNodes::BasicType::Void: + break; + } + + case ShaderAst::BinaryType::CompGe: + { + switch (leftTypeBase) + { + case ShaderAst::PrimitiveType::Float32: + return SpirvOp::OpFOrdGreaterThan; + + case ShaderAst::PrimitiveType::Int32: + return SpirvOp::OpSGreaterThan; + + case ShaderAst::PrimitiveType::UInt32: + return SpirvOp::OpUGreaterThan; + + case ShaderAst::PrimitiveType::Boolean: break; } break; } - - case ShaderNodes::BinaryType::Multiply: + + case ShaderAst::BinaryType::CompGt: { - switch (leftType) + switch (leftTypeBase) { - case ShaderNodes::BasicType::Float1: + case ShaderAst::PrimitiveType::Float32: + return SpirvOp::OpFOrdGreaterThanEqual; + + case ShaderAst::PrimitiveType::Int32: + return SpirvOp::OpSGreaterThanEqual; + + case ShaderAst::PrimitiveType::UInt32: + return SpirvOp::OpUGreaterThanEqual; + + case ShaderAst::PrimitiveType::Boolean: + break; + } + + break; + } + + case ShaderAst::BinaryType::CompLe: + { + switch (leftTypeBase) + { + case ShaderAst::PrimitiveType::Float32: + return SpirvOp::OpFOrdLessThanEqual; + + case ShaderAst::PrimitiveType::Int32: + return SpirvOp::OpSLessThanEqual; + + case ShaderAst::PrimitiveType::UInt32: + return SpirvOp::OpULessThanEqual; + + case ShaderAst::PrimitiveType::Boolean: + break; + } + + break; + } + + case ShaderAst::BinaryType::CompLt: + { + switch (leftTypeBase) + { + case ShaderAst::PrimitiveType::Float32: + return SpirvOp::OpFOrdLessThan; + + case ShaderAst::PrimitiveType::Int32: + return SpirvOp::OpSLessThan; + + case ShaderAst::PrimitiveType::UInt32: + return SpirvOp::OpULessThan; + + case ShaderAst::PrimitiveType::Boolean: + break; + } + + break; + } + + case ShaderAst::BinaryType::CompNe: + { + switch (leftTypeBase) + { + case ShaderAst::PrimitiveType::Boolean: + return SpirvOp::OpLogicalNotEqual; + + case ShaderAst::PrimitiveType::Float32: + return SpirvOp::OpFOrdNotEqual; + + case ShaderAst::PrimitiveType::Int32: + case ShaderAst::PrimitiveType::UInt32: + return SpirvOp::OpINotEqual; + } + + break; + } + + case ShaderAst::BinaryType::Multiply: + { + switch (leftTypeBase) + { + case ShaderAst::PrimitiveType::Float32: { - switch (rightType) + if (IsPrimitiveType(leftType)) { - case ShaderNodes::BasicType::Float1: - return SpirvOp::OpFMul; - - case ShaderNodes::BasicType::Float2: - case ShaderNodes::BasicType::Float3: - case ShaderNodes::BasicType::Float4: - swapOperands = true; - return SpirvOp::OpVectorTimesScalar; - - case ShaderNodes::BasicType::Mat4x4: + // Handle float * matrix|vector as matrix|vector * float + if (IsMatrixType(rightType)) + { swapOperands = true; return SpirvOp::OpMatrixTimesScalar; - - default: - break; - } - - break; - } - - case ShaderNodes::BasicType::Float2: - case ShaderNodes::BasicType::Float3: - case ShaderNodes::BasicType::Float4: - { - switch (rightType) - { - case ShaderNodes::BasicType::Float1: + } + else if (IsVectorType(rightType)) + { + swapOperands = true; return SpirvOp::OpVectorTimesScalar; - - case ShaderNodes::BasicType::Float2: - case ShaderNodes::BasicType::Float3: - case ShaderNodes::BasicType::Float4: - return SpirvOp::OpFMul; - - case ShaderNodes::BasicType::Mat4x4: - return SpirvOp::OpVectorTimesMatrix; - - default: - break; + } } - - break; - } - - case ShaderNodes::BasicType::Int1: - case ShaderNodes::BasicType::Int2: - case ShaderNodes::BasicType::Int3: - case ShaderNodes::BasicType::Int4: - case ShaderNodes::BasicType::UInt1: - case ShaderNodes::BasicType::UInt2: - case ShaderNodes::BasicType::UInt3: - case ShaderNodes::BasicType::UInt4: - return SpirvOp::OpIMul; - - case ShaderNodes::BasicType::Mat4x4: - { - switch (rightType) + else if (IsPrimitiveType(rightType)) { - case ShaderNodes::BasicType::Float1: return SpirvOp::OpMatrixTimesScalar; - case ShaderNodes::BasicType::Float4: return SpirvOp::OpMatrixTimesVector; - case ShaderNodes::BasicType::Mat4x4: return SpirvOp::OpMatrixTimesMatrix; - - default: - break; + if (IsMatrixType(leftType)) + return SpirvOp::OpMatrixTimesScalar; + else if (IsVectorType(leftType)) + return SpirvOp::OpVectorTimesScalar; + } + else if (IsMatrixType(leftType)) + { + if (IsMatrixType(rightType)) + return SpirvOp::OpMatrixTimesMatrix; + else if (IsVectorType(rightType)) + return SpirvOp::OpMatrixTimesVector; + } + else if (IsMatrixType(rightType)) + { + assert(IsVectorType(leftType)); + return SpirvOp::OpVectorTimesMatrix; } - break; + return SpirvOp::OpFMul; } + case ShaderAst::PrimitiveType::Int32: + case ShaderAst::PrimitiveType::UInt32: + return SpirvOp::OpIMul; + default: break; } @@ -278,42 +317,274 @@ namespace Nz if (swapOperands) std::swap(leftOperand, rightOperand); - m_writer.GetInstructions().Append(op, m_writer.GetTypeId(resultType), resultId, leftOperand, rightOperand); + if (node.op == ShaderAst::BinaryType::Divide) + { + //TODO: Handle other cases + if (IsVectorType(leftType) && IsPrimitiveType(rightType)) + { + const ShaderAst::VectorType& leftVec = std::get(leftType); + + UInt32 vecType = m_writer.GetTypeId(leftType); + + UInt32 rightAsVec = m_writer.AllocateResultId(); + m_currentBlock->AppendVariadic(SpirvOp::OpCompositeConstruct, [&](auto&& append) + { + append(vecType); + append(rightAsVec); + + for (std::size_t i = 0; i < leftVec.componentCount; ++i) + append(rightOperand); + }); + + rightOperand = rightAsVec; + } + else if (leftType != rightType) + throw std::runtime_error("unexpected division operands"); + } + + m_currentBlock->Append(op, m_writer.GetTypeId(resultType), resultId, leftOperand, rightOperand); PushResultId(resultId); } - void SpirvAstVisitor::Visit(ShaderNodes::Cast& node) + void SpirvAstVisitor::Visit(ShaderAst::BranchStatement& node) { - const ShaderExpressionType& targetExprType = node.exprType; - assert(IsBasicType(targetExprType)); + assert(!node.condStatements.empty()); + auto& firstCond = node.condStatements.front(); - ShaderNodes::BasicType targetType = std::get(targetExprType); + UInt32 previousConditionId = EvaluateExpression(firstCond.condition); + SpirvBlock previousContentBlock(m_writer); + m_currentBlock = &previousContentBlock; - StackVector exprResults = NazaraStackVector(UInt32, node.expressions.size()); + firstCond.statement->Visit(*this); - for (const auto& exprPtr : node.expressions) + SpirvBlock mergeBlock(m_writer); + m_functionBlocks.back().Append(SpirvOp::OpSelectionMerge, mergeBlock.GetLabelId(), SpirvSelectionControl::None); + + std::optional nextBlock; + for (std::size_t statementIndex = 1; statementIndex < node.condStatements.size(); ++statementIndex) { - if (!exprPtr) - break; + auto& statement = node.condStatements[statementIndex]; - exprResults.push_back(EvaluateExpression(exprPtr)); + SpirvBlock contentBlock(m_writer); + + m_functionBlocks.back().Append(SpirvOp::OpBranchConditional, previousConditionId, previousContentBlock.GetLabelId(), contentBlock.GetLabelId()); + + previousConditionId = EvaluateExpression(statement.condition); + m_functionBlocks.emplace_back(std::move(previousContentBlock)); + previousContentBlock = std::move(contentBlock); + + m_currentBlock = &previousContentBlock; + + statement.statement->Visit(*this); } - UInt32 resultId = m_writer.AllocateResultId(); - - m_writer.GetInstructions().AppendVariadic(SpirvOp::OpCompositeConstruct, [&](const auto& appender) + if (node.elseStatement) { - appender(m_writer.GetTypeId(targetType)); - appender(resultId); + SpirvBlock elseBlock(m_writer); - for (UInt32 exprResultId : exprResults) - appender(exprResultId); + m_currentBlock = &elseBlock; + + node.elseStatement->Visit(*this); + + elseBlock.Append(SpirvOp::OpBranch, mergeBlock.GetLabelId()); //< FIXME: Shouldn't terminate twice + + m_functionBlocks.back().Append(SpirvOp::OpBranchConditional, previousConditionId, previousContentBlock.GetLabelId(), elseBlock.GetLabelId()); + m_functionBlocks.emplace_back(std::move(previousContentBlock)); + m_functionBlocks.emplace_back(std::move(elseBlock)); + } + else + { + m_functionBlocks.back().Append(SpirvOp::OpBranchConditional, previousConditionId, previousContentBlock.GetLabelId(), mergeBlock.GetLabelId()); + m_functionBlocks.emplace_back(std::move(previousContentBlock)); + } + + m_functionBlocks.emplace_back(std::move(mergeBlock)); + + m_currentBlock = &m_functionBlocks.back(); + } + + void SpirvAstVisitor::Visit(ShaderAst::CallFunctionExpression& node) + { + assert(std::holds_alternative(node.targetFunction)); + std::size_t functionIndex = std::get(node.targetFunction); + + UInt32 funcId = 0; + for (const auto& func : m_funcData) + { + if (func.funcIndex == functionIndex) + { + funcId = func.funcId; + break; + } + } + assert(funcId != 0); + + const FuncData& funcData = m_funcData[m_funcIndex]; + const auto& funcCall = funcData.funcCalls[m_funcCallIndex++]; + + StackArray parameterIds = NazaraStackArrayNoInit(UInt32, node.parameters.size()); + for (std::size_t i = 0; i < node.parameters.size(); ++i) + { + UInt32 resultId = EvaluateExpression(node.parameters[i]); + UInt32 varId = funcData.variables[funcCall.firstVarIndex + i].varId; + m_currentBlock->Append(SpirvOp::OpStore, varId, resultId); + + parameterIds[i] = varId; + } + + UInt32 resultId = AllocateResultId(); + m_currentBlock->AppendVariadic(SpirvOp::OpFunctionCall, [&](auto&& appender) + { + appender(m_writer.GetTypeId(ShaderAst::GetExpressionType(node))); + appender(resultId); + appender(funcId); + + for (std::size_t i = 0; i < node.parameters.size(); ++i) + appender(parameterIds[i]); }); PushResultId(resultId); } - void SpirvAstVisitor::Visit(ShaderNodes::Constant& node) + void SpirvAstVisitor::Visit(ShaderAst::CastExpression& node) + { + const ShaderAst::ExpressionType& targetExprType = node.targetType; + if (IsPrimitiveType(targetExprType)) + { + ShaderAst::PrimitiveType targetType = std::get(targetExprType); + + assert(node.expressions[0] && !node.expressions[1]); + ShaderAst::ExpressionPtr& expression = node.expressions[0]; + + assert(expression->cachedExpressionType.has_value()); + const ShaderAst::ExpressionType& exprType = expression->cachedExpressionType.value(); + assert(IsPrimitiveType(exprType)); + ShaderAst::PrimitiveType fromType = std::get(exprType); + + UInt32 fromId = EvaluateExpression(expression); + if (targetType == fromType) + return PushResultId(fromId); + + std::optional castOp; + switch (targetType) + { + case ShaderAst::PrimitiveType::Boolean: + throw std::runtime_error("unsupported cast to boolean"); + + case ShaderAst::PrimitiveType::Float32: + { + switch (fromType) + { + case ShaderAst::PrimitiveType::Boolean: + throw std::runtime_error("unsupported cast from boolean"); + + case ShaderAst::PrimitiveType::Float32: + break; //< Already handled + + case ShaderAst::PrimitiveType::Int32: + castOp = SpirvOp::OpConvertSToF; + break; + + case ShaderAst::PrimitiveType::UInt32: + castOp = SpirvOp::OpConvertUToF; + break; + } + break; + } + + case ShaderAst::PrimitiveType::Int32: + { + switch (fromType) + { + case ShaderAst::PrimitiveType::Boolean: + throw std::runtime_error("unsupported cast from boolean"); + + case ShaderAst::PrimitiveType::Float32: + castOp = SpirvOp::OpConvertFToS; + break; + + case ShaderAst::PrimitiveType::Int32: + break; //< Already handled + + case ShaderAst::PrimitiveType::UInt32: + castOp = SpirvOp::OpSConvert; + break; + } + break; + } + + case ShaderAst::PrimitiveType::UInt32: + { + switch (fromType) + { + case ShaderAst::PrimitiveType::Boolean: + throw std::runtime_error("unsupported cast from boolean"); + + case ShaderAst::PrimitiveType::Float32: + castOp = SpirvOp::OpConvertFToU; + break; + + case ShaderAst::PrimitiveType::Int32: + castOp = SpirvOp::OpUConvert; + break; + + case ShaderAst::PrimitiveType::UInt32: + break; //< Already handled + } + break; + } + } + + assert(castOp); + + UInt32 resultId = m_writer.AllocateResultId(); + m_currentBlock->Append(*castOp, m_writer.GetTypeId(targetType), resultId, fromId); + + throw std::runtime_error("toudou"); + } + else + { + assert(IsVectorType(targetExprType)); + StackVector exprResults = NazaraStackVector(UInt32, node.expressions.size()); + + for (auto& exprPtr : node.expressions) + { + if (!exprPtr) + break; + + exprResults.push_back(EvaluateExpression(exprPtr)); + } + + UInt32 resultId = m_writer.AllocateResultId(); + + m_currentBlock->AppendVariadic(SpirvOp::OpCompositeConstruct, [&](const auto& appender) + { + appender(m_writer.GetTypeId(targetExprType)); + appender(resultId); + + for (UInt32 exprResultId : exprResults) + appender(exprResultId); + }); + + PushResultId(resultId); + } + } + + void SpirvAstVisitor::Visit(ShaderAst::ConditionalExpression& node) + { + if (m_writer.IsOptionEnabled(node.optionIndex)) + node.truePath->Visit(*this); + else + node.falsePath->Visit(*this); + } + + void SpirvAstVisitor::Visit(ShaderAst::ConditionalStatement& node) + { + if (m_writer.IsOptionEnabled(node.optionIndex)) + node.statement->Visit(*this); + } + + void SpirvAstVisitor::Visit(ShaderAst::ConstantExpression& node) { std::visit([&] (const auto& value) { @@ -321,90 +592,312 @@ namespace Nz }, node.value); } - void SpirvAstVisitor::Visit(ShaderNodes::DeclareVariable& node) + void SpirvAstVisitor::Visit(ShaderAst::DeclareExternalStatement& node) { - if (node.expression) - { - assert(node.variable->GetType() == ShaderNodes::VariableType::LocalVariable); + assert(node.varIndex); - const auto& localVar = static_cast(*node.variable); - m_writer.WriteLocalVariable(localVar.name, EvaluateExpression(node.expression)); + std::size_t varIndex = *node.varIndex; + for (auto&& extVar : node.externalVars) + RegisterExternalVariable(varIndex++, extVar.type); + } + + void SpirvAstVisitor::Visit(ShaderAst::DeclareFunctionStatement& node) + { + assert(node.funcIndex); + m_funcIndex = *node.funcIndex; + m_funcCallIndex = 0; + + auto& func = m_funcData[m_funcIndex]; + + m_instructions.Append(SpirvOp::OpFunction, func.returnTypeId, func.funcId, 0, func.funcTypeId); + + if (!func.parameters.empty()) + { + std::size_t varIndex = *node.varIndex; + for (const auto& param : func.parameters) + { + UInt32 paramResultId = m_writer.AllocateResultId(); + m_instructions.Append(SpirvOp::OpFunctionParameter, param.pointerTypeId, paramResultId); + + RegisterVariable(varIndex++, param.typeId, paramResultId, SpirvStorageClass::Function); + } + } + + m_functionBlocks.clear(); + + m_currentBlock = &m_functionBlocks.emplace_back(m_writer); + CallOnExit resetCurrentBlock([&] { m_currentBlock = nullptr; }); + + for (auto& var : func.variables) + { + var.varId = m_writer.AllocateResultId(); + m_currentBlock->Append(SpirvOp::OpVariable, var.typeId, var.varId, SpirvStorageClass::Function); + } + + if (func.entryPointData) + { + auto& entryPointData = *func.entryPointData; + if (entryPointData.inputStruct) + { + auto& inputStruct = *entryPointData.inputStruct; + + std::size_t varIndex = *node.varIndex; + + UInt32 paramId = m_writer.AllocateResultId(); + m_currentBlock->Append(SpirvOp::OpVariable, inputStruct.pointerId, paramId, SpirvStorageClass::Function); + + for (const auto& input : entryPointData.inputs) + { + UInt32 resultId = m_writer.AllocateResultId(); + m_currentBlock->Append(SpirvOp::OpAccessChain, input.memberPointerId, resultId, paramId, input.memberIndexConstantId); + m_currentBlock->Append(SpirvOp::OpCopyMemory, resultId, input.varId); + } + + RegisterVariable(varIndex, inputStruct.typeId, paramId, SpirvStorageClass::Function); + } + } + + for (auto& statementPtr : node.statements) + statementPtr->Visit(*this); + + // Add implicit return + if (!m_functionBlocks.back().IsTerminated()) + m_functionBlocks.back().Append(SpirvOp::OpReturn); + + for (SpirvBlock& block : m_functionBlocks) + m_instructions.AppendSection(block); + + m_instructions.Append(SpirvOp::OpFunctionEnd); + } + + void SpirvAstVisitor::Visit(ShaderAst::DeclareOptionStatement& /*node*/) + { + /* nothing to do */ + } + + void SpirvAstVisitor::Visit(ShaderAst::DeclareStructStatement& node) + { + assert(node.structIndex); + RegisterStruct(*node.structIndex, node.description); + } + + void SpirvAstVisitor::Visit(ShaderAst::DeclareVariableStatement& node) + { + const auto& func = m_funcData[m_funcIndex]; + + UInt32 typeId = m_writer.GetTypeId(node.varType); + + assert(node.varIndex); + auto varIt = func.varIndexToVarId.find(*node.varIndex); + UInt32 varId = func.variables[varIt->second].varId; + + RegisterVariable(*node.varIndex, typeId, varId, SpirvStorageClass::Function); + + if (node.initialExpression) + { + UInt32 value = EvaluateExpression(node.initialExpression); + m_currentBlock->Append(SpirvOp::OpStore, varId, value); } } - void SpirvAstVisitor::Visit(ShaderNodes::ExpressionStatement& node) + void SpirvAstVisitor::Visit(ShaderAst::DiscardStatement& /*node*/) { - Visit(node.expression); + m_currentBlock->Append(SpirvOp::OpKill); + } + + void SpirvAstVisitor::Visit(ShaderAst::ExpressionStatement& node) + { + node.expression->Visit(*this); + PopResultId(); } - void SpirvAstVisitor::Visit(ShaderNodes::Identifier& node) - { - SpirvExpressionLoad loadVisitor(m_writer); - PushResultId(loadVisitor.Evaluate(node)); - } - - void SpirvAstVisitor::Visit(ShaderNodes::IntrinsicCall& node) + void SpirvAstVisitor::Visit(ShaderAst::IntrinsicExpression& node) { switch (node.intrinsic) { - case ShaderNodes::IntrinsicType::DotProduct: + case ShaderAst::IntrinsicType::DotProduct: { - const ShaderExpressionType& vecExprType = node.parameters[0]->GetExpressionType(); - assert(IsBasicType(vecExprType)); + const ShaderAst::ExpressionType& vecExprType = GetExpressionType(*node.parameters[0]); + assert(IsVectorType(vecExprType)); - ShaderNodes::BasicType vecType = std::get(vecExprType); + const ShaderAst::VectorType& vecType = std::get(vecExprType); - UInt32 typeId = m_writer.GetTypeId(node.GetComponentType(vecType)); + UInt32 typeId = m_writer.GetTypeId(vecType.type); UInt32 vec1 = EvaluateExpression(node.parameters[0]); UInt32 vec2 = EvaluateExpression(node.parameters[1]); UInt32 resultId = m_writer.AllocateResultId(); - m_writer.GetInstructions().Append(SpirvOp::OpDot, typeId, resultId, vec1, vec2); + m_currentBlock->Append(SpirvOp::OpDot, typeId, resultId, vec1, vec2); PushResultId(resultId); break; } - case ShaderNodes::IntrinsicType::CrossProduct: + case ShaderAst::IntrinsicType::Length: + { + UInt32 glslInstructionSet = m_writer.GetExtendedInstructionSet("GLSL.std.450"); + + const ShaderAst::ExpressionType& vecExprType = GetExpressionType(*node.parameters[0]); + assert(IsVectorType(vecExprType)); + + const ShaderAst::VectorType& vecType = std::get(vecExprType); + UInt32 typeId = m_writer.GetTypeId(vecType.type); + + UInt32 vec = EvaluateExpression(node.parameters[0]); + + UInt32 resultId = m_writer.AllocateResultId(); + + m_currentBlock->Append(SpirvOp::OpExtInst, typeId, resultId, glslInstructionSet, GLSLstd450Length, vec); + PushResultId(resultId); + break; + } + + case ShaderAst::IntrinsicType::Max: + case ShaderAst::IntrinsicType::Min: + { + UInt32 glslInstructionSet = m_writer.GetExtendedInstructionSet("GLSL.std.450"); + + const ShaderAst::ExpressionType& parameterType = GetExpressionType(*node.parameters[0]); + assert(IsPrimitiveType(parameterType) || IsVectorType(parameterType)); + UInt32 typeId = m_writer.GetTypeId(parameterType); + + ShaderAst::PrimitiveType basicType; + if (IsPrimitiveType(parameterType)) + basicType = std::get(parameterType); + else if (IsVectorType(parameterType)) + basicType = std::get(parameterType).type; + else + throw std::runtime_error("unexpected expression type"); + + GLSLstd450 op; + switch (basicType) + { + case ShaderAst::PrimitiveType::Boolean: + throw std::runtime_error("unexpected boolean for max/min intrinsic"); + + case ShaderAst::PrimitiveType::Float32: + op = (node.intrinsic == ShaderAst::IntrinsicType::Max) ? GLSLstd450FMax : GLSLstd450FMin; + break; + + case ShaderAst::PrimitiveType::Int32: + op = (node.intrinsic == ShaderAst::IntrinsicType::Max) ? GLSLstd450SMax : GLSLstd450SMin; + break; + + case ShaderAst::PrimitiveType::UInt32: + op = (node.intrinsic == ShaderAst::IntrinsicType::Max) ? GLSLstd450UMax : GLSLstd450UMin; + break; + } + + UInt32 firstParam = EvaluateExpression(node.parameters[0]); + UInt32 secondParam = EvaluateExpression(node.parameters[1]); + UInt32 resultId = m_writer.AllocateResultId(); + + m_currentBlock->Append(SpirvOp::OpExtInst, typeId, resultId, glslInstructionSet, op, firstParam, secondParam); + PushResultId(resultId); + break; + } + + case ShaderAst::IntrinsicType::Pow: + { + UInt32 glslInstructionSet = m_writer.GetExtendedInstructionSet("GLSL.std.450"); + + const ShaderAst::ExpressionType& parameterType = GetExpressionType(*node.parameters[0]); + assert(IsPrimitiveType(parameterType) || IsVectorType(parameterType)); + UInt32 typeId = m_writer.GetTypeId(parameterType); + + ShaderAst::PrimitiveType basicType; + if (IsPrimitiveType(parameterType)) + basicType = std::get(parameterType); + else if (IsVectorType(parameterType)) + basicType = std::get(parameterType).type; + else + throw std::runtime_error("unexpected expression type"); + + UInt32 firstParam = EvaluateExpression(node.parameters[0]); + UInt32 secondParam = EvaluateExpression(node.parameters[1]); + UInt32 resultId = m_writer.AllocateResultId(); + + m_currentBlock->Append(SpirvOp::OpExtInst, typeId, resultId, glslInstructionSet, GLSLstd450Pow, firstParam, secondParam); + PushResultId(resultId); + break; + } + + case ShaderAst::IntrinsicType::SampleTexture: + { + UInt32 typeId = m_writer.GetTypeId(ShaderAst::VectorType{4, ShaderAst::PrimitiveType::Float32}); + + UInt32 samplerId = EvaluateExpression(node.parameters[0]); + UInt32 coordinatesId = EvaluateExpression(node.parameters[1]); + UInt32 resultId = m_writer.AllocateResultId(); + + m_currentBlock->Append(SpirvOp::OpImageSampleImplicitLod, typeId, resultId, samplerId, coordinatesId); + PushResultId(resultId); + break; + } + + case ShaderAst::IntrinsicType::CrossProduct: default: throw std::runtime_error("not yet implemented"); } } - void SpirvAstVisitor::Visit(ShaderNodes::Sample2D& node) + void SpirvAstVisitor::Visit(ShaderAst::NoOpStatement& /*node*/) { - UInt32 typeId = m_writer.GetTypeId(ShaderNodes::BasicType::Float4); - - UInt32 samplerId = EvaluateExpression(node.sampler); - UInt32 coordinatesId = EvaluateExpression(node.coordinates); - UInt32 resultId = m_writer.AllocateResultId(); - - m_writer.GetInstructions().Append(SpirvOp::OpImageSampleImplicitLod, typeId, resultId, samplerId, coordinatesId); - PushResultId(resultId); + // nothing to do } - void SpirvAstVisitor::Visit(ShaderNodes::StatementBlock& node) + void SpirvAstVisitor::Visit(ShaderAst::MultiStatement& node) { for (auto& statement : node.statements) - Visit(statement); + statement->Visit(*this); } - void SpirvAstVisitor::Visit(ShaderNodes::SwizzleOp& node) + void SpirvAstVisitor::Visit(ShaderAst::ReturnStatement& node) { - const ShaderExpressionType& targetExprType = node.GetExpressionType(); - assert(IsBasicType(targetExprType)); + if (node.returnExpr) + { + // Handle entry point return + const auto& func = m_funcData[m_funcIndex]; + if (func.entryPointData) + { + auto& entryPointData = *func.entryPointData; + if (entryPointData.outputStructTypeId) + { + UInt32 paramId = EvaluateExpression(node.returnExpr); + for (const auto& output : entryPointData.outputs) + { + UInt32 resultId = m_writer.AllocateResultId(); + m_currentBlock->Append(SpirvOp::OpCompositeExtract, output.typeId, resultId, paramId, output.memberIndex); + m_currentBlock->Append(SpirvOp::OpStore, output.varId, resultId); + } + } - ShaderNodes::BasicType targetType = std::get(targetExprType); + m_currentBlock->Append(SpirvOp::OpReturn); + } + else + m_currentBlock->Append(SpirvOp::OpReturnValue, EvaluateExpression(node.returnExpr)); + } + else + m_currentBlock->Append(SpirvOp::OpReturn); + } + void SpirvAstVisitor::Visit(ShaderAst::SwizzleExpression& node) + { UInt32 exprResultId = EvaluateExpression(node.expression); UInt32 resultId = m_writer.AllocateResultId(); + const ShaderAst::ExpressionType& targetExprType = GetExpressionType(node); + if (node.componentCount > 1) { + assert(IsVectorType(targetExprType)); + + const ShaderAst::VectorType& targetType = std::get(targetExprType); + // Swizzling is implemented via SpirvOp::OpVectorShuffle using the same vector twice as operands - m_writer.GetInstructions().AppendVariadic(SpirvOp::OpVectorShuffle, [&](const auto& appender) + m_currentBlock->AppendVariadic(SpirvOp::OpVectorShuffle, [&](const auto& appender) { appender(m_writer.GetTypeId(targetType)); appender(resultId); @@ -412,20 +905,91 @@ namespace Nz appender(exprResultId); for (std::size_t i = 0; i < node.componentCount; ++i) - appender(UInt32(node.components[0]) - UInt32(node.components[i])); + appender(UInt32(node.components[i])); }); } else { + assert(IsPrimitiveType(targetExprType)); + + ShaderAst::PrimitiveType targetType = std::get(targetExprType); + // Extract a single component from the vector assert(node.componentCount == 1); - m_writer.GetInstructions().Append(SpirvOp::OpCompositeExtract, m_writer.GetTypeId(targetType), resultId, exprResultId, UInt32(node.components[0]) - UInt32(ShaderNodes::SwizzleComponent::First) ); + m_currentBlock->Append(SpirvOp::OpCompositeExtract, m_writer.GetTypeId(targetType), resultId, exprResultId, UInt32(node.components[0]) - UInt32(ShaderAst::SwizzleComponent::First) ); } PushResultId(resultId); } + void SpirvAstVisitor::Visit(ShaderAst::VariableExpression& node) + { + SpirvExpressionLoad loadVisitor(m_writer, *this, *m_currentBlock); + PushResultId(loadVisitor.Evaluate(node)); + } + + void SpirvAstVisitor::Visit(ShaderAst::UnaryExpression& node) + { + const ShaderAst::ExpressionType& resultType = GetExpressionType(node); + const ShaderAst::ExpressionType& exprType = GetExpressionType(*node.expression); + + UInt32 operand = EvaluateExpression(node.expression); + + UInt32 resultId = [&] + { + switch (node.op) + { + case ShaderAst::UnaryType::LogicalNot: + { + assert(IsPrimitiveType(exprType)); + assert(std::get(resultType) == ShaderAst::PrimitiveType::Boolean); + + UInt32 resultId = m_writer.AllocateResultId(); + m_currentBlock->Append(SpirvOp::OpLogicalNot, m_writer.GetTypeId(resultType), resultId, operand); + + return resultId; + } + + case ShaderAst::UnaryType::Minus: + { + ShaderAst::PrimitiveType basicType; + if (IsPrimitiveType(exprType)) + basicType = std::get(exprType); + else if (IsVectorType(exprType)) + basicType = std::get(exprType).type; + else + throw std::runtime_error("unexpected expression type"); + + UInt32 resultId = m_writer.AllocateResultId(); + + switch (basicType) + { + case ShaderAst::PrimitiveType::Float32: + m_currentBlock->Append(SpirvOp::OpFNegate, m_writer.GetTypeId(resultType), resultId, operand); + return resultId; + + case ShaderAst::PrimitiveType::Int32: + case ShaderAst::PrimitiveType::UInt32: + m_currentBlock->Append(SpirvOp::OpSNegate, m_writer.GetTypeId(resultType), resultId, operand); + return resultId; + + default: + break; + } + } + + case ShaderAst::UnaryType::Plus: + PushResultId(operand); //< No-op + break; + } + + throw std::runtime_error("unexpected unary operation"); + }(); + + PushResultId(resultId); + } + void SpirvAstVisitor::PushResultId(UInt32 value) { m_resultIds.push_back(value); diff --git a/src/Nazara/Shader/SpirvConstantCache.cpp b/src/Nazara/Shader/SpirvConstantCache.cpp index b8489ce76..d569bb22f 100644 --- a/src/Nazara/Shader/SpirvConstantCache.cpp +++ b/src/Nazara/Shader/SpirvConstantCache.cpp @@ -3,7 +3,6 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include -#include #include #include #include @@ -18,6 +17,7 @@ namespace Nz template overloaded(Ts...)->overloaded; } + struct SpirvConstantCache::Eq { bool Compare(const ConstantBool& lhs, const ConstantBool& rhs) const @@ -109,6 +109,9 @@ namespace Nz if (lhs.debugName != rhs.debugName) return false; + if (lhs.funcId != rhs.funcId) + return false; + if (!Compare(lhs.initializer, rhs.initializer)) return false; @@ -228,12 +231,12 @@ namespace Nz void Register(const Image& image) { - Register(image.sampledType); + cache.Register(*image.sampledType); } void Register(const Function& func) { - Register(func.returnType); + cache.Register(*func.returnType); Register(func.parameters); } @@ -353,6 +356,12 @@ namespace Nz }, v); } + void Register(const std::vector& lhs) + { + for (std::size_t i = 0; i < lhs.size(); ++i) + cache.Register(*lhs[i]); + } + template void Register(const std::vector& lhs) { @@ -390,6 +399,7 @@ namespace Nz tsl::ordered_map, UInt32 /*id*/, AnyHasher, Eq> ids; tsl::ordered_map variableIds; tsl::ordered_map structureSizes; + StructCallback structCallback; UInt32& nextResultId; }; @@ -401,6 +411,201 @@ namespace Nz SpirvConstantCache::SpirvConstantCache(SpirvConstantCache&& cache) noexcept = default; SpirvConstantCache::~SpirvConstantCache() = default; + + auto SpirvConstantCache::BuildConstant(const ShaderAst::ConstantValue& value) const -> ConstantPtr + { + return std::make_shared(std::visit([&](auto&& arg) -> SpirvConstantCache::AnyConstant + { + using T = std::decay_t; + + if constexpr (std::is_same_v) + return ConstantBool{ arg }; + else if constexpr (std::is_same_v || std::is_same_v || std::is_same_v) + return ConstantScalar{ arg }; + else if constexpr (std::is_same_v || std::is_same_v) + { + return ConstantComposite{ + BuildType(ShaderAst::VectorType{ 2, (std::is_same_v) ? ShaderAst::PrimitiveType::Float32 : ShaderAst::PrimitiveType::Int32 }), + { + BuildConstant(arg.x), + BuildConstant(arg.y) + } + }; + } + else if constexpr (std::is_same_v || std::is_same_v) + { + return ConstantComposite{ + BuildType(ShaderAst::VectorType{ 3, (std::is_same_v) ? ShaderAst::PrimitiveType::Float32 : ShaderAst::PrimitiveType::Int32 }), + { + BuildConstant(arg.x), + BuildConstant(arg.y), + BuildConstant(arg.z) + } + }; + } + else if constexpr (std::is_same_v || std::is_same_v) + { + return ConstantComposite{ + BuildType(ShaderAst::VectorType{ 4, (std::is_same_v) ? ShaderAst::PrimitiveType::Float32 : ShaderAst::PrimitiveType::Int32 }), + { + BuildConstant(arg.x), + BuildConstant(arg.y), + BuildConstant(arg.z), + BuildConstant(arg.w) + } + }; + } + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, value)); + } + + auto SpirvConstantCache::BuildFunctionType(const ShaderAst::ExpressionType& retType, const std::vector& parameters) const -> TypePtr + { + std::vector parameterTypes; + parameterTypes.reserve(parameters.size()); + + for (const auto& parameterType : parameters) + parameterTypes.push_back(BuildPointerType(parameterType, SpirvStorageClass::Function)); + + return std::make_shared(Function{ + BuildType(retType), + std::move(parameterTypes) + }); + } + + auto SpirvConstantCache::BuildPointerType(const ShaderAst::ExpressionType& type, SpirvStorageClass storageClass) const -> TypePtr + { + return std::make_shared(Pointer{ + BuildType(type), + storageClass + }); + } + + auto SpirvConstantCache::BuildPointerType(const ShaderAst::PrimitiveType& type, SpirvStorageClass storageClass) const -> TypePtr + { + return std::make_shared(Pointer{ + BuildType(type), + storageClass + }); + } + + auto SpirvConstantCache::BuildType(const ShaderAst::ExpressionType& type) const -> TypePtr + { + return std::visit([&](auto&& arg) -> TypePtr + { + return BuildType(arg); + }, type); + } + + auto SpirvConstantCache::BuildType(const ShaderAst::IdentifierType& /*type*/) const -> TypePtr + { + // No IdentifierType is expected (as they should have been resolved by now) + throw std::runtime_error("unexpected identifier"); + } + + auto SpirvConstantCache::BuildType(const ShaderAst::PrimitiveType& type) const -> TypePtr + { + return std::make_shared([&]() -> AnyType + { + switch (type) + { + case ShaderAst::PrimitiveType::Boolean: + return Bool{}; + + case ShaderAst::PrimitiveType::Float32: + return Float{ 32 }; + + case ShaderAst::PrimitiveType::Int32: + return Integer{ 32, true }; + + case ShaderAst::PrimitiveType::UInt32: + return Integer{ 32, false }; + } + + throw std::runtime_error("unexpected type"); + }()); + } + + auto SpirvConstantCache::BuildType(const ShaderAst::MatrixType& type) const -> TypePtr + { + return std::make_shared( + Matrix{ + BuildType(ShaderAst::VectorType { + UInt32(type.rowCount), type.type + }), + UInt32(type.columnCount) + }); + } + + auto SpirvConstantCache::BuildType(const ShaderAst::NoType& /*type*/) const -> TypePtr + { + return std::make_shared(Void{}); + } + + auto SpirvConstantCache::BuildType(const ShaderAst::SamplerType& type) const -> TypePtr + { + Image imageType; + imageType.sampled = true; + imageType.sampledType = BuildType(type.sampledType); + + switch (type.dim) + { + case ImageType::Cubemap: + imageType.dim = SpirvDim::Cube; + break; + + case ImageType::E1D_Array: + imageType.arrayed = true; + case ImageType::E1D: + imageType.dim = SpirvDim::Dim1D; + break; + + case ImageType::E2D_Array: + imageType.arrayed = true; + case ImageType::E2D: + imageType.dim = SpirvDim::Dim2D; + break; + + case ImageType::E3D: + imageType.dim = SpirvDim::Dim3D; + break; + } + + return std::make_shared(SampledImage{ std::make_shared(imageType) }); + } + + auto SpirvConstantCache::BuildType(const ShaderAst::StructType& type) const -> TypePtr + { + assert(m_internal->structCallback); + return BuildType(m_internal->structCallback(type.structIndex)); + } + + auto SpirvConstantCache::BuildType(const ShaderAst::StructDescription& structDesc) const -> TypePtr + { + Structure sType; + sType.name = structDesc.name; + + for (const auto& member : structDesc.members) + { + auto& sMembers = sType.members.emplace_back(); + sMembers.name = member.name; + sMembers.type = BuildType(member.type); + } + + return std::make_shared(std::move(sType)); + } + + auto SpirvConstantCache::BuildType(const ShaderAst::VectorType& type) const -> TypePtr + { + return std::make_shared(Vector{ BuildType(type.type), UInt32(type.componentCount) }); + } + + auto SpirvConstantCache::BuildType(const ShaderAst::UniformType& type) const -> TypePtr + { + assert(std::holds_alternative(type.containedType)); + return BuildType(std::get(type.containedType)); + } UInt32 SpirvConstantCache::GetId(const Constant& c) { @@ -415,7 +620,7 @@ namespace Nz { auto it = m_internal->ids.find(t.type); if (it == m_internal->ids.end()) - throw std::runtime_error("constant is not registered"); + throw std::runtime_error("type is not registered"); return it->second; } @@ -481,6 +686,11 @@ namespace Nz return it.value(); } + void SpirvConstantCache::SetStructCallback(StructCallback callback) + { + m_internal->structCallback = std::move(callback); + } + void SpirvConstantCache::Write(SpirvSection& annotations, SpirvSection& constants, SpirvSection& debugInfos) { for (auto&& [object, id] : m_internal->ids) @@ -516,165 +726,6 @@ namespace Nz SpirvConstantCache& SpirvConstantCache::operator=(SpirvConstantCache&& cache) noexcept = default; - auto SpirvConstantCache::BuildConstant(const ShaderConstantValue& value) -> ConstantPtr - { - return std::make_shared(std::visit([&](auto&& arg) -> SpirvConstantCache::AnyConstant - { - using T = std::decay_t; - - if constexpr (std::is_same_v) - return ConstantBool{ arg }; - else if constexpr (std::is_same_v || std::is_same_v || std::is_same_v) - return ConstantScalar{ arg }; - else if constexpr (std::is_same_v || std::is_same_v) - { - return ConstantComposite{ - BuildType((std::is_same_v) ? ShaderNodes::BasicType::Float2 : ShaderNodes::BasicType::Int2), - { - BuildConstant(arg.x), - BuildConstant(arg.y) - } - }; - } - else if constexpr (std::is_same_v || std::is_same_v) - { - return ConstantComposite{ - BuildType((std::is_same_v) ? ShaderNodes::BasicType::Float3 : ShaderNodes::BasicType::Int3), - { - BuildConstant(arg.x), - BuildConstant(arg.y), - BuildConstant(arg.z) - } - }; - } - else if constexpr (std::is_same_v || std::is_same_v) - { - return ConstantComposite{ - BuildType((std::is_same_v) ? ShaderNodes::BasicType::Float4 : ShaderNodes::BasicType::Int4), - { - BuildConstant(arg.x), - BuildConstant(arg.y), - BuildConstant(arg.z), - BuildConstant(arg.w) - } - }; - } - else - static_assert(AlwaysFalse::value, "non-exhaustive visitor"); - }, value)); - } - - auto SpirvConstantCache::BuildPointerType(const ShaderNodes::BasicType& type, SpirvStorageClass storageClass) -> TypePtr - { - return std::make_shared(SpirvConstantCache::Pointer{ - SpirvConstantCache::BuildType(type), - storageClass - }); - } - - auto SpirvConstantCache::BuildPointerType(const ShaderAst& shader, const ShaderExpressionType& type, SpirvStorageClass storageClass) -> TypePtr - { - return std::make_shared(SpirvConstantCache::Pointer{ - SpirvConstantCache::BuildType(shader, type), - storageClass - }); - } - - auto SpirvConstantCache::BuildType(const ShaderNodes::BasicType& type) -> TypePtr - { - return std::make_shared([&]() -> AnyType - { - switch (type) - { - case ShaderNodes::BasicType::Boolean: - return Bool{}; - - case ShaderNodes::BasicType::Float1: - return Float{ 32 }; - - case ShaderNodes::BasicType::Int1: - return Integer{ 32, true }; - - case ShaderNodes::BasicType::Float2: - case ShaderNodes::BasicType::Float3: - case ShaderNodes::BasicType::Float4: - case ShaderNodes::BasicType::Int2: - case ShaderNodes::BasicType::Int3: - case ShaderNodes::BasicType::Int4: - case ShaderNodes::BasicType::UInt2: - case ShaderNodes::BasicType::UInt3: - case ShaderNodes::BasicType::UInt4: - { - auto vecType = BuildType(ShaderNodes::Node::GetComponentType(type)); - UInt32 componentCount = ShaderNodes::Node::GetComponentCount(type); - - return Vector{ vecType, componentCount }; - } - - case ShaderNodes::BasicType::Mat4x4: - return Matrix{ BuildType(ShaderNodes::BasicType::Float4), 4u }; - - case ShaderNodes::BasicType::UInt1: - return Integer{ 32, false }; - - case ShaderNodes::BasicType::Void: - return Void{}; - - case ShaderNodes::BasicType::Sampler2D: - { - auto imageType = Image{ - {}, //< qualifier - {}, //< depth - {}, //< sampled - SpirvDim::Dim2D, //< dim - SpirvImageFormat::Unknown, //< format - BuildType(ShaderNodes::BasicType::Float1), //< sampledType - false, //< arrayed, - false //< multisampled - }; - - return SampledImage{ std::make_shared(imageType) }; - } - } - - throw std::runtime_error("unexpected type"); - }()); - } - - auto SpirvConstantCache::BuildType(const ShaderAst& shader, const ShaderExpressionType& type) -> TypePtr - { - return std::visit([&](auto&& arg) -> TypePtr - { - using T = std::decay_t; - if constexpr (std::is_same_v) - return BuildType(arg); - else if constexpr (std::is_same_v) - { - // Register struct members type - const auto& structs = shader.GetStructs(); - auto it = std::find_if(structs.begin(), structs.end(), [&](const auto& s) { return s.name == arg; }); - if (it == structs.end()) - throw std::runtime_error("struct " + arg + " has not been defined"); - - const ShaderAst::Struct& s = *it; - - Structure sType; - sType.name = s.name; - - for (const auto& member : s.members) - { - auto& sMembers = sType.members.emplace_back(); - sMembers.name = member.name; - sMembers.type = BuildType(shader, member.type); - } - - return std::make_shared(std::move(sType)); - } - else - static_assert(AlwaysFalse::value, "non-exhaustive visitor"); - }, type); - } - void SpirvConstantCache::Write(const AnyConstant& constant, UInt32 resultId, SpirvSection& constants) { std::visit([&](auto&& arg) @@ -682,7 +733,7 @@ namespace Nz using ConstantType = std::decay_t; if constexpr (std::is_same_v) - constants.Append((arg.value) ? SpirvOp::OpConstantTrue : SpirvOp::OpConstantFalse, resultId); + constants.Append((arg.value) ? SpirvOp::OpConstantTrue : SpirvOp::OpConstantFalse, GetId({ Bool{} }), resultId); else if constexpr (std::is_same_v) { constants.AppendVariadic(SpirvOp::OpConstantComposite, [&](const auto& appender) @@ -746,6 +797,8 @@ namespace Nz appender(GetId(*param)); }); } + else if constexpr (std::is_same_v) + throw std::runtime_error("unexpected identifier"); else if constexpr (std::is_same_v) { UInt32 depth; @@ -756,9 +809,9 @@ namespace Nz UInt32 sampled; if (arg.sampled.has_value()) - sampled = (*arg.sampled) ? 1 : 0; + sampled = (*arg.sampled) ? 1 : 2; //< Yes/No else - sampled = 2; + sampled = 0; //< Dunno constants.AppendVariadic(SpirvOp::OpTypeImage, [&](const auto& appender) { @@ -808,7 +861,7 @@ namespace Nz annotations.Append(SpirvOp::OpDecorate, resultId, SpirvDecoration::Block); - FieldOffsets structOffsets(StructLayout_Std140); + FieldOffsets structOffsets(StructLayout::Std140); for (std::size_t memberIndex = 0; memberIndex < structData.members.size(); ++memberIndex) { @@ -820,18 +873,18 @@ namespace Nz using T = std::decay_t; if constexpr (std::is_same_v) - return structOffsets.AddField(StructFieldType_Bool1); + return structOffsets.AddField(StructFieldType::Bool1); else if constexpr (std::is_same_v) { switch (arg.width) { - case 32: return structOffsets.AddField(StructFieldType_Float1); - case 64: return structOffsets.AddField(StructFieldType_Double1); + case 32: return structOffsets.AddField(StructFieldType::Float1); + case 64: return structOffsets.AddField(StructFieldType::Double1); default: throw std::runtime_error("unexpected float width " + std::to_string(arg.width)); } } else if constexpr (std::is_same_v) - return structOffsets.AddField((arg.signedness) ? StructFieldType_Int1 : StructFieldType_UInt1); + return structOffsets.AddField((arg.signedness) ? StructFieldType::Int1 : StructFieldType::UInt1); else if constexpr (std::is_same_v) { assert(std::holds_alternative(arg.columnType->type)); @@ -845,8 +898,8 @@ namespace Nz StructFieldType columnType; switch (vecType.width) { - case 32: columnType = StructFieldType_Float1; break; - case 64: columnType = StructFieldType_Double1; break; + case 32: columnType = StructFieldType::Float1; break; + case 64: columnType = StructFieldType::Double1; break; default: throw std::runtime_error("unexpected float width " + std::to_string(vecType.width)); } @@ -867,14 +920,14 @@ namespace Nz else if constexpr (std::is_same_v) { if (std::holds_alternative(arg.componentType->type)) - return structOffsets.AddField(static_cast(StructFieldType_Bool1 + arg.componentCount - 1)); + return structOffsets.AddField(static_cast(UnderlyingCast(StructFieldType::Bool1) + arg.componentCount - 1)); else if (std::holds_alternative(arg.componentType->type)) { Float& floatData = std::get(arg.componentType->type); switch (floatData.width) { - case 32: return structOffsets.AddField(static_cast(StructFieldType_Float1 + arg.componentCount - 1)); - case 64: return structOffsets.AddField(static_cast(StructFieldType_Double1 + arg.componentCount - 1)); + case 32: return structOffsets.AddField(static_cast(UnderlyingCast(StructFieldType::Float1) + arg.componentCount - 1)); + case 64: return structOffsets.AddField(static_cast(UnderlyingCast(StructFieldType::Double1) + arg.componentCount - 1)); default: throw std::runtime_error("unexpected float width " + std::to_string(floatData.width)); } } @@ -885,15 +938,17 @@ namespace Nz throw std::runtime_error("unexpected integer width " + std::to_string(intData.width)); if (intData.signedness) - return structOffsets.AddField(static_cast(StructFieldType_Int1 + arg.componentCount - 1)); + return structOffsets.AddField(static_cast(UnderlyingCast(StructFieldType::Int1) + arg.componentCount - 1)); else - return structOffsets.AddField(static_cast(StructFieldType_UInt1 + arg.componentCount - 1)); + return structOffsets.AddField(static_cast(UnderlyingCast(StructFieldType::UInt1) + arg.componentCount - 1)); } else throw std::runtime_error("unexpected type for vector"); } else if constexpr (std::is_same_v) throw std::runtime_error("unexpected function as struct member"); + else if constexpr (std::is_same_v) + throw std::runtime_error("unexpected identifier"); else if constexpr (std::is_same_v || std::is_same_v) throw std::runtime_error("unexpected opaque type as struct member"); else if constexpr (std::is_same_v) diff --git a/src/Nazara/Shader/SpirvData.cpp b/src/Nazara/Shader/SpirvData.cpp index dae33b777..c0c333eeb 100644 --- a/src/Nazara/Shader/SpirvData.cpp +++ b/src/Nazara/Shader/SpirvData.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 Jérôme Leclercq +// Copyright (C) 2021 Jérôme Leclercq // This file is part of the "Nazara Engine - Shader generator" // For conditions of distribution and use, see copyright notice in Config.hpp" @@ -11,7 +11,7 @@ namespace Nz { - static constexpr std::array s_operands = { + static constexpr std::array s_operands = { { { SpirvOperandKind::IdResultType, @@ -5429,6 +5429,70 @@ namespace Nz SpirvOperandKind::IdRef, R"('Index')" }, + { + SpirvOperandKind::IdRef, + R"('Accel')" + }, + { + SpirvOperandKind::IdRef, + R"('Ray Flags')" + }, + { + SpirvOperandKind::IdRef, + R"('Cull Mask')" + }, + { + SpirvOperandKind::IdRef, + R"('SBT Offset')" + }, + { + SpirvOperandKind::IdRef, + R"('SBT Stride')" + }, + { + SpirvOperandKind::IdRef, + R"('Miss Index')" + }, + { + SpirvOperandKind::IdRef, + R"('Ray Origin')" + }, + { + SpirvOperandKind::IdRef, + R"('Ray Tmin')" + }, + { + SpirvOperandKind::IdRef, + R"('Ray Direction')" + }, + { + SpirvOperandKind::IdRef, + R"('Ray Tmax')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdRef, + R"('SBT Index')" + }, + { + SpirvOperandKind::IdRef, + R"('Callable Data')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Accel')" + }, { SpirvOperandKind::IdResult, R"(IdResult)" @@ -5715,7 +5779,7 @@ namespace Nz }, { SpirvOperandKind::IdScope, - R"('Execution')" + R"('Scope')" }, { SpirvOperandKind::IdResultType, @@ -6345,6 +6409,126 @@ namespace Nz SpirvOperandKind::IdRef, R"('Operand 1')" }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::LiteralString, + R"('Asm target')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Asm type')" + }, + { + SpirvOperandKind::IdRef, + R"('Target')" + }, + { + SpirvOperandKind::LiteralString, + R"('Asm instructions')" + }, + { + SpirvOperandKind::LiteralString, + R"('Constraints')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Asm')" + }, + { + SpirvOperandKind::IdRef, + R"('Argument 0')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdScope, + R"('Memory')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Semantics')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdScope, + R"('Memory')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Semantics')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('Condition')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('ExpectedValue')" + }, { SpirvOperandKind::IdRef, R"('Target')" @@ -8185,6 +8369,30 @@ namespace Nz SpirvOperandKind::IdRef, R"('Payload')" }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Lenght')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Ptr')" + }, { SpirvOperandKind::LiteralInteger, R"('Loop Control Parameters')" @@ -8197,6 +8405,30 @@ namespace Nz SpirvOperandKind::IdResult, R"(IdResult)" }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, { SpirvOperandKind::IdRef, R"('Packet Size')" @@ -8513,3341 +8745,4061 @@ namespace Nz SpirvOperandKind::IdRef, R"('Value')" }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Member 0 type', + +'member 1 type', + +...)" + }, + { + SpirvOperandKind::IdRef, + R"('Constituents')" + }, + { + SpirvOperandKind::IdRef, + R"('Constituents')" + }, } }; - static std::array s_instructions = { + static std::array s_instructions = { { { SpirvOp::OpNop, R"(OpNop)", nullptr, + nullptr, 0, }, { SpirvOp::OpUndef, R"(OpUndef)", &s_operands[0], + &s_operands[1], 2, }, { SpirvOp::OpSourceContinued, R"(OpSourceContinued)", &s_operands[2], + nullptr, 1, }, { SpirvOp::OpSource, R"(OpSource)", &s_operands[3], + nullptr, 4, }, { SpirvOp::OpSourceExtension, R"(OpSourceExtension)", &s_operands[7], + nullptr, 1, }, { SpirvOp::OpName, R"(OpName)", &s_operands[8], + nullptr, 2, }, { SpirvOp::OpMemberName, R"(OpMemberName)", &s_operands[10], + nullptr, 3, }, { SpirvOp::OpString, R"(OpString)", &s_operands[13], + &s_operands[13], 2, }, { SpirvOp::OpLine, R"(OpLine)", &s_operands[15], + nullptr, 3, }, { SpirvOp::OpExtension, R"(OpExtension)", &s_operands[18], + nullptr, 1, }, { SpirvOp::OpExtInstImport, R"(OpExtInstImport)", &s_operands[19], + &s_operands[19], 2, }, { SpirvOp::OpExtInst, R"(OpExtInst)", &s_operands[21], + &s_operands[22], 5, }, { SpirvOp::OpMemoryModel, R"(OpMemoryModel)", &s_operands[26], + nullptr, 2, }, { SpirvOp::OpEntryPoint, R"(OpEntryPoint)", &s_operands[28], + nullptr, 4, }, { SpirvOp::OpExecutionMode, R"(OpExecutionMode)", &s_operands[32], + nullptr, 2, }, { SpirvOp::OpCapability, R"(OpCapability)", &s_operands[34], + nullptr, 1, }, { SpirvOp::OpTypeVoid, R"(OpTypeVoid)", &s_operands[35], + &s_operands[35], 1, }, { SpirvOp::OpTypeBool, R"(OpTypeBool)", &s_operands[36], + &s_operands[36], 1, }, { SpirvOp::OpTypeInt, R"(OpTypeInt)", &s_operands[37], + &s_operands[37], 3, }, { SpirvOp::OpTypeFloat, R"(OpTypeFloat)", &s_operands[40], + &s_operands[40], 2, }, { SpirvOp::OpTypeVector, R"(OpTypeVector)", &s_operands[42], + &s_operands[42], 3, }, { SpirvOp::OpTypeMatrix, R"(OpTypeMatrix)", &s_operands[45], + &s_operands[45], 3, }, { SpirvOp::OpTypeImage, R"(OpTypeImage)", &s_operands[48], + &s_operands[48], 9, }, { SpirvOp::OpTypeSampler, R"(OpTypeSampler)", &s_operands[57], + &s_operands[57], 1, }, { SpirvOp::OpTypeSampledImage, R"(OpTypeSampledImage)", &s_operands[58], + &s_operands[58], 2, }, { SpirvOp::OpTypeArray, R"(OpTypeArray)", &s_operands[60], + &s_operands[60], 3, }, { SpirvOp::OpTypeRuntimeArray, R"(OpTypeRuntimeArray)", &s_operands[63], + &s_operands[63], 2, }, { SpirvOp::OpTypeStruct, R"(OpTypeStruct)", &s_operands[65], + &s_operands[65], 2, }, { SpirvOp::OpTypeOpaque, R"(OpTypeOpaque)", &s_operands[67], + &s_operands[67], 2, }, { SpirvOp::OpTypePointer, R"(OpTypePointer)", &s_operands[69], + &s_operands[69], 3, }, { SpirvOp::OpTypeFunction, R"(OpTypeFunction)", &s_operands[72], + &s_operands[72], 3, }, { SpirvOp::OpTypeEvent, R"(OpTypeEvent)", &s_operands[75], + &s_operands[75], 1, }, { SpirvOp::OpTypeDeviceEvent, R"(OpTypeDeviceEvent)", &s_operands[76], + &s_operands[76], 1, }, { SpirvOp::OpTypeReserveId, R"(OpTypeReserveId)", &s_operands[77], + &s_operands[77], 1, }, { SpirvOp::OpTypeQueue, R"(OpTypeQueue)", &s_operands[78], + &s_operands[78], 1, }, { SpirvOp::OpTypePipe, R"(OpTypePipe)", &s_operands[79], + &s_operands[79], 2, }, { SpirvOp::OpTypeForwardPointer, R"(OpTypeForwardPointer)", &s_operands[81], + nullptr, 2, }, { SpirvOp::OpConstantTrue, R"(OpConstantTrue)", &s_operands[83], + &s_operands[84], 2, }, { SpirvOp::OpConstantFalse, R"(OpConstantFalse)", &s_operands[85], + &s_operands[86], 2, }, { SpirvOp::OpConstant, R"(OpConstant)", &s_operands[87], + &s_operands[88], 3, }, { SpirvOp::OpConstantComposite, R"(OpConstantComposite)", &s_operands[90], + &s_operands[91], 3, }, { SpirvOp::OpConstantSampler, R"(OpConstantSampler)", &s_operands[93], + &s_operands[94], 5, }, { SpirvOp::OpConstantNull, R"(OpConstantNull)", &s_operands[98], + &s_operands[99], 2, }, { SpirvOp::OpSpecConstantTrue, R"(OpSpecConstantTrue)", &s_operands[100], + &s_operands[101], 2, }, { SpirvOp::OpSpecConstantFalse, R"(OpSpecConstantFalse)", &s_operands[102], + &s_operands[103], 2, }, { SpirvOp::OpSpecConstant, R"(OpSpecConstant)", &s_operands[104], + &s_operands[105], 3, }, { SpirvOp::OpSpecConstantComposite, R"(OpSpecConstantComposite)", &s_operands[107], + &s_operands[108], 3, }, { SpirvOp::OpSpecConstantOp, R"(OpSpecConstantOp)", &s_operands[110], + &s_operands[111], 3, }, { SpirvOp::OpFunction, R"(OpFunction)", &s_operands[113], + &s_operands[114], 4, }, { SpirvOp::OpFunctionParameter, R"(OpFunctionParameter)", &s_operands[117], + &s_operands[118], 2, }, { SpirvOp::OpFunctionEnd, R"(OpFunctionEnd)", nullptr, + nullptr, 0, }, { SpirvOp::OpFunctionCall, R"(OpFunctionCall)", &s_operands[119], + &s_operands[120], 4, }, { SpirvOp::OpVariable, R"(OpVariable)", &s_operands[123], + &s_operands[124], 4, }, { SpirvOp::OpImageTexelPointer, R"(OpImageTexelPointer)", &s_operands[127], + &s_operands[128], 5, }, { SpirvOp::OpLoad, R"(OpLoad)", &s_operands[132], + &s_operands[133], 4, }, { SpirvOp::OpStore, R"(OpStore)", &s_operands[136], + nullptr, 3, }, { SpirvOp::OpCopyMemory, R"(OpCopyMemory)", &s_operands[139], + nullptr, 4, }, { SpirvOp::OpCopyMemorySized, R"(OpCopyMemorySized)", &s_operands[143], + nullptr, 5, }, { SpirvOp::OpAccessChain, R"(OpAccessChain)", &s_operands[148], + &s_operands[149], 4, }, { SpirvOp::OpInBoundsAccessChain, R"(OpInBoundsAccessChain)", &s_operands[152], + &s_operands[153], 4, }, { SpirvOp::OpPtrAccessChain, R"(OpPtrAccessChain)", &s_operands[156], + &s_operands[157], 5, }, { SpirvOp::OpArrayLength, R"(OpArrayLength)", &s_operands[161], + &s_operands[162], 4, }, { SpirvOp::OpGenericPtrMemSemantics, R"(OpGenericPtrMemSemantics)", &s_operands[165], + &s_operands[166], 3, }, { SpirvOp::OpInBoundsPtrAccessChain, R"(OpInBoundsPtrAccessChain)", &s_operands[168], + &s_operands[169], 5, }, { SpirvOp::OpDecorate, R"(OpDecorate)", &s_operands[173], + nullptr, 2, }, { SpirvOp::OpMemberDecorate, R"(OpMemberDecorate)", &s_operands[175], + nullptr, 3, }, { SpirvOp::OpDecorationGroup, R"(OpDecorationGroup)", &s_operands[178], + &s_operands[178], 1, }, { SpirvOp::OpGroupDecorate, R"(OpGroupDecorate)", &s_operands[179], + nullptr, 2, }, { SpirvOp::OpGroupMemberDecorate, R"(OpGroupMemberDecorate)", &s_operands[181], + nullptr, 2, }, { SpirvOp::OpVectorExtractDynamic, R"(OpVectorExtractDynamic)", &s_operands[183], + &s_operands[184], 4, }, { SpirvOp::OpVectorInsertDynamic, R"(OpVectorInsertDynamic)", &s_operands[187], + &s_operands[188], 5, }, { SpirvOp::OpVectorShuffle, R"(OpVectorShuffle)", &s_operands[192], + &s_operands[193], 5, }, { SpirvOp::OpCompositeConstruct, R"(OpCompositeConstruct)", &s_operands[197], + &s_operands[198], 3, }, { SpirvOp::OpCompositeExtract, R"(OpCompositeExtract)", &s_operands[200], + &s_operands[201], 4, }, { SpirvOp::OpCompositeInsert, R"(OpCompositeInsert)", &s_operands[204], + &s_operands[205], 5, }, { SpirvOp::OpCopyObject, R"(OpCopyObject)", &s_operands[209], + &s_operands[210], 3, }, { SpirvOp::OpTranspose, R"(OpTranspose)", &s_operands[212], + &s_operands[213], 3, }, { SpirvOp::OpSampledImage, R"(OpSampledImage)", &s_operands[215], + &s_operands[216], 4, }, { SpirvOp::OpImageSampleImplicitLod, R"(OpImageSampleImplicitLod)", &s_operands[219], + &s_operands[220], 5, }, { SpirvOp::OpImageSampleExplicitLod, R"(OpImageSampleExplicitLod)", &s_operands[224], + &s_operands[225], 5, }, { SpirvOp::OpImageSampleDrefImplicitLod, R"(OpImageSampleDrefImplicitLod)", &s_operands[229], + &s_operands[230], 6, }, { SpirvOp::OpImageSampleDrefExplicitLod, R"(OpImageSampleDrefExplicitLod)", &s_operands[235], + &s_operands[236], 6, }, { SpirvOp::OpImageSampleProjImplicitLod, R"(OpImageSampleProjImplicitLod)", &s_operands[241], + &s_operands[242], 5, }, { SpirvOp::OpImageSampleProjExplicitLod, R"(OpImageSampleProjExplicitLod)", &s_operands[246], + &s_operands[247], 5, }, { SpirvOp::OpImageSampleProjDrefImplicitLod, R"(OpImageSampleProjDrefImplicitLod)", &s_operands[251], + &s_operands[252], 6, }, { SpirvOp::OpImageSampleProjDrefExplicitLod, R"(OpImageSampleProjDrefExplicitLod)", &s_operands[257], + &s_operands[258], 6, }, { SpirvOp::OpImageFetch, R"(OpImageFetch)", &s_operands[263], + &s_operands[264], 5, }, { SpirvOp::OpImageGather, R"(OpImageGather)", &s_operands[268], + &s_operands[269], 6, }, { SpirvOp::OpImageDrefGather, R"(OpImageDrefGather)", &s_operands[274], + &s_operands[275], 6, }, { SpirvOp::OpImageRead, R"(OpImageRead)", &s_operands[280], + &s_operands[281], 5, }, { SpirvOp::OpImageWrite, R"(OpImageWrite)", &s_operands[285], + nullptr, 4, }, { SpirvOp::OpImage, R"(OpImage)", &s_operands[289], + &s_operands[290], 3, }, { SpirvOp::OpImageQueryFormat, R"(OpImageQueryFormat)", &s_operands[292], + &s_operands[293], 3, }, { SpirvOp::OpImageQueryOrder, R"(OpImageQueryOrder)", &s_operands[295], + &s_operands[296], 3, }, { SpirvOp::OpImageQuerySizeLod, R"(OpImageQuerySizeLod)", &s_operands[298], + &s_operands[299], 4, }, { SpirvOp::OpImageQuerySize, R"(OpImageQuerySize)", &s_operands[302], + &s_operands[303], 3, }, { SpirvOp::OpImageQueryLod, R"(OpImageQueryLod)", &s_operands[305], + &s_operands[306], 4, }, { SpirvOp::OpImageQueryLevels, R"(OpImageQueryLevels)", &s_operands[309], + &s_operands[310], 3, }, { SpirvOp::OpImageQuerySamples, R"(OpImageQuerySamples)", &s_operands[312], + &s_operands[313], 3, }, { SpirvOp::OpConvertFToU, R"(OpConvertFToU)", &s_operands[315], + &s_operands[316], 3, }, { SpirvOp::OpConvertFToS, R"(OpConvertFToS)", &s_operands[318], + &s_operands[319], 3, }, { SpirvOp::OpConvertSToF, R"(OpConvertSToF)", &s_operands[321], + &s_operands[322], 3, }, { SpirvOp::OpConvertUToF, R"(OpConvertUToF)", &s_operands[324], + &s_operands[325], 3, }, { SpirvOp::OpUConvert, R"(OpUConvert)", &s_operands[327], + &s_operands[328], 3, }, { SpirvOp::OpSConvert, R"(OpSConvert)", &s_operands[330], + &s_operands[331], 3, }, { SpirvOp::OpFConvert, R"(OpFConvert)", &s_operands[333], + &s_operands[334], 3, }, { SpirvOp::OpQuantizeToF16, R"(OpQuantizeToF16)", &s_operands[336], + &s_operands[337], 3, }, { SpirvOp::OpConvertPtrToU, R"(OpConvertPtrToU)", &s_operands[339], + &s_operands[340], 3, }, { SpirvOp::OpSatConvertSToU, R"(OpSatConvertSToU)", &s_operands[342], + &s_operands[343], 3, }, { SpirvOp::OpSatConvertUToS, R"(OpSatConvertUToS)", &s_operands[345], + &s_operands[346], 3, }, { SpirvOp::OpConvertUToPtr, R"(OpConvertUToPtr)", &s_operands[348], + &s_operands[349], 3, }, { SpirvOp::OpPtrCastToGeneric, R"(OpPtrCastToGeneric)", &s_operands[351], + &s_operands[352], 3, }, { SpirvOp::OpGenericCastToPtr, R"(OpGenericCastToPtr)", &s_operands[354], + &s_operands[355], 3, }, { SpirvOp::OpGenericCastToPtrExplicit, R"(OpGenericCastToPtrExplicit)", &s_operands[357], + &s_operands[358], 4, }, { SpirvOp::OpBitcast, R"(OpBitcast)", &s_operands[361], + &s_operands[362], 3, }, { SpirvOp::OpSNegate, R"(OpSNegate)", &s_operands[364], + &s_operands[365], 3, }, { SpirvOp::OpFNegate, R"(OpFNegate)", &s_operands[367], + &s_operands[368], 3, }, { SpirvOp::OpIAdd, R"(OpIAdd)", &s_operands[370], + &s_operands[371], 4, }, { SpirvOp::OpFAdd, R"(OpFAdd)", &s_operands[374], + &s_operands[375], 4, }, { SpirvOp::OpISub, R"(OpISub)", &s_operands[378], + &s_operands[379], 4, }, { SpirvOp::OpFSub, R"(OpFSub)", &s_operands[382], + &s_operands[383], 4, }, { SpirvOp::OpIMul, R"(OpIMul)", &s_operands[386], + &s_operands[387], 4, }, { SpirvOp::OpFMul, R"(OpFMul)", &s_operands[390], + &s_operands[391], 4, }, { SpirvOp::OpUDiv, R"(OpUDiv)", &s_operands[394], + &s_operands[395], 4, }, { SpirvOp::OpSDiv, R"(OpSDiv)", &s_operands[398], + &s_operands[399], 4, }, { SpirvOp::OpFDiv, R"(OpFDiv)", &s_operands[402], + &s_operands[403], 4, }, { SpirvOp::OpUMod, R"(OpUMod)", &s_operands[406], + &s_operands[407], 4, }, { SpirvOp::OpSRem, R"(OpSRem)", &s_operands[410], + &s_operands[411], 4, }, { SpirvOp::OpSMod, R"(OpSMod)", &s_operands[414], + &s_operands[415], 4, }, { SpirvOp::OpFRem, R"(OpFRem)", &s_operands[418], + &s_operands[419], 4, }, { SpirvOp::OpFMod, R"(OpFMod)", &s_operands[422], + &s_operands[423], 4, }, { SpirvOp::OpVectorTimesScalar, R"(OpVectorTimesScalar)", &s_operands[426], + &s_operands[427], 4, }, { SpirvOp::OpMatrixTimesScalar, R"(OpMatrixTimesScalar)", &s_operands[430], + &s_operands[431], 4, }, { SpirvOp::OpVectorTimesMatrix, R"(OpVectorTimesMatrix)", &s_operands[434], + &s_operands[435], 4, }, { SpirvOp::OpMatrixTimesVector, R"(OpMatrixTimesVector)", &s_operands[438], + &s_operands[439], 4, }, { SpirvOp::OpMatrixTimesMatrix, R"(OpMatrixTimesMatrix)", &s_operands[442], + &s_operands[443], 4, }, { SpirvOp::OpOuterProduct, R"(OpOuterProduct)", &s_operands[446], + &s_operands[447], 4, }, { SpirvOp::OpDot, R"(OpDot)", &s_operands[450], + &s_operands[451], 4, }, { SpirvOp::OpIAddCarry, R"(OpIAddCarry)", &s_operands[454], + &s_operands[455], 4, }, { SpirvOp::OpISubBorrow, R"(OpISubBorrow)", &s_operands[458], + &s_operands[459], 4, }, { SpirvOp::OpUMulExtended, R"(OpUMulExtended)", &s_operands[462], + &s_operands[463], 4, }, { SpirvOp::OpSMulExtended, R"(OpSMulExtended)", &s_operands[466], + &s_operands[467], 4, }, { SpirvOp::OpAny, R"(OpAny)", &s_operands[470], + &s_operands[471], 3, }, { SpirvOp::OpAll, R"(OpAll)", &s_operands[473], + &s_operands[474], 3, }, { SpirvOp::OpIsNan, R"(OpIsNan)", &s_operands[476], + &s_operands[477], 3, }, { SpirvOp::OpIsInf, R"(OpIsInf)", &s_operands[479], + &s_operands[480], 3, }, { SpirvOp::OpIsFinite, R"(OpIsFinite)", &s_operands[482], + &s_operands[483], 3, }, { SpirvOp::OpIsNormal, R"(OpIsNormal)", &s_operands[485], + &s_operands[486], 3, }, { SpirvOp::OpSignBitSet, R"(OpSignBitSet)", &s_operands[488], + &s_operands[489], 3, }, { SpirvOp::OpLessOrGreater, R"(OpLessOrGreater)", &s_operands[491], + &s_operands[492], 4, }, { SpirvOp::OpOrdered, R"(OpOrdered)", &s_operands[495], + &s_operands[496], 4, }, { SpirvOp::OpUnordered, R"(OpUnordered)", &s_operands[499], + &s_operands[500], 4, }, { SpirvOp::OpLogicalEqual, R"(OpLogicalEqual)", &s_operands[503], + &s_operands[504], 4, }, { SpirvOp::OpLogicalNotEqual, R"(OpLogicalNotEqual)", &s_operands[507], + &s_operands[508], 4, }, { SpirvOp::OpLogicalOr, R"(OpLogicalOr)", &s_operands[511], + &s_operands[512], 4, }, { SpirvOp::OpLogicalAnd, R"(OpLogicalAnd)", &s_operands[515], + &s_operands[516], 4, }, { SpirvOp::OpLogicalNot, R"(OpLogicalNot)", &s_operands[519], + &s_operands[520], 3, }, { SpirvOp::OpSelect, R"(OpSelect)", &s_operands[522], + &s_operands[523], 5, }, { SpirvOp::OpIEqual, R"(OpIEqual)", &s_operands[527], + &s_operands[528], 4, }, { SpirvOp::OpINotEqual, R"(OpINotEqual)", &s_operands[531], + &s_operands[532], 4, }, { SpirvOp::OpUGreaterThan, R"(OpUGreaterThan)", &s_operands[535], + &s_operands[536], 4, }, { SpirvOp::OpSGreaterThan, R"(OpSGreaterThan)", &s_operands[539], + &s_operands[540], 4, }, { SpirvOp::OpUGreaterThanEqual, R"(OpUGreaterThanEqual)", &s_operands[543], + &s_operands[544], 4, }, { SpirvOp::OpSGreaterThanEqual, R"(OpSGreaterThanEqual)", &s_operands[547], + &s_operands[548], 4, }, { SpirvOp::OpULessThan, R"(OpULessThan)", &s_operands[551], + &s_operands[552], 4, }, { SpirvOp::OpSLessThan, R"(OpSLessThan)", &s_operands[555], + &s_operands[556], 4, }, { SpirvOp::OpULessThanEqual, R"(OpULessThanEqual)", &s_operands[559], + &s_operands[560], 4, }, { SpirvOp::OpSLessThanEqual, R"(OpSLessThanEqual)", &s_operands[563], + &s_operands[564], 4, }, { SpirvOp::OpFOrdEqual, R"(OpFOrdEqual)", &s_operands[567], + &s_operands[568], 4, }, { SpirvOp::OpFUnordEqual, R"(OpFUnordEqual)", &s_operands[571], + &s_operands[572], 4, }, { SpirvOp::OpFOrdNotEqual, R"(OpFOrdNotEqual)", &s_operands[575], + &s_operands[576], 4, }, { SpirvOp::OpFUnordNotEqual, R"(OpFUnordNotEqual)", &s_operands[579], + &s_operands[580], 4, }, { SpirvOp::OpFOrdLessThan, R"(OpFOrdLessThan)", &s_operands[583], + &s_operands[584], 4, }, { SpirvOp::OpFUnordLessThan, R"(OpFUnordLessThan)", &s_operands[587], + &s_operands[588], 4, }, { SpirvOp::OpFOrdGreaterThan, R"(OpFOrdGreaterThan)", &s_operands[591], + &s_operands[592], 4, }, { SpirvOp::OpFUnordGreaterThan, R"(OpFUnordGreaterThan)", &s_operands[595], + &s_operands[596], 4, }, { SpirvOp::OpFOrdLessThanEqual, R"(OpFOrdLessThanEqual)", &s_operands[599], + &s_operands[600], 4, }, { SpirvOp::OpFUnordLessThanEqual, R"(OpFUnordLessThanEqual)", &s_operands[603], + &s_operands[604], 4, }, { SpirvOp::OpFOrdGreaterThanEqual, R"(OpFOrdGreaterThanEqual)", &s_operands[607], + &s_operands[608], 4, }, { SpirvOp::OpFUnordGreaterThanEqual, R"(OpFUnordGreaterThanEqual)", &s_operands[611], + &s_operands[612], 4, }, { SpirvOp::OpShiftRightLogical, R"(OpShiftRightLogical)", &s_operands[615], + &s_operands[616], 4, }, { SpirvOp::OpShiftRightArithmetic, R"(OpShiftRightArithmetic)", &s_operands[619], + &s_operands[620], 4, }, { SpirvOp::OpShiftLeftLogical, R"(OpShiftLeftLogical)", &s_operands[623], + &s_operands[624], 4, }, { SpirvOp::OpBitwiseOr, R"(OpBitwiseOr)", &s_operands[627], + &s_operands[628], 4, }, { SpirvOp::OpBitwiseXor, R"(OpBitwiseXor)", &s_operands[631], + &s_operands[632], 4, }, { SpirvOp::OpBitwiseAnd, R"(OpBitwiseAnd)", &s_operands[635], + &s_operands[636], 4, }, { SpirvOp::OpNot, R"(OpNot)", &s_operands[639], + &s_operands[640], 3, }, { SpirvOp::OpBitFieldInsert, R"(OpBitFieldInsert)", &s_operands[642], + &s_operands[643], 6, }, { SpirvOp::OpBitFieldSExtract, R"(OpBitFieldSExtract)", &s_operands[648], + &s_operands[649], 5, }, { SpirvOp::OpBitFieldUExtract, R"(OpBitFieldUExtract)", &s_operands[653], + &s_operands[654], 5, }, { SpirvOp::OpBitReverse, R"(OpBitReverse)", &s_operands[658], + &s_operands[659], 3, }, { SpirvOp::OpBitCount, R"(OpBitCount)", &s_operands[661], + &s_operands[662], 3, }, { SpirvOp::OpDPdx, R"(OpDPdx)", &s_operands[664], + &s_operands[665], 3, }, { SpirvOp::OpDPdy, R"(OpDPdy)", &s_operands[667], + &s_operands[668], 3, }, { SpirvOp::OpFwidth, R"(OpFwidth)", &s_operands[670], + &s_operands[671], 3, }, { SpirvOp::OpDPdxFine, R"(OpDPdxFine)", &s_operands[673], + &s_operands[674], 3, }, { SpirvOp::OpDPdyFine, R"(OpDPdyFine)", &s_operands[676], + &s_operands[677], 3, }, { SpirvOp::OpFwidthFine, R"(OpFwidthFine)", &s_operands[679], + &s_operands[680], 3, }, { SpirvOp::OpDPdxCoarse, R"(OpDPdxCoarse)", &s_operands[682], + &s_operands[683], 3, }, { SpirvOp::OpDPdyCoarse, R"(OpDPdyCoarse)", &s_operands[685], + &s_operands[686], 3, }, { SpirvOp::OpFwidthCoarse, R"(OpFwidthCoarse)", &s_operands[688], + &s_operands[689], 3, }, { SpirvOp::OpEmitVertex, R"(OpEmitVertex)", nullptr, + nullptr, 0, }, { SpirvOp::OpEndPrimitive, R"(OpEndPrimitive)", nullptr, + nullptr, 0, }, { SpirvOp::OpEmitStreamVertex, R"(OpEmitStreamVertex)", &s_operands[691], + nullptr, 1, }, { SpirvOp::OpEndStreamPrimitive, R"(OpEndStreamPrimitive)", &s_operands[692], + nullptr, 1, }, { SpirvOp::OpControlBarrier, R"(OpControlBarrier)", &s_operands[693], + nullptr, 3, }, { SpirvOp::OpMemoryBarrier, R"(OpMemoryBarrier)", &s_operands[696], + nullptr, 2, }, { SpirvOp::OpAtomicLoad, R"(OpAtomicLoad)", &s_operands[698], + &s_operands[699], 5, }, { SpirvOp::OpAtomicStore, R"(OpAtomicStore)", &s_operands[703], + nullptr, 4, }, { SpirvOp::OpAtomicExchange, R"(OpAtomicExchange)", &s_operands[707], + &s_operands[708], 6, }, { SpirvOp::OpAtomicCompareExchange, R"(OpAtomicCompareExchange)", &s_operands[713], + &s_operands[714], 8, }, { SpirvOp::OpAtomicCompareExchangeWeak, R"(OpAtomicCompareExchangeWeak)", &s_operands[721], + &s_operands[722], 8, }, { SpirvOp::OpAtomicIIncrement, R"(OpAtomicIIncrement)", &s_operands[729], + &s_operands[730], 5, }, { SpirvOp::OpAtomicIDecrement, R"(OpAtomicIDecrement)", &s_operands[734], + &s_operands[735], 5, }, { SpirvOp::OpAtomicIAdd, R"(OpAtomicIAdd)", &s_operands[739], + &s_operands[740], 6, }, { SpirvOp::OpAtomicISub, R"(OpAtomicISub)", &s_operands[745], + &s_operands[746], 6, }, { SpirvOp::OpAtomicSMin, R"(OpAtomicSMin)", &s_operands[751], + &s_operands[752], 6, }, { SpirvOp::OpAtomicUMin, R"(OpAtomicUMin)", &s_operands[757], + &s_operands[758], 6, }, { SpirvOp::OpAtomicSMax, R"(OpAtomicSMax)", &s_operands[763], + &s_operands[764], 6, }, { SpirvOp::OpAtomicUMax, R"(OpAtomicUMax)", &s_operands[769], + &s_operands[770], 6, }, { SpirvOp::OpAtomicAnd, R"(OpAtomicAnd)", &s_operands[775], + &s_operands[776], 6, }, { SpirvOp::OpAtomicOr, R"(OpAtomicOr)", &s_operands[781], + &s_operands[782], 6, }, { SpirvOp::OpAtomicXor, R"(OpAtomicXor)", &s_operands[787], + &s_operands[788], 6, }, { SpirvOp::OpPhi, R"(OpPhi)", &s_operands[793], + &s_operands[794], 3, }, { SpirvOp::OpLoopMerge, R"(OpLoopMerge)", &s_operands[796], + nullptr, 3, }, { SpirvOp::OpSelectionMerge, R"(OpSelectionMerge)", &s_operands[799], + nullptr, 2, }, { SpirvOp::OpLabel, R"(OpLabel)", &s_operands[801], + &s_operands[801], 1, }, { SpirvOp::OpBranch, R"(OpBranch)", &s_operands[802], + nullptr, 1, }, { SpirvOp::OpBranchConditional, R"(OpBranchConditional)", &s_operands[803], + nullptr, 4, }, { SpirvOp::OpSwitch, R"(OpSwitch)", &s_operands[807], + nullptr, 3, }, { SpirvOp::OpKill, R"(OpKill)", nullptr, + nullptr, 0, }, { SpirvOp::OpReturn, R"(OpReturn)", nullptr, + nullptr, 0, }, { SpirvOp::OpReturnValue, R"(OpReturnValue)", &s_operands[810], + nullptr, 1, }, { SpirvOp::OpUnreachable, R"(OpUnreachable)", nullptr, + nullptr, 0, }, { SpirvOp::OpLifetimeStart, R"(OpLifetimeStart)", &s_operands[811], + nullptr, 2, }, { SpirvOp::OpLifetimeStop, R"(OpLifetimeStop)", &s_operands[813], + nullptr, 2, }, { SpirvOp::OpGroupAsyncCopy, R"(OpGroupAsyncCopy)", &s_operands[815], + &s_operands[816], 8, }, { SpirvOp::OpGroupWaitEvents, R"(OpGroupWaitEvents)", &s_operands[823], + nullptr, 3, }, { SpirvOp::OpGroupAll, R"(OpGroupAll)", &s_operands[826], + &s_operands[827], 4, }, { SpirvOp::OpGroupAny, R"(OpGroupAny)", &s_operands[830], + &s_operands[831], 4, }, { SpirvOp::OpGroupBroadcast, R"(OpGroupBroadcast)", &s_operands[834], + &s_operands[835], 5, }, { SpirvOp::OpGroupIAdd, R"(OpGroupIAdd)", &s_operands[839], + &s_operands[840], 5, }, { SpirvOp::OpGroupFAdd, R"(OpGroupFAdd)", &s_operands[844], + &s_operands[845], 5, }, { SpirvOp::OpGroupFMin, R"(OpGroupFMin)", &s_operands[849], + &s_operands[850], 5, }, { SpirvOp::OpGroupUMin, R"(OpGroupUMin)", &s_operands[854], + &s_operands[855], 5, }, { SpirvOp::OpGroupSMin, R"(OpGroupSMin)", &s_operands[859], + &s_operands[860], 5, }, { SpirvOp::OpGroupFMax, R"(OpGroupFMax)", &s_operands[864], + &s_operands[865], 5, }, { SpirvOp::OpGroupUMax, R"(OpGroupUMax)", &s_operands[869], + &s_operands[870], 5, }, { SpirvOp::OpGroupSMax, R"(OpGroupSMax)", &s_operands[874], + &s_operands[875], 5, }, { SpirvOp::OpReadPipe, R"(OpReadPipe)", &s_operands[879], + &s_operands[880], 6, }, { SpirvOp::OpWritePipe, R"(OpWritePipe)", &s_operands[885], + &s_operands[886], 6, }, { SpirvOp::OpReservedReadPipe, R"(OpReservedReadPipe)", &s_operands[891], + &s_operands[892], 8, }, { SpirvOp::OpReservedWritePipe, R"(OpReservedWritePipe)", &s_operands[899], + &s_operands[900], 8, }, { SpirvOp::OpReserveReadPipePackets, R"(OpReserveReadPipePackets)", &s_operands[907], + &s_operands[908], 6, }, { SpirvOp::OpReserveWritePipePackets, R"(OpReserveWritePipePackets)", &s_operands[913], + &s_operands[914], 6, }, { SpirvOp::OpCommitReadPipe, R"(OpCommitReadPipe)", &s_operands[919], + nullptr, 4, }, { SpirvOp::OpCommitWritePipe, R"(OpCommitWritePipe)", &s_operands[923], + nullptr, 4, }, { SpirvOp::OpIsValidReserveId, R"(OpIsValidReserveId)", &s_operands[927], + &s_operands[928], 3, }, { SpirvOp::OpGetNumPipePackets, R"(OpGetNumPipePackets)", &s_operands[930], + &s_operands[931], 5, }, { SpirvOp::OpGetMaxPipePackets, R"(OpGetMaxPipePackets)", &s_operands[935], + &s_operands[936], 5, }, { SpirvOp::OpGroupReserveReadPipePackets, R"(OpGroupReserveReadPipePackets)", &s_operands[940], + &s_operands[941], 7, }, { SpirvOp::OpGroupReserveWritePipePackets, R"(OpGroupReserveWritePipePackets)", &s_operands[947], + &s_operands[948], 7, }, { SpirvOp::OpGroupCommitReadPipe, R"(OpGroupCommitReadPipe)", &s_operands[954], + nullptr, 5, }, { SpirvOp::OpGroupCommitWritePipe, R"(OpGroupCommitWritePipe)", &s_operands[959], + nullptr, 5, }, { SpirvOp::OpEnqueueMarker, R"(OpEnqueueMarker)", &s_operands[964], + &s_operands[965], 6, }, { SpirvOp::OpEnqueueKernel, R"(OpEnqueueKernel)", &s_operands[970], + &s_operands[971], 13, }, { SpirvOp::OpGetKernelNDrangeSubGroupCount, R"(OpGetKernelNDrangeSubGroupCount)", &s_operands[983], + &s_operands[984], 7, }, { SpirvOp::OpGetKernelNDrangeMaxSubGroupSize, R"(OpGetKernelNDrangeMaxSubGroupSize)", &s_operands[990], + &s_operands[991], 7, }, { SpirvOp::OpGetKernelWorkGroupSize, R"(OpGetKernelWorkGroupSize)", &s_operands[997], + &s_operands[998], 6, }, { SpirvOp::OpGetKernelPreferredWorkGroupSizeMultiple, R"(OpGetKernelPreferredWorkGroupSizeMultiple)", &s_operands[1003], + &s_operands[1004], 6, }, { SpirvOp::OpRetainEvent, R"(OpRetainEvent)", &s_operands[1009], + nullptr, 1, }, { SpirvOp::OpReleaseEvent, R"(OpReleaseEvent)", &s_operands[1010], + nullptr, 1, }, { SpirvOp::OpCreateUserEvent, R"(OpCreateUserEvent)", &s_operands[1011], + &s_operands[1012], 2, }, { SpirvOp::OpIsValidEvent, R"(OpIsValidEvent)", &s_operands[1013], + &s_operands[1014], 3, }, { SpirvOp::OpSetUserEventStatus, R"(OpSetUserEventStatus)", &s_operands[1016], + nullptr, 2, }, { SpirvOp::OpCaptureEventProfilingInfo, R"(OpCaptureEventProfilingInfo)", &s_operands[1018], + nullptr, 3, }, { SpirvOp::OpGetDefaultQueue, R"(OpGetDefaultQueue)", &s_operands[1021], + &s_operands[1022], 2, }, { SpirvOp::OpBuildNDRange, R"(OpBuildNDRange)", &s_operands[1023], + &s_operands[1024], 5, }, { SpirvOp::OpImageSparseSampleImplicitLod, R"(OpImageSparseSampleImplicitLod)", &s_operands[1028], + &s_operands[1029], 5, }, { SpirvOp::OpImageSparseSampleExplicitLod, R"(OpImageSparseSampleExplicitLod)", &s_operands[1033], + &s_operands[1034], 5, }, { SpirvOp::OpImageSparseSampleDrefImplicitLod, R"(OpImageSparseSampleDrefImplicitLod)", &s_operands[1038], + &s_operands[1039], 6, }, { SpirvOp::OpImageSparseSampleDrefExplicitLod, R"(OpImageSparseSampleDrefExplicitLod)", &s_operands[1044], + &s_operands[1045], 6, }, { SpirvOp::OpImageSparseSampleProjImplicitLod, R"(OpImageSparseSampleProjImplicitLod)", &s_operands[1050], + &s_operands[1051], 5, }, { SpirvOp::OpImageSparseSampleProjExplicitLod, R"(OpImageSparseSampleProjExplicitLod)", &s_operands[1055], + &s_operands[1056], 5, }, { SpirvOp::OpImageSparseSampleProjDrefImplicitLod, R"(OpImageSparseSampleProjDrefImplicitLod)", &s_operands[1060], + &s_operands[1061], 6, }, { SpirvOp::OpImageSparseSampleProjDrefExplicitLod, R"(OpImageSparseSampleProjDrefExplicitLod)", &s_operands[1066], + &s_operands[1067], 6, }, { SpirvOp::OpImageSparseFetch, R"(OpImageSparseFetch)", &s_operands[1072], + &s_operands[1073], 5, }, { SpirvOp::OpImageSparseGather, R"(OpImageSparseGather)", &s_operands[1077], + &s_operands[1078], 6, }, { SpirvOp::OpImageSparseDrefGather, R"(OpImageSparseDrefGather)", &s_operands[1083], + &s_operands[1084], 6, }, { SpirvOp::OpImageSparseTexelsResident, R"(OpImageSparseTexelsResident)", &s_operands[1089], + &s_operands[1090], 3, }, { SpirvOp::OpNoLine, R"(OpNoLine)", nullptr, + nullptr, 0, }, { SpirvOp::OpAtomicFlagTestAndSet, R"(OpAtomicFlagTestAndSet)", &s_operands[1092], + &s_operands[1093], 5, }, { SpirvOp::OpAtomicFlagClear, R"(OpAtomicFlagClear)", &s_operands[1097], + nullptr, 3, }, { SpirvOp::OpImageSparseRead, R"(OpImageSparseRead)", &s_operands[1100], + &s_operands[1101], 5, }, { SpirvOp::OpSizeOf, R"(OpSizeOf)", &s_operands[1105], + &s_operands[1106], 3, }, { SpirvOp::OpTypePipeStorage, R"(OpTypePipeStorage)", &s_operands[1108], + &s_operands[1108], 1, }, { SpirvOp::OpConstantPipeStorage, R"(OpConstantPipeStorage)", &s_operands[1109], + &s_operands[1110], 5, }, { SpirvOp::OpCreatePipeFromPipeStorage, R"(OpCreatePipeFromPipeStorage)", &s_operands[1114], + &s_operands[1115], 3, }, { SpirvOp::OpGetKernelLocalSizeForSubgroupCount, R"(OpGetKernelLocalSizeForSubgroupCount)", &s_operands[1117], + &s_operands[1118], 7, }, { SpirvOp::OpGetKernelMaxNumSubgroups, R"(OpGetKernelMaxNumSubgroups)", &s_operands[1124], + &s_operands[1125], 6, }, { SpirvOp::OpTypeNamedBarrier, R"(OpTypeNamedBarrier)", &s_operands[1130], + &s_operands[1130], 1, }, { SpirvOp::OpNamedBarrierInitialize, R"(OpNamedBarrierInitialize)", &s_operands[1131], + &s_operands[1132], 3, }, { SpirvOp::OpMemoryNamedBarrier, R"(OpMemoryNamedBarrier)", &s_operands[1134], + nullptr, 3, }, { SpirvOp::OpModuleProcessed, R"(OpModuleProcessed)", &s_operands[1137], + nullptr, 1, }, { SpirvOp::OpExecutionModeId, R"(OpExecutionModeId)", &s_operands[1138], + nullptr, 2, }, { SpirvOp::OpDecorateId, R"(OpDecorateId)", &s_operands[1140], + nullptr, 2, }, { SpirvOp::OpGroupNonUniformElect, R"(OpGroupNonUniformElect)", &s_operands[1142], + &s_operands[1143], 3, }, { SpirvOp::OpGroupNonUniformAll, R"(OpGroupNonUniformAll)", &s_operands[1145], + &s_operands[1146], 4, }, { SpirvOp::OpGroupNonUniformAny, R"(OpGroupNonUniformAny)", &s_operands[1149], + &s_operands[1150], 4, }, { SpirvOp::OpGroupNonUniformAllEqual, R"(OpGroupNonUniformAllEqual)", &s_operands[1153], + &s_operands[1154], 4, }, { SpirvOp::OpGroupNonUniformBroadcast, R"(OpGroupNonUniformBroadcast)", &s_operands[1157], + &s_operands[1158], 5, }, { SpirvOp::OpGroupNonUniformBroadcastFirst, R"(OpGroupNonUniformBroadcastFirst)", &s_operands[1162], + &s_operands[1163], 4, }, { SpirvOp::OpGroupNonUniformBallot, R"(OpGroupNonUniformBallot)", &s_operands[1166], + &s_operands[1167], 4, }, { SpirvOp::OpGroupNonUniformInverseBallot, R"(OpGroupNonUniformInverseBallot)", &s_operands[1170], + &s_operands[1171], 4, }, { SpirvOp::OpGroupNonUniformBallotBitExtract, R"(OpGroupNonUniformBallotBitExtract)", &s_operands[1174], + &s_operands[1175], 5, }, { SpirvOp::OpGroupNonUniformBallotBitCount, R"(OpGroupNonUniformBallotBitCount)", &s_operands[1179], + &s_operands[1180], 5, }, { SpirvOp::OpGroupNonUniformBallotFindLSB, R"(OpGroupNonUniformBallotFindLSB)", &s_operands[1184], + &s_operands[1185], 4, }, { SpirvOp::OpGroupNonUniformBallotFindMSB, R"(OpGroupNonUniformBallotFindMSB)", &s_operands[1188], + &s_operands[1189], 4, }, { SpirvOp::OpGroupNonUniformShuffle, R"(OpGroupNonUniformShuffle)", &s_operands[1192], + &s_operands[1193], 5, }, { SpirvOp::OpGroupNonUniformShuffleXor, R"(OpGroupNonUniformShuffleXor)", &s_operands[1197], + &s_operands[1198], 5, }, { SpirvOp::OpGroupNonUniformShuffleUp, R"(OpGroupNonUniformShuffleUp)", &s_operands[1202], + &s_operands[1203], 5, }, { SpirvOp::OpGroupNonUniformShuffleDown, R"(OpGroupNonUniformShuffleDown)", &s_operands[1207], + &s_operands[1208], 5, }, { SpirvOp::OpGroupNonUniformIAdd, R"(OpGroupNonUniformIAdd)", &s_operands[1212], + &s_operands[1213], 6, }, { SpirvOp::OpGroupNonUniformFAdd, R"(OpGroupNonUniformFAdd)", &s_operands[1218], + &s_operands[1219], 6, }, { SpirvOp::OpGroupNonUniformIMul, R"(OpGroupNonUniformIMul)", &s_operands[1224], + &s_operands[1225], 6, }, { SpirvOp::OpGroupNonUniformFMul, R"(OpGroupNonUniformFMul)", &s_operands[1230], + &s_operands[1231], 6, }, { SpirvOp::OpGroupNonUniformSMin, R"(OpGroupNonUniformSMin)", &s_operands[1236], + &s_operands[1237], 6, }, { SpirvOp::OpGroupNonUniformUMin, R"(OpGroupNonUniformUMin)", &s_operands[1242], + &s_operands[1243], 6, }, { SpirvOp::OpGroupNonUniformFMin, R"(OpGroupNonUniformFMin)", &s_operands[1248], + &s_operands[1249], 6, }, { SpirvOp::OpGroupNonUniformSMax, R"(OpGroupNonUniformSMax)", &s_operands[1254], + &s_operands[1255], 6, }, { SpirvOp::OpGroupNonUniformUMax, R"(OpGroupNonUniformUMax)", &s_operands[1260], + &s_operands[1261], 6, }, { SpirvOp::OpGroupNonUniformFMax, R"(OpGroupNonUniformFMax)", &s_operands[1266], + &s_operands[1267], 6, }, { SpirvOp::OpGroupNonUniformBitwiseAnd, R"(OpGroupNonUniformBitwiseAnd)", &s_operands[1272], + &s_operands[1273], 6, }, { SpirvOp::OpGroupNonUniformBitwiseOr, R"(OpGroupNonUniformBitwiseOr)", &s_operands[1278], + &s_operands[1279], 6, }, { SpirvOp::OpGroupNonUniformBitwiseXor, R"(OpGroupNonUniformBitwiseXor)", &s_operands[1284], + &s_operands[1285], 6, }, { SpirvOp::OpGroupNonUniformLogicalAnd, R"(OpGroupNonUniformLogicalAnd)", &s_operands[1290], + &s_operands[1291], 6, }, { SpirvOp::OpGroupNonUniformLogicalOr, R"(OpGroupNonUniformLogicalOr)", &s_operands[1296], + &s_operands[1297], 6, }, { SpirvOp::OpGroupNonUniformLogicalXor, R"(OpGroupNonUniformLogicalXor)", &s_operands[1302], + &s_operands[1303], 6, }, { SpirvOp::OpGroupNonUniformQuadBroadcast, R"(OpGroupNonUniformQuadBroadcast)", &s_operands[1308], + &s_operands[1309], 5, }, { SpirvOp::OpGroupNonUniformQuadSwap, R"(OpGroupNonUniformQuadSwap)", &s_operands[1313], + &s_operands[1314], 5, }, { SpirvOp::OpCopyLogical, R"(OpCopyLogical)", &s_operands[1318], + &s_operands[1319], 3, }, { SpirvOp::OpPtrEqual, R"(OpPtrEqual)", &s_operands[1321], + &s_operands[1322], 4, }, { SpirvOp::OpPtrNotEqual, R"(OpPtrNotEqual)", &s_operands[1325], + &s_operands[1326], 4, }, { SpirvOp::OpPtrDiff, R"(OpPtrDiff)", &s_operands[1329], + &s_operands[1330], 4, }, { SpirvOp::OpTerminateInvocation, R"(OpTerminateInvocation)", nullptr, + nullptr, 0, }, { SpirvOp::OpSubgroupBallotKHR, R"(OpSubgroupBallotKHR)", &s_operands[1333], + &s_operands[1334], 3, }, { SpirvOp::OpSubgroupFirstInvocationKHR, R"(OpSubgroupFirstInvocationKHR)", &s_operands[1336], + &s_operands[1337], 3, }, { SpirvOp::OpSubgroupAllKHR, R"(OpSubgroupAllKHR)", &s_operands[1339], + &s_operands[1340], 3, }, { SpirvOp::OpSubgroupAnyKHR, R"(OpSubgroupAnyKHR)", &s_operands[1342], + &s_operands[1343], 3, }, { SpirvOp::OpSubgroupAllEqualKHR, R"(OpSubgroupAllEqualKHR)", &s_operands[1345], + &s_operands[1346], 3, }, { SpirvOp::OpSubgroupReadInvocationKHR, R"(OpSubgroupReadInvocationKHR)", &s_operands[1348], + &s_operands[1349], 4, }, { - SpirvOp::OpTypeRayQueryProvisionalKHR, - R"(OpTypeRayQueryProvisionalKHR)", + SpirvOp::OpTraceRayKHR, + R"(OpTraceRayKHR)", &s_operands[1352], - 1, + nullptr, + 11, }, { - SpirvOp::OpRayQueryInitializeKHR, - R"(OpRayQueryInitializeKHR)", - &s_operands[1353], - 8, - }, - { - SpirvOp::OpRayQueryTerminateKHR, - R"(OpRayQueryTerminateKHR)", - &s_operands[1361], - 1, - }, - { - SpirvOp::OpRayQueryGenerateIntersectionKHR, - R"(OpRayQueryGenerateIntersectionKHR)", - &s_operands[1362], + SpirvOp::OpExecuteCallableKHR, + R"(OpExecuteCallableKHR)", + &s_operands[1363], + nullptr, 2, }, { - SpirvOp::OpRayQueryConfirmIntersectionKHR, - R"(OpRayQueryConfirmIntersectionKHR)", - &s_operands[1364], - 1, - }, - { - SpirvOp::OpRayQueryProceedKHR, - R"(OpRayQueryProceedKHR)", + SpirvOp::OpConvertUToAccelerationStructureKHR, + R"(OpConvertUToAccelerationStructureKHR)", &s_operands[1365], + &s_operands[1366], 3, }, - { - SpirvOp::OpRayQueryGetIntersectionTypeKHR, - R"(OpRayQueryGetIntersectionTypeKHR)", - &s_operands[1368], - 4, - }, - { - SpirvOp::OpGroupIAddNonUniformAMD, - R"(OpGroupIAddNonUniformAMD)", - &s_operands[1372], - 5, - }, - { - SpirvOp::OpGroupFAddNonUniformAMD, - R"(OpGroupFAddNonUniformAMD)", - &s_operands[1377], - 5, - }, - { - SpirvOp::OpGroupFMinNonUniformAMD, - R"(OpGroupFMinNonUniformAMD)", - &s_operands[1382], - 5, - }, - { - SpirvOp::OpGroupUMinNonUniformAMD, - R"(OpGroupUMinNonUniformAMD)", - &s_operands[1387], - 5, - }, - { - SpirvOp::OpGroupSMinNonUniformAMD, - R"(OpGroupSMinNonUniformAMD)", - &s_operands[1392], - 5, - }, - { - SpirvOp::OpGroupFMaxNonUniformAMD, - R"(OpGroupFMaxNonUniformAMD)", - &s_operands[1397], - 5, - }, - { - SpirvOp::OpGroupUMaxNonUniformAMD, - R"(OpGroupUMaxNonUniformAMD)", - &s_operands[1402], - 5, - }, - { - SpirvOp::OpGroupSMaxNonUniformAMD, - R"(OpGroupSMaxNonUniformAMD)", - &s_operands[1407], - 5, - }, - { - SpirvOp::OpFragmentMaskFetchAMD, - R"(OpFragmentMaskFetchAMD)", - &s_operands[1412], - 4, - }, - { - SpirvOp::OpFragmentFetchAMD, - R"(OpFragmentFetchAMD)", - &s_operands[1416], - 5, - }, - { - SpirvOp::OpReadClockKHR, - R"(OpReadClockKHR)", - &s_operands[1421], - 3, - }, - { - SpirvOp::OpImageSampleFootprintNV, - R"(OpImageSampleFootprintNV)", - &s_operands[1424], - 7, - }, - { - SpirvOp::OpGroupNonUniformPartitionNV, - R"(OpGroupNonUniformPartitionNV)", - &s_operands[1431], - 3, - }, - { - SpirvOp::OpWritePackedPrimitiveIndices4x8NV, - R"(OpWritePackedPrimitiveIndices4x8NV)", - &s_operands[1434], - 2, - }, - { - SpirvOp::OpReportIntersectionKHR, - R"(OpReportIntersectionKHR)", - &s_operands[1436], - 4, - }, { SpirvOp::OpIgnoreIntersectionKHR, R"(OpIgnoreIntersectionKHR)", nullptr, + nullptr, 0, }, { SpirvOp::OpTerminateRayKHR, R"(OpTerminateRayKHR)", nullptr, + nullptr, 0, }, { - SpirvOp::OpTraceRayKHR, - R"(OpTraceRayKHR)", + SpirvOp::OpTypeRayQueryKHR, + R"(OpTypeRayQueryKHR)", + &s_operands[1368], + &s_operands[1368], + 1, + }, + { + SpirvOp::OpRayQueryInitializeKHR, + R"(OpRayQueryInitializeKHR)", + &s_operands[1369], + nullptr, + 8, + }, + { + SpirvOp::OpRayQueryTerminateKHR, + R"(OpRayQueryTerminateKHR)", + &s_operands[1377], + nullptr, + 1, + }, + { + SpirvOp::OpRayQueryGenerateIntersectionKHR, + R"(OpRayQueryGenerateIntersectionKHR)", + &s_operands[1378], + nullptr, + 2, + }, + { + SpirvOp::OpRayQueryConfirmIntersectionKHR, + R"(OpRayQueryConfirmIntersectionKHR)", + &s_operands[1380], + nullptr, + 1, + }, + { + SpirvOp::OpRayQueryProceedKHR, + R"(OpRayQueryProceedKHR)", + &s_operands[1381], + &s_operands[1382], + 3, + }, + { + SpirvOp::OpRayQueryGetIntersectionTypeKHR, + R"(OpRayQueryGetIntersectionTypeKHR)", + &s_operands[1384], + &s_operands[1385], + 4, + }, + { + SpirvOp::OpGroupIAddNonUniformAMD, + R"(OpGroupIAddNonUniformAMD)", + &s_operands[1388], + &s_operands[1389], + 5, + }, + { + SpirvOp::OpGroupFAddNonUniformAMD, + R"(OpGroupFAddNonUniformAMD)", + &s_operands[1393], + &s_operands[1394], + 5, + }, + { + SpirvOp::OpGroupFMinNonUniformAMD, + R"(OpGroupFMinNonUniformAMD)", + &s_operands[1398], + &s_operands[1399], + 5, + }, + { + SpirvOp::OpGroupUMinNonUniformAMD, + R"(OpGroupUMinNonUniformAMD)", + &s_operands[1403], + &s_operands[1404], + 5, + }, + { + SpirvOp::OpGroupSMinNonUniformAMD, + R"(OpGroupSMinNonUniformAMD)", + &s_operands[1408], + &s_operands[1409], + 5, + }, + { + SpirvOp::OpGroupFMaxNonUniformAMD, + R"(OpGroupFMaxNonUniformAMD)", + &s_operands[1413], + &s_operands[1414], + 5, + }, + { + SpirvOp::OpGroupUMaxNonUniformAMD, + R"(OpGroupUMaxNonUniformAMD)", + &s_operands[1418], + &s_operands[1419], + 5, + }, + { + SpirvOp::OpGroupSMaxNonUniformAMD, + R"(OpGroupSMaxNonUniformAMD)", + &s_operands[1423], + &s_operands[1424], + 5, + }, + { + SpirvOp::OpFragmentMaskFetchAMD, + R"(OpFragmentMaskFetchAMD)", + &s_operands[1428], + &s_operands[1429], + 4, + }, + { + SpirvOp::OpFragmentFetchAMD, + R"(OpFragmentFetchAMD)", + &s_operands[1432], + &s_operands[1433], + 5, + }, + { + SpirvOp::OpReadClockKHR, + R"(OpReadClockKHR)", + &s_operands[1437], + &s_operands[1438], + 3, + }, + { + SpirvOp::OpImageSampleFootprintNV, + R"(OpImageSampleFootprintNV)", &s_operands[1440], + &s_operands[1441], + 7, + }, + { + SpirvOp::OpGroupNonUniformPartitionNV, + R"(OpGroupNonUniformPartitionNV)", + &s_operands[1447], + &s_operands[1448], + 3, + }, + { + SpirvOp::OpWritePackedPrimitiveIndices4x8NV, + R"(OpWritePackedPrimitiveIndices4x8NV)", + &s_operands[1450], + nullptr, + 2, + }, + { + SpirvOp::OpReportIntersectionKHR, + R"(OpReportIntersectionKHR)", + &s_operands[1452], + &s_operands[1453], + 4, + }, + { + SpirvOp::OpIgnoreIntersectionNV, + R"(OpIgnoreIntersectionNV)", + nullptr, + nullptr, + 0, + }, + { + SpirvOp::OpTerminateRayNV, + R"(OpTerminateRayNV)", + nullptr, + nullptr, + 0, + }, + { + SpirvOp::OpTraceNV, + R"(OpTraceNV)", + &s_operands[1456], + nullptr, 11, }, { SpirvOp::OpTypeAccelerationStructureKHR, R"(OpTypeAccelerationStructureKHR)", - &s_operands[1451], + &s_operands[1467], + &s_operands[1467], 1, }, { - SpirvOp::OpExecuteCallableKHR, - R"(OpExecuteCallableKHR)", - &s_operands[1452], + SpirvOp::OpExecuteCallableNV, + R"(OpExecuteCallableNV)", + &s_operands[1468], + nullptr, 2, }, { SpirvOp::OpTypeCooperativeMatrixNV, R"(OpTypeCooperativeMatrixNV)", - &s_operands[1454], + &s_operands[1470], + &s_operands[1470], 5, }, { SpirvOp::OpCooperativeMatrixLoadNV, R"(OpCooperativeMatrixLoadNV)", - &s_operands[1459], + &s_operands[1475], + &s_operands[1476], 6, }, { SpirvOp::OpCooperativeMatrixStoreNV, R"(OpCooperativeMatrixStoreNV)", - &s_operands[1465], + &s_operands[1481], + nullptr, 5, }, { SpirvOp::OpCooperativeMatrixMulAddNV, R"(OpCooperativeMatrixMulAddNV)", - &s_operands[1470], + &s_operands[1486], + &s_operands[1487], 5, }, { SpirvOp::OpCooperativeMatrixLengthNV, R"(OpCooperativeMatrixLengthNV)", - &s_operands[1475], + &s_operands[1491], + &s_operands[1492], 3, }, { SpirvOp::OpBeginInvocationInterlockEXT, R"(OpBeginInvocationInterlockEXT)", nullptr, + nullptr, 0, }, { SpirvOp::OpEndInvocationInterlockEXT, R"(OpEndInvocationInterlockEXT)", nullptr, + nullptr, 0, }, { SpirvOp::OpDemoteToHelperInvocationEXT, R"(OpDemoteToHelperInvocationEXT)", nullptr, + nullptr, 0, }, { SpirvOp::OpIsHelperInvocationEXT, R"(OpIsHelperInvocationEXT)", - &s_operands[1478], + &s_operands[1494], + &s_operands[1495], 2, }, { SpirvOp::OpSubgroupShuffleINTEL, R"(OpSubgroupShuffleINTEL)", - &s_operands[1480], + &s_operands[1496], + &s_operands[1497], 4, }, { SpirvOp::OpSubgroupShuffleDownINTEL, R"(OpSubgroupShuffleDownINTEL)", - &s_operands[1484], + &s_operands[1500], + &s_operands[1501], 5, }, { SpirvOp::OpSubgroupShuffleUpINTEL, R"(OpSubgroupShuffleUpINTEL)", - &s_operands[1489], + &s_operands[1505], + &s_operands[1506], 5, }, { SpirvOp::OpSubgroupShuffleXorINTEL, R"(OpSubgroupShuffleXorINTEL)", - &s_operands[1494], + &s_operands[1510], + &s_operands[1511], 4, }, { SpirvOp::OpSubgroupBlockReadINTEL, R"(OpSubgroupBlockReadINTEL)", - &s_operands[1498], + &s_operands[1514], + &s_operands[1515], 3, }, { SpirvOp::OpSubgroupBlockWriteINTEL, R"(OpSubgroupBlockWriteINTEL)", - &s_operands[1501], + &s_operands[1517], + nullptr, 2, }, { SpirvOp::OpSubgroupImageBlockReadINTEL, R"(OpSubgroupImageBlockReadINTEL)", - &s_operands[1503], + &s_operands[1519], + &s_operands[1520], 4, }, { SpirvOp::OpSubgroupImageBlockWriteINTEL, R"(OpSubgroupImageBlockWriteINTEL)", - &s_operands[1507], + &s_operands[1523], + nullptr, 3, }, { SpirvOp::OpSubgroupImageMediaBlockReadINTEL, R"(OpSubgroupImageMediaBlockReadINTEL)", - &s_operands[1510], + &s_operands[1526], + &s_operands[1527], 6, }, { SpirvOp::OpSubgroupImageMediaBlockWriteINTEL, R"(OpSubgroupImageMediaBlockWriteINTEL)", - &s_operands[1516], + &s_operands[1532], + nullptr, 5, }, { SpirvOp::OpUCountLeadingZerosINTEL, R"(OpUCountLeadingZerosINTEL)", - &s_operands[1521], + &s_operands[1537], + &s_operands[1538], 3, }, { SpirvOp::OpUCountTrailingZerosINTEL, R"(OpUCountTrailingZerosINTEL)", - &s_operands[1524], + &s_operands[1540], + &s_operands[1541], 3, }, { SpirvOp::OpAbsISubINTEL, R"(OpAbsISubINTEL)", - &s_operands[1527], + &s_operands[1543], + &s_operands[1544], 4, }, { SpirvOp::OpAbsUSubINTEL, R"(OpAbsUSubINTEL)", - &s_operands[1531], + &s_operands[1547], + &s_operands[1548], 4, }, { SpirvOp::OpIAddSatINTEL, R"(OpIAddSatINTEL)", - &s_operands[1535], + &s_operands[1551], + &s_operands[1552], 4, }, { SpirvOp::OpUAddSatINTEL, R"(OpUAddSatINTEL)", - &s_operands[1539], + &s_operands[1555], + &s_operands[1556], 4, }, { SpirvOp::OpIAverageINTEL, R"(OpIAverageINTEL)", - &s_operands[1543], + &s_operands[1559], + &s_operands[1560], 4, }, { SpirvOp::OpUAverageINTEL, R"(OpUAverageINTEL)", - &s_operands[1547], + &s_operands[1563], + &s_operands[1564], 4, }, { SpirvOp::OpIAverageRoundedINTEL, R"(OpIAverageRoundedINTEL)", - &s_operands[1551], + &s_operands[1567], + &s_operands[1568], 4, }, { SpirvOp::OpUAverageRoundedINTEL, R"(OpUAverageRoundedINTEL)", - &s_operands[1555], + &s_operands[1571], + &s_operands[1572], 4, }, { SpirvOp::OpISubSatINTEL, R"(OpISubSatINTEL)", - &s_operands[1559], + &s_operands[1575], + &s_operands[1576], 4, }, { SpirvOp::OpUSubSatINTEL, R"(OpUSubSatINTEL)", - &s_operands[1563], + &s_operands[1579], + &s_operands[1580], 4, }, { SpirvOp::OpIMul32x16INTEL, R"(OpIMul32x16INTEL)", - &s_operands[1567], + &s_operands[1583], + &s_operands[1584], 4, }, { SpirvOp::OpUMul32x16INTEL, R"(OpUMul32x16INTEL)", - &s_operands[1571], + &s_operands[1587], + &s_operands[1588], 4, }, { - SpirvOp::OpFunctionPointerINTEL, - R"(OpFunctionPointerINTEL)", - &s_operands[1575], + SpirvOp::OpConstFunctionPointerINTEL, + R"(OpConstFunctionPointerINTEL)", + &s_operands[1591], + &s_operands[1592], 3, }, { SpirvOp::OpFunctionPointerCallINTEL, R"(OpFunctionPointerCallINTEL)", - &s_operands[1578], + &s_operands[1594], + &s_operands[1595], 3, }, + { + SpirvOp::OpAsmTargetINTEL, + R"(OpAsmTargetINTEL)", + &s_operands[1597], + &s_operands[1598], + 3, + }, + { + SpirvOp::OpAsmINTEL, + R"(OpAsmINTEL)", + &s_operands[1600], + &s_operands[1601], + 6, + }, + { + SpirvOp::OpAsmCallINTEL, + R"(OpAsmCallINTEL)", + &s_operands[1606], + &s_operands[1607], + 4, + }, + { + SpirvOp::OpAtomicFMinEXT, + R"(OpAtomicFMinEXT)", + &s_operands[1610], + &s_operands[1611], + 6, + }, + { + SpirvOp::OpAtomicFMaxEXT, + R"(OpAtomicFMaxEXT)", + &s_operands[1616], + &s_operands[1617], + 6, + }, + { + SpirvOp::OpAssumeTrueKHR, + R"(OpAssumeTrueKHR)", + &s_operands[1622], + nullptr, + 1, + }, + { + SpirvOp::OpExpectKHR, + R"(OpExpectKHR)", + &s_operands[1623], + &s_operands[1624], + 4, + }, { SpirvOp::OpDecorateStringGOOGLE, R"(OpDecorateStringGOOGLE)", - &s_operands[1581], + &s_operands[1627], + nullptr, 2, }, { SpirvOp::OpMemberDecorateStringGOOGLE, R"(OpMemberDecorateStringGOOGLE)", - &s_operands[1583], + &s_operands[1629], + nullptr, 3, }, { SpirvOp::OpVmeImageINTEL, R"(OpVmeImageINTEL)", - &s_operands[1586], + &s_operands[1632], + &s_operands[1633], 4, }, { SpirvOp::OpTypeVmeImageINTEL, R"(OpTypeVmeImageINTEL)", - &s_operands[1590], + &s_operands[1636], + &s_operands[1636], 2, }, { SpirvOp::OpTypeAvcImePayloadINTEL, R"(OpTypeAvcImePayloadINTEL)", - &s_operands[1592], + &s_operands[1638], + &s_operands[1638], 1, }, { SpirvOp::OpTypeAvcRefPayloadINTEL, R"(OpTypeAvcRefPayloadINTEL)", - &s_operands[1593], + &s_operands[1639], + &s_operands[1639], 1, }, { SpirvOp::OpTypeAvcSicPayloadINTEL, R"(OpTypeAvcSicPayloadINTEL)", - &s_operands[1594], + &s_operands[1640], + &s_operands[1640], 1, }, { SpirvOp::OpTypeAvcMcePayloadINTEL, R"(OpTypeAvcMcePayloadINTEL)", - &s_operands[1595], + &s_operands[1641], + &s_operands[1641], 1, }, { SpirvOp::OpTypeAvcMceResultINTEL, R"(OpTypeAvcMceResultINTEL)", - &s_operands[1596], + &s_operands[1642], + &s_operands[1642], 1, }, { SpirvOp::OpTypeAvcImeResultINTEL, R"(OpTypeAvcImeResultINTEL)", - &s_operands[1597], + &s_operands[1643], + &s_operands[1643], 1, }, { SpirvOp::OpTypeAvcImeResultSingleReferenceStreamoutINTEL, R"(OpTypeAvcImeResultSingleReferenceStreamoutINTEL)", - &s_operands[1598], + &s_operands[1644], + &s_operands[1644], 1, }, { SpirvOp::OpTypeAvcImeResultDualReferenceStreamoutINTEL, R"(OpTypeAvcImeResultDualReferenceStreamoutINTEL)", - &s_operands[1599], + &s_operands[1645], + &s_operands[1645], 1, }, { SpirvOp::OpTypeAvcImeSingleReferenceStreaminINTEL, R"(OpTypeAvcImeSingleReferenceStreaminINTEL)", - &s_operands[1600], + &s_operands[1646], + &s_operands[1646], 1, }, { SpirvOp::OpTypeAvcImeDualReferenceStreaminINTEL, R"(OpTypeAvcImeDualReferenceStreaminINTEL)", - &s_operands[1601], + &s_operands[1647], + &s_operands[1647], 1, }, { SpirvOp::OpTypeAvcRefResultINTEL, R"(OpTypeAvcRefResultINTEL)", - &s_operands[1602], + &s_operands[1648], + &s_operands[1648], 1, }, { SpirvOp::OpTypeAvcSicResultINTEL, R"(OpTypeAvcSicResultINTEL)", - &s_operands[1603], + &s_operands[1649], + &s_operands[1649], 1, }, { SpirvOp::OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL, R"(OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL)", - &s_operands[1604], + &s_operands[1650], + &s_operands[1651], 4, }, { SpirvOp::OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL, R"(OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL)", - &s_operands[1608], + &s_operands[1654], + &s_operands[1655], 4, }, { SpirvOp::OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL, R"(OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL)", - &s_operands[1612], + &s_operands[1658], + &s_operands[1659], 4, }, { SpirvOp::OpSubgroupAvcMceSetInterShapePenaltyINTEL, R"(OpSubgroupAvcMceSetInterShapePenaltyINTEL)", - &s_operands[1616], + &s_operands[1662], + &s_operands[1663], 4, }, { SpirvOp::OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL, R"(OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL)", - &s_operands[1620], + &s_operands[1666], + &s_operands[1667], 4, }, { SpirvOp::OpSubgroupAvcMceSetInterDirectionPenaltyINTEL, R"(OpSubgroupAvcMceSetInterDirectionPenaltyINTEL)", - &s_operands[1624], + &s_operands[1670], + &s_operands[1671], 4, }, { SpirvOp::OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL, R"(OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL)", - &s_operands[1628], + &s_operands[1674], + &s_operands[1675], 4, }, { SpirvOp::OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL, R"(OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL)", - &s_operands[1632], + &s_operands[1678], + &s_operands[1679], 4, }, { SpirvOp::OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL, R"(OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL)", - &s_operands[1636], + &s_operands[1682], + &s_operands[1683], 2, }, { SpirvOp::OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL, R"(OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL)", - &s_operands[1638], + &s_operands[1684], + &s_operands[1685], 2, }, { SpirvOp::OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL, R"(OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL)", - &s_operands[1640], + &s_operands[1686], + &s_operands[1687], 2, }, { SpirvOp::OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL, R"(OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL)", - &s_operands[1642], + &s_operands[1688], + &s_operands[1689], 6, }, { SpirvOp::OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL, R"(OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL)", - &s_operands[1648], + &s_operands[1694], + &s_operands[1695], 4, }, { SpirvOp::OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL, R"(OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL)", - &s_operands[1652], + &s_operands[1698], + &s_operands[1699], 2, }, { SpirvOp::OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL, R"(OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL)", - &s_operands[1654], + &s_operands[1700], + &s_operands[1701], 2, }, { SpirvOp::OpSubgroupAvcMceSetAcOnlyHaarINTEL, R"(OpSubgroupAvcMceSetAcOnlyHaarINTEL)", - &s_operands[1656], + &s_operands[1702], + &s_operands[1703], 3, }, { SpirvOp::OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL, R"(OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL)", - &s_operands[1659], + &s_operands[1705], + &s_operands[1706], 4, }, { SpirvOp::OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL, R"(OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL)", - &s_operands[1663], + &s_operands[1709], + &s_operands[1710], 4, }, { SpirvOp::OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL, R"(OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL)", - &s_operands[1667], + &s_operands[1713], + &s_operands[1714], 5, }, { SpirvOp::OpSubgroupAvcMceConvertToImePayloadINTEL, R"(OpSubgroupAvcMceConvertToImePayloadINTEL)", - &s_operands[1672], + &s_operands[1718], + &s_operands[1719], 3, }, { SpirvOp::OpSubgroupAvcMceConvertToImeResultINTEL, R"(OpSubgroupAvcMceConvertToImeResultINTEL)", - &s_operands[1675], + &s_operands[1721], + &s_operands[1722], 3, }, { SpirvOp::OpSubgroupAvcMceConvertToRefPayloadINTEL, R"(OpSubgroupAvcMceConvertToRefPayloadINTEL)", - &s_operands[1678], + &s_operands[1724], + &s_operands[1725], 3, }, { SpirvOp::OpSubgroupAvcMceConvertToRefResultINTEL, R"(OpSubgroupAvcMceConvertToRefResultINTEL)", - &s_operands[1681], + &s_operands[1727], + &s_operands[1728], 3, }, { SpirvOp::OpSubgroupAvcMceConvertToSicPayloadINTEL, R"(OpSubgroupAvcMceConvertToSicPayloadINTEL)", - &s_operands[1684], + &s_operands[1730], + &s_operands[1731], 3, }, { SpirvOp::OpSubgroupAvcMceConvertToSicResultINTEL, R"(OpSubgroupAvcMceConvertToSicResultINTEL)", - &s_operands[1687], + &s_operands[1733], + &s_operands[1734], 3, }, { SpirvOp::OpSubgroupAvcMceGetMotionVectorsINTEL, R"(OpSubgroupAvcMceGetMotionVectorsINTEL)", - &s_operands[1690], + &s_operands[1736], + &s_operands[1737], 3, }, { SpirvOp::OpSubgroupAvcMceGetInterDistortionsINTEL, R"(OpSubgroupAvcMceGetInterDistortionsINTEL)", - &s_operands[1693], + &s_operands[1739], + &s_operands[1740], 3, }, { SpirvOp::OpSubgroupAvcMceGetBestInterDistortionsINTEL, R"(OpSubgroupAvcMceGetBestInterDistortionsINTEL)", - &s_operands[1696], + &s_operands[1742], + &s_operands[1743], 3, }, { SpirvOp::OpSubgroupAvcMceGetInterMajorShapeINTEL, R"(OpSubgroupAvcMceGetInterMajorShapeINTEL)", - &s_operands[1699], + &s_operands[1745], + &s_operands[1746], 3, }, { SpirvOp::OpSubgroupAvcMceGetInterMinorShapeINTEL, R"(OpSubgroupAvcMceGetInterMinorShapeINTEL)", - &s_operands[1702], + &s_operands[1748], + &s_operands[1749], 3, }, { SpirvOp::OpSubgroupAvcMceGetInterDirectionsINTEL, R"(OpSubgroupAvcMceGetInterDirectionsINTEL)", - &s_operands[1705], + &s_operands[1751], + &s_operands[1752], 3, }, { SpirvOp::OpSubgroupAvcMceGetInterMotionVectorCountINTEL, R"(OpSubgroupAvcMceGetInterMotionVectorCountINTEL)", - &s_operands[1708], + &s_operands[1754], + &s_operands[1755], 3, }, { SpirvOp::OpSubgroupAvcMceGetInterReferenceIdsINTEL, R"(OpSubgroupAvcMceGetInterReferenceIdsINTEL)", - &s_operands[1711], + &s_operands[1757], + &s_operands[1758], 3, }, { SpirvOp::OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL, R"(OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL)", - &s_operands[1714], + &s_operands[1760], + &s_operands[1761], 5, }, { SpirvOp::OpSubgroupAvcImeInitializeINTEL, R"(OpSubgroupAvcImeInitializeINTEL)", - &s_operands[1719], + &s_operands[1765], + &s_operands[1766], 5, }, { SpirvOp::OpSubgroupAvcImeSetSingleReferenceINTEL, R"(OpSubgroupAvcImeSetSingleReferenceINTEL)", - &s_operands[1724], + &s_operands[1770], + &s_operands[1771], 5, }, { SpirvOp::OpSubgroupAvcImeSetDualReferenceINTEL, R"(OpSubgroupAvcImeSetDualReferenceINTEL)", - &s_operands[1729], + &s_operands[1775], + &s_operands[1776], 6, }, { SpirvOp::OpSubgroupAvcImeRefWindowSizeINTEL, R"(OpSubgroupAvcImeRefWindowSizeINTEL)", - &s_operands[1735], + &s_operands[1781], + &s_operands[1782], 4, }, { SpirvOp::OpSubgroupAvcImeAdjustRefOffsetINTEL, R"(OpSubgroupAvcImeAdjustRefOffsetINTEL)", - &s_operands[1739], + &s_operands[1785], + &s_operands[1786], 6, }, { SpirvOp::OpSubgroupAvcImeConvertToMcePayloadINTEL, R"(OpSubgroupAvcImeConvertToMcePayloadINTEL)", - &s_operands[1745], + &s_operands[1791], + &s_operands[1792], 3, }, { SpirvOp::OpSubgroupAvcImeSetMaxMotionVectorCountINTEL, R"(OpSubgroupAvcImeSetMaxMotionVectorCountINTEL)", - &s_operands[1748], + &s_operands[1794], + &s_operands[1795], 4, }, { SpirvOp::OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL, R"(OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL)", - &s_operands[1752], + &s_operands[1798], + &s_operands[1799], 3, }, { SpirvOp::OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL, R"(OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL)", - &s_operands[1755], + &s_operands[1801], + &s_operands[1802], 4, }, { SpirvOp::OpSubgroupAvcImeSetWeightedSadINTEL, R"(OpSubgroupAvcImeSetWeightedSadINTEL)", - &s_operands[1759], + &s_operands[1805], + &s_operands[1806], 4, }, { SpirvOp::OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL, R"(OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL)", - &s_operands[1763], + &s_operands[1809], + &s_operands[1810], 5, }, { SpirvOp::OpSubgroupAvcImeEvaluateWithDualReferenceINTEL, R"(OpSubgroupAvcImeEvaluateWithDualReferenceINTEL)", - &s_operands[1768], + &s_operands[1814], + &s_operands[1815], 6, }, { SpirvOp::OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL, R"(OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL)", - &s_operands[1774], + &s_operands[1820], + &s_operands[1821], 6, }, { SpirvOp::OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL, R"(OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL)", - &s_operands[1780], + &s_operands[1826], + &s_operands[1827], 7, }, { SpirvOp::OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL, R"(OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL)", - &s_operands[1787], + &s_operands[1833], + &s_operands[1834], 5, }, { SpirvOp::OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL, R"(OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL)", - &s_operands[1792], + &s_operands[1838], + &s_operands[1839], 6, }, { SpirvOp::OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL, R"(OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL)", - &s_operands[1798], + &s_operands[1844], + &s_operands[1845], 6, }, { SpirvOp::OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL, R"(OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL)", - &s_operands[1804], + &s_operands[1850], + &s_operands[1851], 7, }, { SpirvOp::OpSubgroupAvcImeConvertToMceResultINTEL, R"(OpSubgroupAvcImeConvertToMceResultINTEL)", - &s_operands[1811], + &s_operands[1857], + &s_operands[1858], 3, }, { SpirvOp::OpSubgroupAvcImeGetSingleReferenceStreaminINTEL, R"(OpSubgroupAvcImeGetSingleReferenceStreaminINTEL)", - &s_operands[1814], + &s_operands[1860], + &s_operands[1861], 3, }, { SpirvOp::OpSubgroupAvcImeGetDualReferenceStreaminINTEL, R"(OpSubgroupAvcImeGetDualReferenceStreaminINTEL)", - &s_operands[1817], + &s_operands[1863], + &s_operands[1864], 3, }, { SpirvOp::OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL, R"(OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL)", - &s_operands[1820], + &s_operands[1866], + &s_operands[1867], 3, }, { SpirvOp::OpSubgroupAvcImeStripDualReferenceStreamoutINTEL, R"(OpSubgroupAvcImeStripDualReferenceStreamoutINTEL)", - &s_operands[1823], + &s_operands[1869], + &s_operands[1870], 3, }, { SpirvOp::OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL, R"(OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL)", - &s_operands[1826], + &s_operands[1872], + &s_operands[1873], 4, }, { SpirvOp::OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL, R"(OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL)", - &s_operands[1830], + &s_operands[1876], + &s_operands[1877], 4, }, { SpirvOp::OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL, R"(OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL)", - &s_operands[1834], + &s_operands[1880], + &s_operands[1881], 4, }, { SpirvOp::OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL, R"(OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL)", - &s_operands[1838], + &s_operands[1884], + &s_operands[1885], 5, }, { SpirvOp::OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL, R"(OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL)", - &s_operands[1843], + &s_operands[1889], + &s_operands[1890], 5, }, { SpirvOp::OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL, R"(OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL)", - &s_operands[1848], + &s_operands[1894], + &s_operands[1895], 5, }, { SpirvOp::OpSubgroupAvcImeGetBorderReachedINTEL, R"(OpSubgroupAvcImeGetBorderReachedINTEL)", - &s_operands[1853], + &s_operands[1899], + &s_operands[1900], 4, }, { SpirvOp::OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL, R"(OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL)", - &s_operands[1857], + &s_operands[1903], + &s_operands[1904], 3, }, { SpirvOp::OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL, R"(OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL)", - &s_operands[1860], + &s_operands[1906], + &s_operands[1907], 3, }, { SpirvOp::OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL, R"(OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL)", - &s_operands[1863], + &s_operands[1909], + &s_operands[1910], 3, }, { SpirvOp::OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL, R"(OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL)", - &s_operands[1866], + &s_operands[1912], + &s_operands[1913], 3, }, { SpirvOp::OpSubgroupAvcFmeInitializeINTEL, R"(OpSubgroupAvcFmeInitializeINTEL)", - &s_operands[1869], + &s_operands[1915], + &s_operands[1916], 9, }, { SpirvOp::OpSubgroupAvcBmeInitializeINTEL, R"(OpSubgroupAvcBmeInitializeINTEL)", - &s_operands[1878], + &s_operands[1924], + &s_operands[1925], 10, }, { SpirvOp::OpSubgroupAvcRefConvertToMcePayloadINTEL, R"(OpSubgroupAvcRefConvertToMcePayloadINTEL)", - &s_operands[1888], + &s_operands[1934], + &s_operands[1935], 3, }, { SpirvOp::OpSubgroupAvcRefSetBidirectionalMixDisableINTEL, R"(OpSubgroupAvcRefSetBidirectionalMixDisableINTEL)", - &s_operands[1891], + &s_operands[1937], + &s_operands[1938], 3, }, { SpirvOp::OpSubgroupAvcRefSetBilinearFilterEnableINTEL, R"(OpSubgroupAvcRefSetBilinearFilterEnableINTEL)", - &s_operands[1894], + &s_operands[1940], + &s_operands[1941], 3, }, { SpirvOp::OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL, R"(OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL)", - &s_operands[1897], + &s_operands[1943], + &s_operands[1944], 5, }, { SpirvOp::OpSubgroupAvcRefEvaluateWithDualReferenceINTEL, R"(OpSubgroupAvcRefEvaluateWithDualReferenceINTEL)", - &s_operands[1902], + &s_operands[1948], + &s_operands[1949], 6, }, { SpirvOp::OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL, R"(OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL)", - &s_operands[1908], + &s_operands[1954], + &s_operands[1955], 5, }, { SpirvOp::OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL, R"(OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL)", - &s_operands[1913], + &s_operands[1959], + &s_operands[1960], 6, }, { SpirvOp::OpSubgroupAvcRefConvertToMceResultINTEL, R"(OpSubgroupAvcRefConvertToMceResultINTEL)", - &s_operands[1919], + &s_operands[1965], + &s_operands[1966], 3, }, { SpirvOp::OpSubgroupAvcSicInitializeINTEL, R"(OpSubgroupAvcSicInitializeINTEL)", - &s_operands[1922], + &s_operands[1968], + &s_operands[1969], 3, }, { SpirvOp::OpSubgroupAvcSicConfigureSkcINTEL, R"(OpSubgroupAvcSicConfigureSkcINTEL)", - &s_operands[1925], + &s_operands[1971], + &s_operands[1972], 8, }, { SpirvOp::OpSubgroupAvcSicConfigureIpeLumaINTEL, R"(OpSubgroupAvcSicConfigureIpeLumaINTEL)", - &s_operands[1933], + &s_operands[1979], + &s_operands[1980], 10, }, { SpirvOp::OpSubgroupAvcSicConfigureIpeLumaChromaINTEL, R"(OpSubgroupAvcSicConfigureIpeLumaChromaINTEL)", - &s_operands[1943], + &s_operands[1989], + &s_operands[1990], 13, }, { SpirvOp::OpSubgroupAvcSicGetMotionVectorMaskINTEL, R"(OpSubgroupAvcSicGetMotionVectorMaskINTEL)", - &s_operands[1956], + &s_operands[2002], + &s_operands[2003], 4, }, { SpirvOp::OpSubgroupAvcSicConvertToMcePayloadINTEL, R"(OpSubgroupAvcSicConvertToMcePayloadINTEL)", - &s_operands[1960], + &s_operands[2006], + &s_operands[2007], 3, }, { SpirvOp::OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL, R"(OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL)", - &s_operands[1963], + &s_operands[2009], + &s_operands[2010], 4, }, { SpirvOp::OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL, R"(OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL)", - &s_operands[1967], + &s_operands[2013], + &s_operands[2014], 6, }, { SpirvOp::OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL, R"(OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL)", - &s_operands[1973], + &s_operands[2019], + &s_operands[2020], 4, }, { SpirvOp::OpSubgroupAvcSicSetBilinearFilterEnableINTEL, R"(OpSubgroupAvcSicSetBilinearFilterEnableINTEL)", - &s_operands[1977], + &s_operands[2023], + &s_operands[2024], 3, }, { SpirvOp::OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL, R"(OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL)", - &s_operands[1980], + &s_operands[2026], + &s_operands[2027], 4, }, { SpirvOp::OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL, R"(OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL)", - &s_operands[1984], + &s_operands[2030], + &s_operands[2031], 4, }, { SpirvOp::OpSubgroupAvcSicEvaluateIpeINTEL, R"(OpSubgroupAvcSicEvaluateIpeINTEL)", - &s_operands[1988], + &s_operands[2034], + &s_operands[2035], 4, }, { SpirvOp::OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL, R"(OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL)", - &s_operands[1992], + &s_operands[2038], + &s_operands[2039], 5, }, { SpirvOp::OpSubgroupAvcSicEvaluateWithDualReferenceINTEL, R"(OpSubgroupAvcSicEvaluateWithDualReferenceINTEL)", - &s_operands[1997], + &s_operands[2043], + &s_operands[2044], 6, }, { SpirvOp::OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL, R"(OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL)", - &s_operands[2003], + &s_operands[2049], + &s_operands[2050], 5, }, { SpirvOp::OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL, R"(OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL)", - &s_operands[2008], + &s_operands[2054], + &s_operands[2055], 6, }, { SpirvOp::OpSubgroupAvcSicConvertToMceResultINTEL, R"(OpSubgroupAvcSicConvertToMceResultINTEL)", - &s_operands[2014], + &s_operands[2060], + &s_operands[2061], 3, }, { SpirvOp::OpSubgroupAvcSicGetIpeLumaShapeINTEL, R"(OpSubgroupAvcSicGetIpeLumaShapeINTEL)", - &s_operands[2017], + &s_operands[2063], + &s_operands[2064], 3, }, { SpirvOp::OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL, R"(OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL)", - &s_operands[2020], + &s_operands[2066], + &s_operands[2067], 3, }, { SpirvOp::OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL, R"(OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL)", - &s_operands[2023], + &s_operands[2069], + &s_operands[2070], 3, }, { SpirvOp::OpSubgroupAvcSicGetPackedIpeLumaModesINTEL, R"(OpSubgroupAvcSicGetPackedIpeLumaModesINTEL)", - &s_operands[2026], + &s_operands[2072], + &s_operands[2073], 3, }, { SpirvOp::OpSubgroupAvcSicGetIpeChromaModeINTEL, R"(OpSubgroupAvcSicGetIpeChromaModeINTEL)", - &s_operands[2029], + &s_operands[2075], + &s_operands[2076], 3, }, { SpirvOp::OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL, R"(OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL)", - &s_operands[2032], + &s_operands[2078], + &s_operands[2079], 3, }, { SpirvOp::OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL, R"(OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL)", - &s_operands[2035], + &s_operands[2081], + &s_operands[2082], 3, }, { SpirvOp::OpSubgroupAvcSicGetInterRawSadsINTEL, R"(OpSubgroupAvcSicGetInterRawSadsINTEL)", - &s_operands[2038], + &s_operands[2084], + &s_operands[2085], 3, }, + { + SpirvOp::OpVariableLengthArrayINTEL, + R"(OpVariableLengthArrayINTEL)", + &s_operands[2087], + &s_operands[2088], + 3, + }, + { + SpirvOp::OpSaveMemoryINTEL, + R"(OpSaveMemoryINTEL)", + &s_operands[2090], + &s_operands[2091], + 2, + }, + { + SpirvOp::OpRestoreMemoryINTEL, + R"(OpRestoreMemoryINTEL)", + &s_operands[2092], + nullptr, + 1, + }, { SpirvOp::OpLoopControlINTEL, R"(OpLoopControlINTEL)", - &s_operands[2041], + &s_operands[2093], + nullptr, 1, }, + { + SpirvOp::OpPtrCastToCrossWorkgroupINTEL, + R"(OpPtrCastToCrossWorkgroupINTEL)", + &s_operands[2094], + &s_operands[2095], + 3, + }, + { + SpirvOp::OpCrossWorkgroupCastToPtrINTEL, + R"(OpCrossWorkgroupCastToPtrINTEL)", + &s_operands[2097], + &s_operands[2098], + 3, + }, { SpirvOp::OpReadPipeBlockingINTEL, R"(OpReadPipeBlockingINTEL)", - &s_operands[2042], + &s_operands[2100], + &s_operands[2101], 4, }, { SpirvOp::OpWritePipeBlockingINTEL, R"(OpWritePipeBlockingINTEL)", - &s_operands[2046], + &s_operands[2104], + &s_operands[2105], 4, }, { SpirvOp::OpFPGARegINTEL, R"(OpFPGARegINTEL)", - &s_operands[2050], + &s_operands[2108], + &s_operands[2109], 4, }, { SpirvOp::OpRayQueryGetRayTMinKHR, R"(OpRayQueryGetRayTMinKHR)", - &s_operands[2054], + &s_operands[2112], + &s_operands[2113], 3, }, { SpirvOp::OpRayQueryGetRayFlagsKHR, R"(OpRayQueryGetRayFlagsKHR)", - &s_operands[2057], + &s_operands[2115], + &s_operands[2116], 3, }, { SpirvOp::OpRayQueryGetIntersectionTKHR, R"(OpRayQueryGetIntersectionTKHR)", - &s_operands[2060], + &s_operands[2118], + &s_operands[2119], 4, }, { SpirvOp::OpRayQueryGetIntersectionInstanceCustomIndexKHR, R"(OpRayQueryGetIntersectionInstanceCustomIndexKHR)", - &s_operands[2064], + &s_operands[2122], + &s_operands[2123], 4, }, { SpirvOp::OpRayQueryGetIntersectionInstanceIdKHR, R"(OpRayQueryGetIntersectionInstanceIdKHR)", - &s_operands[2068], + &s_operands[2126], + &s_operands[2127], 4, }, { SpirvOp::OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR, R"(OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR)", - &s_operands[2072], + &s_operands[2130], + &s_operands[2131], 4, }, { SpirvOp::OpRayQueryGetIntersectionGeometryIndexKHR, R"(OpRayQueryGetIntersectionGeometryIndexKHR)", - &s_operands[2076], + &s_operands[2134], + &s_operands[2135], 4, }, { SpirvOp::OpRayQueryGetIntersectionPrimitiveIndexKHR, R"(OpRayQueryGetIntersectionPrimitiveIndexKHR)", - &s_operands[2080], + &s_operands[2138], + &s_operands[2139], 4, }, { SpirvOp::OpRayQueryGetIntersectionBarycentricsKHR, R"(OpRayQueryGetIntersectionBarycentricsKHR)", - &s_operands[2084], + &s_operands[2142], + &s_operands[2143], 4, }, { SpirvOp::OpRayQueryGetIntersectionFrontFaceKHR, R"(OpRayQueryGetIntersectionFrontFaceKHR)", - &s_operands[2088], + &s_operands[2146], + &s_operands[2147], 4, }, { SpirvOp::OpRayQueryGetIntersectionCandidateAABBOpaqueKHR, R"(OpRayQueryGetIntersectionCandidateAABBOpaqueKHR)", - &s_operands[2092], + &s_operands[2150], + &s_operands[2151], 3, }, { SpirvOp::OpRayQueryGetIntersectionObjectRayDirectionKHR, R"(OpRayQueryGetIntersectionObjectRayDirectionKHR)", - &s_operands[2095], + &s_operands[2153], + &s_operands[2154], 4, }, { SpirvOp::OpRayQueryGetIntersectionObjectRayOriginKHR, R"(OpRayQueryGetIntersectionObjectRayOriginKHR)", - &s_operands[2099], + &s_operands[2157], + &s_operands[2158], 4, }, { SpirvOp::OpRayQueryGetWorldRayDirectionKHR, R"(OpRayQueryGetWorldRayDirectionKHR)", - &s_operands[2103], + &s_operands[2161], + &s_operands[2162], 3, }, { SpirvOp::OpRayQueryGetWorldRayOriginKHR, R"(OpRayQueryGetWorldRayOriginKHR)", - &s_operands[2106], + &s_operands[2164], + &s_operands[2165], 3, }, { SpirvOp::OpRayQueryGetIntersectionObjectToWorldKHR, R"(OpRayQueryGetIntersectionObjectToWorldKHR)", - &s_operands[2109], + &s_operands[2167], + &s_operands[2168], 4, }, { SpirvOp::OpRayQueryGetIntersectionWorldToObjectKHR, R"(OpRayQueryGetIntersectionWorldToObjectKHR)", - &s_operands[2113], + &s_operands[2171], + &s_operands[2172], 4, }, { SpirvOp::OpAtomicFAddEXT, R"(OpAtomicFAddEXT)", - &s_operands[2117], + &s_operands[2175], + &s_operands[2176], 6, }, + { + SpirvOp::OpTypeBufferSurfaceINTEL, + R"(OpTypeBufferSurfaceINTEL)", + &s_operands[2181], + &s_operands[2181], + 1, + }, + { + SpirvOp::OpTypeStructContinuedINTEL, + R"(OpTypeStructContinuedINTEL)", + &s_operands[2182], + nullptr, + 1, + }, + { + SpirvOp::OpConstantCompositeContinuedINTEL, + R"(OpConstantCompositeContinuedINTEL)", + &s_operands[2183], + nullptr, + 1, + }, + { + SpirvOp::OpSpecConstantCompositeContinuedINTEL, + R"(OpSpecConstantCompositeContinuedINTEL)", + &s_operands[2184], + nullptr, + 1, + }, } }; diff --git a/src/Nazara/Shader/SpirvDecoder.cpp b/src/Nazara/Shader/SpirvDecoder.cpp new file mode 100644 index 000000000..cef949889 --- /dev/null +++ b/src/Nazara/Shader/SpirvDecoder.cpp @@ -0,0 +1,89 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + void SpirvDecoder::Decode(const UInt32* codepoints, std::size_t count) + { + m_currentCodepoint = codepoints; + m_codepointEnd = codepoints + count; + + UInt32 magicNumber = ReadWord(); + if (magicNumber != SpirvMagicNumber) + throw std::runtime_error("invalid Spir-V: magic number didn't match"); + + UInt32 versionNumber = ReadWord(); + if (versionNumber > SpirvVersion) + throw std::runtime_error("Spir-V is more recent than decoder, dismissing"); + + SpirvHeader header; + header.generatorId = ReadWord(); + header.bound = ReadWord(); + header.schema = ReadWord(); + header.versionNumber = versionNumber; + + if (!HandleHeader(header)) + return; + + while (m_currentCodepoint < m_codepointEnd) + { + const UInt32* instructionBegin = m_currentCodepoint; + + UInt32 firstWord = ReadWord(); + + UInt16 wordCount = static_cast((firstWord >> 16) & 0xFFFF); + UInt16 opcode = static_cast(firstWord & 0xFFFF); + + const SpirvInstruction* inst = GetInstructionData(opcode); + if (!inst) + throw std::runtime_error("invalid instruction"); + + if (!HandleOpcode(*inst, wordCount)) + break; + + m_currentCodepoint = instructionBegin + wordCount; + } + } + + bool SpirvDecoder::HandleHeader(const SpirvHeader& /*header*/) + { + return true; + } + + std::string SpirvDecoder::ReadString() + { + std::string str; + + for (;;) + { + UInt32 value = ReadWord(); + for (std::size_t j = 0; j < 4; ++j) + { + char c = static_cast((value >> (j * 8)) & 0xFF); + if (c == '\0') + return str; + + str.push_back(c); + } + } + } + + UInt32 SpirvDecoder::ReadWord() + { + if (m_currentCodepoint >= m_codepointEnd) + throw std::runtime_error("unexpected end of stream"); + + return *m_currentCodepoint++; + } +} diff --git a/src/Nazara/Shader/SpirvExpressionLoad.cpp b/src/Nazara/Shader/SpirvExpressionLoad.cpp index 026fefee8..30ebadc2a 100644 --- a/src/Nazara/Shader/SpirvExpressionLoad.cpp +++ b/src/Nazara/Shader/SpirvExpressionLoad.cpp @@ -3,8 +3,9 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include -#include -#include +#include +#include +#include #include #include @@ -13,10 +14,10 @@ namespace Nz namespace { template struct overloaded : Ts... { using Ts::operator()...; }; - template overloaded(Ts...)->overloaded; + template overloaded(Ts...) -> overloaded; } - UInt32 SpirvExpressionLoad::Evaluate(ShaderNodes::Expression& node) + UInt32 SpirvExpressionLoad::Evaluate(ShaderAst::Expression& node) { node.Visit(*this); @@ -24,9 +25,8 @@ namespace Nz { [this](const Pointer& pointer) -> UInt32 { - UInt32 resultId = m_writer.AllocateResultId(); - - m_writer.GetInstructions().Append(SpirvOp::OpLoad, pointer.pointedTypeId, resultId, pointer.resultId); + UInt32 resultId = m_visitor.AllocateResultId(); + m_block.Append(SpirvOp::OpLoad, pointer.pointedTypeId, resultId, pointer.pointerId); return resultId; }, @@ -41,43 +41,51 @@ namespace Nz }, m_value); } - void SpirvExpressionLoad::Visit(ShaderNodes::AccessMember& node) + void SpirvExpressionLoad::Visit(ShaderAst::AccessIndexExpression& node) { - Visit(node.structExpr); + node.expr->Visit(*this); + + const ShaderAst::ExpressionType& exprType = GetExpressionType(node); + + UInt32 resultId = m_visitor.AllocateResultId(); + UInt32 typeId = m_writer.GetTypeId(exprType); std::visit(overloaded { [&](const Pointer& pointer) { - UInt32 resultId = m_writer.AllocateResultId(); - UInt32 pointerType = m_writer.RegisterPointerType(node.exprType, pointer.storage); //< FIXME - UInt32 typeId = m_writer.GetTypeId(node.exprType); + UInt32 pointerType = m_writer.RegisterPointerType(exprType, pointer.storage); //< FIXME - m_writer.GetInstructions().AppendVariadic(SpirvOp::OpAccessChain, [&](const auto& appender) + StackArray indexIds = NazaraStackArrayNoInit(UInt32, node.indices.size()); + for (std::size_t i = 0; i < node.indices.size(); ++i) + indexIds[i] = m_visitor.EvaluateExpression(node.indices[i]); + + m_block.AppendVariadic(SpirvOp::OpAccessChain, [&](const auto& appender) { appender(pointerType); appender(resultId); - appender(pointer.resultId); + appender(pointer.pointerId); - for (std::size_t index : node.memberIndices) - appender(m_writer.GetConstantId(Int32(index))); + for (UInt32 id : indexIds) + appender(id); }); m_value = Pointer { pointer.storage, resultId, typeId }; }, [&](const Value& value) { - UInt32 resultId = m_writer.AllocateResultId(); - UInt32 typeId = m_writer.GetTypeId(node.exprType); + StackArray indexIds = NazaraStackArrayNoInit(UInt32, node.indices.size()); + for (std::size_t i = 0; i < node.indices.size(); ++i) + indexIds[i] = m_visitor.EvaluateExpression(node.indices[i]); - m_writer.GetInstructions().AppendVariadic(SpirvOp::OpCompositeExtract, [&](const auto& appender) + m_block.AppendVariadic(SpirvOp::OpCompositeExtract, [&](const auto& appender) { appender(typeId); appender(resultId); appender(value.resultId); - for (std::size_t index : node.memberIndices) - appender(m_writer.GetConstantId(Int32(index))); + for (UInt32 id : indexIds) + appender(id); }); m_value = Value { resultId }; @@ -89,33 +97,9 @@ namespace Nz }, m_value); } - void SpirvExpressionLoad::Visit(ShaderNodes::Identifier& node) + void SpirvExpressionLoad::Visit(ShaderAst::VariableExpression& node) { - Visit(node.var); - } - - void SpirvExpressionLoad::Visit(ShaderNodes::InputVariable& var) - { - auto inputVar = m_writer.GetInputVariable(var.name); - - if (auto resultIdOpt = m_writer.ReadVariable(inputVar, SpirvWriter::OnlyCache{})) - m_value = Value{ *resultIdOpt }; - else - m_value = Pointer{ SpirvStorageClass::Input, inputVar.varId, inputVar.typeId }; - } - - void SpirvExpressionLoad::Visit(ShaderNodes::LocalVariable& var) - { - m_value = Value{ m_writer.ReadLocalVariable(var.name) }; - } - - void SpirvExpressionLoad::Visit(ShaderNodes::UniformVariable& var) - { - auto uniformVar = m_writer.GetUniformVariable(var.name); - - if (auto resultIdOpt = m_writer.ReadVariable(uniformVar, SpirvWriter::OnlyCache{})) - m_value = Value{ *resultIdOpt }; - else - m_value = Pointer{ SpirvStorageClass::Uniform, uniformVar.varId, uniformVar.typeId }; + const auto& var = m_visitor.GetVariable(node.variableId); + m_value = Pointer{ var.storage, var.pointerId, var.pointedTypeId }; } } diff --git a/src/Nazara/Shader/SpirvExpressionStore.cpp b/src/Nazara/Shader/SpirvExpressionStore.cpp index 9123bdcf4..47fba160c 100644 --- a/src/Nazara/Shader/SpirvExpressionStore.cpp +++ b/src/Nazara/Shader/SpirvExpressionStore.cpp @@ -3,7 +3,9 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include -#include +#include +#include +#include #include #include @@ -15,19 +17,19 @@ namespace Nz template overloaded(Ts...)->overloaded; } - void SpirvExpressionStore::Store(const ShaderNodes::ExpressionPtr& node, UInt32 resultId) + void SpirvExpressionStore::Store(ShaderAst::ExpressionPtr& node, UInt32 resultId) { - Visit(node); + node->Visit(*this); std::visit(overloaded { [&](const Pointer& pointer) { - m_writer.GetInstructions().Append(SpirvOp::OpStore, pointer.resultId, resultId); + m_block.Append(SpirvOp::OpStore, pointer.pointerId, resultId); }, [&](const LocalVar& value) { - m_writer.WriteLocalVariable(value.varName, resultId); + throw std::runtime_error("not yet implemented"); }, [](std::monostate) { @@ -36,68 +38,54 @@ namespace Nz }, m_value); } - void SpirvExpressionStore::Visit(ShaderNodes::AccessMember& node) + void SpirvExpressionStore::Visit(ShaderAst::AccessIndexExpression& node) { - Visit(node.structExpr); + node.expr->Visit(*this); + + const ShaderAst::ExpressionType& exprType = GetExpressionType(node); std::visit(overloaded { - [&](const Pointer& pointer) -> UInt32 + [&](const Pointer& pointer) { - UInt32 resultId = m_writer.AllocateResultId(); - UInt32 pointerType = m_writer.RegisterPointerType(node.exprType, pointer.storage); //< FIXME + UInt32 resultId = m_visitor.AllocateResultId(); + UInt32 pointerType = m_writer.RegisterPointerType(exprType, pointer.storage); //< FIXME - m_writer.GetInstructions().AppendVariadic(SpirvOp::OpAccessChain, [&](const auto& appender) + StackArray indexIds = NazaraStackArrayNoInit(UInt32, node.indices.size()); + for (std::size_t i = 0; i < node.indices.size(); ++i) + indexIds[i] = m_visitor.EvaluateExpression(node.indices[i]); + + m_block.AppendVariadic(SpirvOp::OpAccessChain, [&](const auto& appender) { appender(pointerType); appender(resultId); - appender(pointer.resultId); + appender(pointer.pointerId); - for (std::size_t index : node.memberIndices) - appender(m_writer.GetConstantId(Int32(index))); + for (UInt32 id : indexIds) + appender(id); }); - m_value = Pointer{ pointer.storage, resultId }; - - return resultId; + m_value = Pointer { pointer.storage, resultId }; }, - [](const LocalVar& value) -> UInt32 + [&](const LocalVar& value) { throw std::runtime_error("not yet implemented"); }, - [](std::monostate) -> UInt32 + [](std::monostate) { throw std::runtime_error("an internal error occurred"); } }, m_value); } - void SpirvExpressionStore::Visit(ShaderNodes::Identifier& node) - { - Visit(node.var); - } - - void SpirvExpressionStore::Visit(ShaderNodes::SwizzleOp& node) + void SpirvExpressionStore::Visit(ShaderAst::SwizzleExpression& node) { throw std::runtime_error("not yet implemented"); } - void SpirvExpressionStore::Visit(ShaderNodes::BuiltinVariable& var) + void SpirvExpressionStore::Visit(ShaderAst::VariableExpression& node) { - const auto& outputVar = m_writer.GetBuiltinVariable(var.entry); - - m_value = Pointer{ SpirvStorageClass::Output, outputVar.varId }; - } - - void SpirvExpressionStore::Visit(ShaderNodes::LocalVariable& var) - { - m_value = LocalVar{ var.name }; - } - - void SpirvExpressionStore::Visit(ShaderNodes::OutputVariable& var) - { - const auto& outputVar = m_writer.GetOutputVariable(var.name); - - m_value = Pointer{ SpirvStorageClass::Output, outputVar.varId }; + const auto& var = m_visitor.GetVariable(node.variableId); + m_value = Pointer{ var.storage, var.pointerId }; } } diff --git a/src/Nazara/Shader/SpirvPrinter.cpp b/src/Nazara/Shader/SpirvPrinter.cpp index 180a54d68..f8bbf4f18 100644 --- a/src/Nazara/Shader/SpirvPrinter.cpp +++ b/src/Nazara/Shader/SpirvPrinter.cpp @@ -4,9 +4,10 @@ #include #include +#include #include -#include #include +#include #include #include #include @@ -20,9 +21,7 @@ namespace Nz { } - const UInt32* codepoints; - std::size_t index = 0; - std::size_t count; + std::size_t resultOffset; std::ostringstream stream; const Settings& settings; }; @@ -30,218 +29,188 @@ namespace Nz std::string SpirvPrinter::Print(const UInt32* codepoints, std::size_t count, const Settings& settings) { State state(settings); - state.codepoints = codepoints; - state.count = count; m_currentState = &state; CallOnExit resetOnExit([&] { m_currentState = nullptr; }); - UInt32 magicNumber = ReadWord(); - if (magicNumber != SpvMagicNumber) - throw std::runtime_error("invalid Spir-V: magic number didn't match"); - - if (m_currentState->settings.printHeader) - m_currentState->stream << "Spir-V module\n"; - - UInt32 versionNumber = ReadWord(); - if (versionNumber > SpvVersion) - throw std::runtime_error("Spir-V is more recent than printer, dismissing"); - - UInt8 majorVersion = ((versionNumber) >> 16) & 0xFF; - UInt8 minorVersion = ((versionNumber) >> 8) & 0xFF; - - UInt32 generatorId = ReadWord(); - UInt32 bound = ReadWord(); - UInt32 schema = ReadWord(); - - if (m_currentState->settings.printHeader) - { - m_currentState->stream << "Version " + std::to_string(+majorVersion) << "." << std::to_string(+minorVersion) << "\n"; - m_currentState->stream << "Generator: " << std::to_string(generatorId) << "\n"; - m_currentState->stream << "Bound: " << std::to_string(bound) << "\n"; - m_currentState->stream << "Schema: " << std::to_string(schema) << "\n"; - } - - while (m_currentState->index < m_currentState->count) - AppendInstruction(); + Decode(codepoints, count); return m_currentState->stream.str(); } - void SpirvPrinter::AppendInstruction() + bool SpirvPrinter::HandleHeader(const SpirvHeader& header) { - std::size_t startIndex = m_currentState->index; + UInt8 majorVersion = ((header.versionNumber) >> 16) & 0xFF; + UInt8 minorVersion = ((header.versionNumber) >> 8) & 0xFF; - UInt32 firstWord = ReadWord(); + m_currentState->resultOffset = std::snprintf(nullptr, 0, "%%%u = ", header.bound); - UInt16 wordCount = static_cast((firstWord >> 16) & 0xFFFF); - UInt16 opcode = static_cast(firstWord & 0xFFFF); + if (m_currentState->settings.printHeader) + { + m_currentState->stream << "Version " + std::to_string(+majorVersion) << "." << std::to_string(+minorVersion) << "\n"; + m_currentState->stream << "Generator: " << std::to_string(header.generatorId) << "\n"; + m_currentState->stream << "Bound: " << std::to_string(header.bound) << "\n"; + m_currentState->stream << "Schema: " << std::to_string(header.schema) << "\n"; + } - const SpirvInstruction* inst = GetInstructionData(opcode); - if (!inst) - throw std::runtime_error("invalid instruction"); + return true; + } - m_currentState->stream << inst->name; + bool SpirvPrinter::HandleOpcode(const SpirvInstruction& instruction, UInt32 wordCount) + { + const UInt32* startPtr = GetCurrentPtr(); if (m_currentState->settings.printParameters) { + std::ostringstream instructionStream; + instructionStream << instruction.name; + + UInt32 resultId = 0; + std::size_t currentOperand = 0; - std::size_t instructionEnd = startIndex + wordCount; - while (m_currentState->index < instructionEnd) + const UInt32* endPtr = startPtr + wordCount - 1; + while (GetCurrentPtr() < endPtr) { - const SpirvInstruction::Operand* operand = &inst->operands[currentOperand]; + const SpirvInstruction::Operand* operand = &instruction.operands[currentOperand]; - m_currentState->stream << " " << operand->name << "("; - - switch (operand->kind) + if (operand->kind != SpirvOperandKind::IdResult) { - case SpirvOperandKind::ImageOperands: - case SpirvOperandKind::FPFastMathMode: - case SpirvOperandKind::SelectionControl: - case SpirvOperandKind::LoopControl: - case SpirvOperandKind::FunctionControl: - case SpirvOperandKind::MemorySemantics: - case SpirvOperandKind::MemoryAccess: - case SpirvOperandKind::KernelProfilingInfo: - case SpirvOperandKind::RayFlags: - case SpirvOperandKind::SourceLanguage: - case SpirvOperandKind::ExecutionModel: - case SpirvOperandKind::AddressingModel: - case SpirvOperandKind::MemoryModel: - case SpirvOperandKind::ExecutionMode: - case SpirvOperandKind::StorageClass: - case SpirvOperandKind::Dim: - case SpirvOperandKind::SamplerAddressingMode: - case SpirvOperandKind::SamplerFilterMode: - case SpirvOperandKind::ImageFormat: - case SpirvOperandKind::ImageChannelOrder: - case SpirvOperandKind::ImageChannelDataType: - case SpirvOperandKind::FPRoundingMode: - case SpirvOperandKind::LinkageType: - case SpirvOperandKind::AccessQualifier: - case SpirvOperandKind::FunctionParameterAttribute: - case SpirvOperandKind::Decoration: - case SpirvOperandKind::BuiltIn: - case SpirvOperandKind::Scope: - case SpirvOperandKind::GroupOperation: - case SpirvOperandKind::KernelEnqueueFlags: - case SpirvOperandKind::Capability: - case SpirvOperandKind::RayQueryIntersection: - case SpirvOperandKind::RayQueryCommittedIntersectionType: - case SpirvOperandKind::RayQueryCandidateIntersectionType: - case SpirvOperandKind::IdResultType: - case SpirvOperandKind::IdResult: - case SpirvOperandKind::IdMemorySemantics: - case SpirvOperandKind::IdScope: - case SpirvOperandKind::IdRef: - case SpirvOperandKind::LiteralInteger: - case SpirvOperandKind::LiteralExtInstInteger: - case SpirvOperandKind::LiteralSpecConstantOpInteger: - case SpirvOperandKind::LiteralContextDependentNumber: //< FIXME + switch (operand->kind) { - UInt32 value = ReadWord(); - m_currentState->stream << value; - break; - } - - case SpirvOperandKind::LiteralString: - { - std::string str = ReadString(); - m_currentState->stream << "\"" << str << "\""; - - /* - std::size_t offset = GetOutputOffset(); - - std::size_t size4 = CountWord(str); - for (std::size_t i = 0; i < size4; ++i) + case SpirvOperandKind::IdRef: + case SpirvOperandKind::IdResultType: + case SpirvOperandKind::IdMemorySemantics: + case SpirvOperandKind::IdScope: { - UInt32 codepoint = 0; - for (std::size_t j = 0; j < 4; ++j) - { - std::size_t pos = i * 4 + j; - if (pos < str.size()) - codepoint |= UInt32(str[pos]) << (j * 8); - } - - Append(codepoint); + UInt32 value = ReadWord(); + instructionStream << " %" << value; + break; } - */ - break; + + case SpirvOperandKind::ImageOperands: + case SpirvOperandKind::FPFastMathMode: + case SpirvOperandKind::SelectionControl: + case SpirvOperandKind::LoopControl: + case SpirvOperandKind::FunctionControl: + case SpirvOperandKind::MemorySemantics: + case SpirvOperandKind::MemoryAccess: + case SpirvOperandKind::KernelProfilingInfo: + case SpirvOperandKind::RayFlags: + case SpirvOperandKind::SourceLanguage: + case SpirvOperandKind::ExecutionModel: + case SpirvOperandKind::AddressingModel: + case SpirvOperandKind::MemoryModel: + case SpirvOperandKind::ExecutionMode: + case SpirvOperandKind::StorageClass: + case SpirvOperandKind::Dim: + case SpirvOperandKind::SamplerAddressingMode: + case SpirvOperandKind::SamplerFilterMode: + case SpirvOperandKind::ImageFormat: + case SpirvOperandKind::ImageChannelOrder: + case SpirvOperandKind::ImageChannelDataType: + case SpirvOperandKind::FPRoundingMode: + case SpirvOperandKind::LinkageType: + case SpirvOperandKind::AccessQualifier: + case SpirvOperandKind::FunctionParameterAttribute: + case SpirvOperandKind::Decoration: + case SpirvOperandKind::BuiltIn: + case SpirvOperandKind::Scope: + case SpirvOperandKind::GroupOperation: + case SpirvOperandKind::KernelEnqueueFlags: + case SpirvOperandKind::Capability: + case SpirvOperandKind::RayQueryIntersection: + case SpirvOperandKind::RayQueryCommittedIntersectionType: + case SpirvOperandKind::RayQueryCandidateIntersectionType: + case SpirvOperandKind::LiteralInteger: + case SpirvOperandKind::LiteralExtInstInteger: + case SpirvOperandKind::LiteralSpecConstantOpInteger: + case SpirvOperandKind::LiteralContextDependentNumber: //< FIXME + { + UInt32 value = ReadWord(); + instructionStream << " " << operand->name << "(" << value << ")"; + break; + } + + case SpirvOperandKind::LiteralString: + { + std::string str = ReadString(); + instructionStream << " \"" << str << "\""; + + /* + std::size_t offset = GetOutputOffset(); + + std::size_t size4 = CountWord(str); + for (std::size_t i = 0; i < size4; ++i) + { + UInt32 codepoint = 0; + for (std::size_t j = 0; j < 4; ++j) + { + std::size_t pos = i * 4 + j; + if (pos < str.size()) + codepoint |= UInt32(str[pos]) << (j * 8); + } + + Append(codepoint); + } + */ + break; + } + + + case SpirvOperandKind::PairLiteralIntegerIdRef: + { + ReadWord(); + ReadWord(); + break; + } + + case SpirvOperandKind::PairIdRefLiteralInteger: + { + ReadWord(); + ReadWord(); + break; + } + + case SpirvOperandKind::PairIdRefIdRef: + { + ReadWord(); + ReadWord(); + break; + } + + /*case SpirvOperandKind::LiteralContextDependentNumber: + { + throw std::runtime_error("not yet implemented"); + }*/ + + default: + break; } - - - case SpirvOperandKind::PairLiteralIntegerIdRef: - { - ReadWord(); - ReadWord(); - break; - } - - case SpirvOperandKind::PairIdRefLiteralInteger: - { - ReadWord(); - ReadWord(); - break; - } - - case SpirvOperandKind::PairIdRefIdRef: - { - ReadWord(); - ReadWord(); - break; - } - - /*case SpirvOperandKind::LiteralContextDependentNumber: - { - throw std::runtime_error("not yet implemented"); - }*/ - - default: - break; - } + else + resultId = ReadWord(); - m_currentState->stream << ")"; - - if (currentOperand < inst->minOperandCount - 1) + if (currentOperand < instruction.minOperandCount - 1) currentOperand++; } + + if (resultId != 0) + { + std::string resultInfo = "%" + std::to_string(resultId) + " = "; + m_currentState->stream << std::setw(m_currentState->resultOffset) << resultInfo; + } + else + m_currentState->stream << std::string(m_currentState->resultOffset, ' '); + + m_currentState->stream << instructionStream.str(); + + assert(GetCurrentPtr() == startPtr + wordCount - 1); } else - { - m_currentState->index += wordCount - 1; - if (m_currentState->index > m_currentState->count) - throw std::runtime_error("unexpected end of stream"); - } + m_currentState->stream << instruction.name; m_currentState->stream << "\n"; - assert(m_currentState->index == startIndex + wordCount); - } - - std::string SpirvPrinter::ReadString() - { - std::string str; - - for (;;) - { - UInt32 value = ReadWord(); - for (std::size_t j = 0; j < 4; ++j) - { - char c = static_cast((value >> (j * 8)) & 0xFF); - if (c == '\0') - return str; - - str.push_back(c); - } - } - } - - UInt32 SpirvPrinter::ReadWord() - { - if (m_currentState->index >= m_currentState->count) - throw std::runtime_error("unexpected end of stream"); - - return m_currentState->codepoints[m_currentState->index++]; + return true; } } diff --git a/src/Nazara/Shader/SpirvSection.cpp b/src/Nazara/Shader/SpirvSectionBase.cpp similarity index 85% rename from src/Nazara/Shader/SpirvSection.cpp rename to src/Nazara/Shader/SpirvSectionBase.cpp index c3d62ade3..9451e93db 100644 --- a/src/Nazara/Shader/SpirvSection.cpp +++ b/src/Nazara/Shader/SpirvSectionBase.cpp @@ -2,13 +2,13 @@ // This file is part of the "Nazara Engine - Shader generator" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include #include namespace Nz { - std::size_t SpirvSection::Append(const Raw& raw) + std::size_t SpirvSectionBase::AppendRaw(const Raw& raw) { std::size_t offset = GetOutputOffset(); @@ -30,7 +30,7 @@ namespace Nz codepoint |= UInt32(ptr[pos]) << (j * 8); } - Append(codepoint); + AppendRaw(codepoint); } return offset; diff --git a/src/Nazara/Shader/SpirvWriter.cpp b/src/Nazara/Shader/SpirvWriter.cpp index 45e1785b2..6c3387f0d 100644 --- a/src/Nazara/Shader/SpirvWriter.cpp +++ b/src/Nazara/Shader/SpirvWriter.cpp @@ -5,17 +5,20 @@ #include #include #include -#include -#include #include +#include #include #include #include +#include +#include +#include +#include #include #include -#include #include #include +#include #include #include #include @@ -25,134 +28,383 @@ namespace Nz { namespace { - class PreVisitor : public ShaderAstRecursiveVisitor, public ShaderVarVisitor + struct Builtin + { + const char* debugName; + ShaderStageTypeFlags compatibleStages; + SpirvBuiltIn decoration; + }; + + std::unordered_map s_builtinMapping = { + { ShaderAst::BuiltinEntry::FragCoord, { "FragmentCoordinates", ShaderStageType::Fragment, SpirvBuiltIn::FragCoord } }, + { ShaderAst::BuiltinEntry::FragDepth, { "FragmentDepth", ShaderStageType::Fragment, SpirvBuiltIn::FragDepth } }, + { ShaderAst::BuiltinEntry::VertexPosition, { "VertexPosition", ShaderStageType::Vertex, SpirvBuiltIn::Position } } + }; + + class PreVisitor : public ShaderAst::AstRecursiveVisitor { public: - using BuiltinContainer = std::unordered_set>; + struct UniformVar + { + std::optional bindingIndex; + UInt32 pointerId; + }; + + using BuiltinDecoration = std::map; + using LocationDecoration = std::map; using ExtInstList = std::unordered_set; - using LocalContainer = std::unordered_set>; - using ParameterContainer = std::unordered_set< std::shared_ptr>; + using ExtVarContainer = std::unordered_map; + using LocalContainer = std::unordered_set; + using FunctionContainer = std::vector>; + using StructContainer = std::vector; - PreVisitor(SpirvConstantCache& constantCache) : - m_constantCache(constantCache) + PreVisitor(const SpirvWriter::States& conditions, SpirvConstantCache& constantCache, std::vector& funcs) : + m_states(conditions), + m_constantCache(constantCache), + m_externalBlockIndex(0), + m_funcs(funcs) { + m_constantCache.SetStructCallback([this](std::size_t structIndex) -> const ShaderAst::StructDescription& + { + assert(structIndex < declaredStructs.size()); + return declaredStructs[structIndex]; + }); } - using ShaderAstRecursiveVisitor::Visit; - using ShaderVarVisitor::Visit; - - void Visit(ShaderNodes::AccessMember& node) override + void Visit(ShaderAst::AccessIndexExpression& node) override { - for (std::size_t index : node.memberIndices) - m_constantCache.Register(*SpirvConstantCache::BuildConstant(Int32(index))); + AstRecursiveVisitor::Visit(node); - ShaderAstRecursiveVisitor::Visit(node); + m_constantCache.Register(*m_constantCache.BuildType(node.cachedExpressionType.value())); } - void Visit(ShaderNodes::Constant& node) override + void Visit(ShaderAst::BinaryExpression& node) override + { + AstRecursiveVisitor::Visit(node); + + m_constantCache.Register(*m_constantCache.BuildType(node.cachedExpressionType.value())); + } + + void Visit(ShaderAst::ConditionalExpression& node) override + { + if (TestBit(m_states.enabledOptions, node.optionIndex)) + node.truePath->Visit(*this); + else + node.falsePath->Visit(*this); + + m_constantCache.Register(*m_constantCache.BuildType(node.cachedExpressionType.value())); + } + + void Visit(ShaderAst::ConditionalStatement& node) override + { + if (TestBit(m_states.enabledOptions, node.optionIndex)) + node.statement->Visit(*this); + } + + void Visit(ShaderAst::ConstantExpression& node) override { std::visit([&](auto&& arg) { - m_constantCache.Register(*SpirvConstantCache::BuildConstant(arg)); + m_constantCache.Register(*m_constantCache.BuildConstant(arg)); }, node.value); - ShaderAstRecursiveVisitor::Visit(node); + AstRecursiveVisitor::Visit(node); } - void Visit(ShaderNodes::DeclareVariable& node) override + void Visit(ShaderAst::DeclareExternalStatement& node) override { - Visit(node.variable); + assert(node.varIndex); + std::size_t varIndex = *node.varIndex; + for (auto& extVar : node.externalVars) + { + SpirvConstantCache::Variable variable; + variable.debugName = extVar.name; + variable.storageClass = (ShaderAst::IsSamplerType(extVar.type)) ? SpirvStorageClass::UniformConstant : SpirvStorageClass::Uniform; + variable.type = m_constantCache.BuildPointerType(extVar.type, variable.storageClass); - ShaderAstRecursiveVisitor::Visit(node); + UniformVar& uniformVar = extVars[varIndex++]; + uniformVar.pointerId = m_constantCache.Register(variable); + uniformVar.bindingIndex = extVar.bindingIndex; + } } - void Visit(ShaderNodes::Identifier& node) override + void Visit(ShaderAst::CallFunctionExpression& node) override { - Visit(node.var); + AstRecursiveVisitor::Visit(node); - ShaderAstRecursiveVisitor::Visit(node); + assert(m_funcIndex); + auto& func = m_funcs[*m_funcIndex]; + + auto& funcCall = func.funcCalls.emplace_back(); + funcCall.firstVarIndex = func.variables.size(); + + for (const auto& parameter : node.parameters) + { + auto& var = func.variables.emplace_back(); + var.typeId = m_constantCache.Register(*m_constantCache.BuildPointerType(GetExpressionType(*parameter), SpirvStorageClass::Function)); + } } - void Visit(ShaderNodes::IntrinsicCall& node) override + void Visit(ShaderAst::DeclareFunctionStatement& node) override { - ShaderAstRecursiveVisitor::Visit(node); + std::optional entryPointType = node.entryStage; + + assert(node.funcIndex); + std::size_t funcIndex = *node.funcIndex; + + if (funcIndex >= m_funcs.size()) + m_funcs.resize(funcIndex + 1); + + auto& funcData = m_funcs[funcIndex]; + funcData.name = node.name; + funcData.funcIndex = funcIndex; + + if (!entryPointType) + { + std::vector parameterTypes; + for (auto& parameter : node.parameters) + parameterTypes.push_back(parameter.type); + + funcData.returnTypeId = m_constantCache.Register(*m_constantCache.BuildType(node.returnType)); + funcData.funcTypeId = m_constantCache.Register(*m_constantCache.BuildFunctionType(node.returnType, parameterTypes)); + + for (auto& parameter : node.parameters) + { + auto& funcParam = funcData.parameters.emplace_back(); + funcParam.pointerTypeId = m_constantCache.Register(*m_constantCache.BuildPointerType(parameter.type, SpirvStorageClass::Function)); + funcParam.typeId = m_constantCache.Register(*m_constantCache.BuildType(parameter.type)); + } + } + else + { + using EntryPoint = SpirvAstVisitor::EntryPoint; + + std::vector executionModes; + + if (*entryPointType == ShaderStageType::Fragment) + { + executionModes.push_back(SpirvExecutionMode::OriginUpperLeft); + if (node.earlyFragmentTests && *node.earlyFragmentTests) + executionModes.push_back(SpirvExecutionMode::EarlyFragmentTests); + + if (node.depthWrite) + { + executionModes.push_back(SpirvExecutionMode::DepthReplacing); + + switch (*node.depthWrite) + { + case ShaderAst::DepthWriteMode::Replace: break; + case ShaderAst::DepthWriteMode::Greater: executionModes.push_back(SpirvExecutionMode::DepthGreater); break; + case ShaderAst::DepthWriteMode::Less: executionModes.push_back(SpirvExecutionMode::DepthLess); break; + case ShaderAst::DepthWriteMode::Unchanged: executionModes.push_back(SpirvExecutionMode::DepthUnchanged); break; + } + } + } + + funcData.returnTypeId = m_constantCache.Register(*m_constantCache.BuildType(ShaderAst::NoType{})); + funcData.funcTypeId = m_constantCache.Register(*m_constantCache.BuildFunctionType(ShaderAst::NoType{}, {})); + + std::optional inputStruct; + std::vector inputs; + if (!node.parameters.empty()) + { + assert(node.parameters.size() == 1); + auto& parameter = node.parameters.front(); + assert(std::holds_alternative(parameter.type)); + + std::size_t structIndex = std::get(parameter.type).structIndex; + const ShaderAst::StructDescription& structDesc = declaredStructs[structIndex]; + + std::size_t memberIndex = 0; + for (const auto& member : structDesc.members) + { + if (UInt32 varId = HandleEntryInOutType(*entryPointType, funcIndex, member, SpirvStorageClass::Input); varId != 0) + { + inputs.push_back({ + m_constantCache.Register(*m_constantCache.BuildConstant(Int32(memberIndex))), + m_constantCache.Register(*m_constantCache.BuildPointerType(member.type, SpirvStorageClass::Function)), + varId + }); + } + + memberIndex++; + } + + inputStruct = EntryPoint::InputStruct{ + m_constantCache.Register(*m_constantCache.BuildPointerType(parameter.type, SpirvStorageClass::Function)), + m_constantCache.Register(*m_constantCache.BuildType(parameter.type)) + }; + } + + std::optional outputStructId; + std::vector outputs; + if (!IsNoType(node.returnType)) + { + assert(std::holds_alternative(node.returnType)); + + std::size_t structIndex = std::get(node.returnType).structIndex; + const ShaderAst::StructDescription& structDesc = declaredStructs[structIndex]; + + std::size_t memberIndex = 0; + for (const auto& member : structDesc.members) + { + if (UInt32 varId = HandleEntryInOutType(*entryPointType, funcIndex, member, SpirvStorageClass::Output); varId != 0) + { + outputs.push_back({ + Int32(memberIndex), + m_constantCache.Register(*m_constantCache.BuildType(member.type)), + varId + }); + } + + memberIndex++; + } + + outputStructId = m_constantCache.Register(*m_constantCache.BuildType(node.returnType)); + } + + funcData.entryPointData = EntryPoint{ + *entryPointType, + inputStruct, + outputStructId, + std::move(inputs), + std::move(outputs), + std::move(executionModes) + }; + } + + m_funcIndex = funcIndex; + AstRecursiveVisitor::Visit(node); + m_funcIndex.reset(); + } + + void Visit(ShaderAst::DeclareStructStatement& node) override + { + AstRecursiveVisitor::Visit(node); + + assert(node.structIndex); + std::size_t structIndex = *node.structIndex; + if (structIndex >= declaredStructs.size()) + declaredStructs.resize(structIndex + 1); + + declaredStructs[structIndex] = node.description; + + m_constantCache.Register(*m_constantCache.BuildType(node.description)); + } + + void Visit(ShaderAst::DeclareVariableStatement& node) override + { + AstRecursiveVisitor::Visit(node); + + assert(m_funcIndex); + auto& func = m_funcs[*m_funcIndex]; + + assert(node.varIndex); + func.varIndexToVarId[*node.varIndex] = func.variables.size(); + + auto& var = func.variables.emplace_back(); + var.typeId = m_constantCache.Register(*m_constantCache.BuildPointerType(node.varType, SpirvStorageClass::Function)); + } + + void Visit(ShaderAst::IdentifierExpression& node) override + { + m_constantCache.Register(*m_constantCache.BuildType(node.cachedExpressionType.value())); + + AstRecursiveVisitor::Visit(node); + } + + void Visit(ShaderAst::IntrinsicExpression& node) override + { + AstRecursiveVisitor::Visit(node); switch (node.intrinsic) { // Require GLSL.std.450 - case ShaderNodes::IntrinsicType::CrossProduct: + case ShaderAst::IntrinsicType::CrossProduct: + case ShaderAst::IntrinsicType::Length: + case ShaderAst::IntrinsicType::Max: + case ShaderAst::IntrinsicType::Min: + case ShaderAst::IntrinsicType::Pow: extInsts.emplace("GLSL.std.450"); break; // Part of SPIR-V core - case ShaderNodes::IntrinsicType::DotProduct: + case ShaderAst::IntrinsicType::DotProduct: + case ShaderAst::IntrinsicType::SampleTexture: break; } + + m_constantCache.Register(*m_constantCache.BuildType(node.cachedExpressionType.value())); } - void Visit(ShaderNodes::BuiltinVariable& var) override + void Visit(ShaderAst::SwizzleExpression& node) override { - builtinVars.insert(std::static_pointer_cast(var.shared_from_this())); + AstRecursiveVisitor::Visit(node); + + m_constantCache.Register(*m_constantCache.BuildType(node.cachedExpressionType.value())); } - void Visit(ShaderNodes::InputVariable& /*var*/) override + void Visit(ShaderAst::UnaryExpression& node) override { - /* Handled by ShaderAst */ + AstRecursiveVisitor::Visit(node); + + m_constantCache.Register(*m_constantCache.BuildType(node.cachedExpressionType.value())); } - void Visit(ShaderNodes::LocalVariable& var) override + UInt32 HandleEntryInOutType(ShaderStageType entryPointType, std::size_t funcIndex, const ShaderAst::StructDescription::StructMember& member, SpirvStorageClass storageClass) { - localVars.insert(std::static_pointer_cast(var.shared_from_this())); + if (member.builtin) + { + auto it = s_builtinMapping.find(*member.builtin); + assert(it != s_builtinMapping.end()); + + Builtin& builtin = it->second; + if ((builtin.compatibleStages & entryPointType) == 0) + return 0; + + SpirvBuiltIn builtinDecoration = builtin.decoration; + + SpirvConstantCache::Variable variable; + variable.debugName = builtin.debugName; + variable.funcId = funcIndex; + variable.storageClass = storageClass; + variable.type = m_constantCache.BuildPointerType(member.type, storageClass); + + UInt32 varId = m_constantCache.Register(variable); + builtinDecorations[varId] = builtinDecoration; + + return varId; + } + else if (member.locationIndex) + { + SpirvConstantCache::Variable variable; + variable.debugName = member.name; + variable.funcId = funcIndex; + variable.storageClass = storageClass; + variable.type = m_constantCache.BuildPointerType(member.type, storageClass); + + UInt32 varId = m_constantCache.Register(variable); + locationDecorations[varId] = *member.locationIndex; + + return varId; + } + + return 0; } - void Visit(ShaderNodes::OutputVariable& /*var*/) override - { - /* Handled by ShaderAst */ - } - - void Visit(ShaderNodes::ParameterVariable& var) override - { - paramVars.insert(std::static_pointer_cast(var.shared_from_this())); - } - - void Visit(ShaderNodes::UniformVariable& /*var*/) override - { - /* Handled by ShaderAst */ - } - - BuiltinContainer builtinVars; + BuiltinDecoration builtinDecorations; ExtInstList extInsts; - LocalContainer localVars; - ParameterContainer paramVars; + ExtVarContainer extVars; + LocationDecoration locationDecorations; + StructContainer declaredStructs; private: + const SpirvWriter::States& m_states; SpirvConstantCache& m_constantCache; + std::optional m_funcIndex; + std::size_t m_externalBlockIndex; + std::vector& m_funcs; }; - - template - constexpr ShaderNodes::BasicType GetBasicType() - { - if constexpr (std::is_same_v) - return ShaderNodes::BasicType::Boolean; - else if constexpr (std::is_same_v) - return(ShaderNodes::BasicType::Float1); - else if constexpr (std::is_same_v) - return(ShaderNodes::BasicType::Int1); - else if constexpr (std::is_same_v) - return(ShaderNodes::BasicType::Float2); - else if constexpr (std::is_same_v) - return(ShaderNodes::BasicType::Float3); - else if constexpr (std::is_same_v) - return(ShaderNodes::BasicType::Float4); - else if constexpr (std::is_same_v) - return(ShaderNodes::BasicType::Int2); - else if constexpr (std::is_same_v) - return(ShaderNodes::BasicType::Int3); - else if constexpr (std::is_same_v) - return(ShaderNodes::BasicType::Int4); - else - static_assert(AlwaysFalse::value, "unhandled type"); - } } struct SpirvWriter::State @@ -164,21 +416,18 @@ namespace Nz struct Func { + const ShaderAst::DeclareFunctionStatement* statement = nullptr; UInt32 typeId; UInt32 id; - std::vector paramsId; }; - tsl::ordered_map inputIds; - tsl::ordered_map outputIds; - tsl::ordered_map uniformIds; - std::unordered_map extensionInstructions; - std::unordered_map builtinIds; + std::unordered_map extensionInstructionSet; std::unordered_map varToResult; - std::vector funcs; + std::vector funcs; std::vector resultIds; UInt32 nextVarIndex = 1; SpirvConstantCache constantTypeCache; //< init after nextVarIndex + PreVisitor* preVisitor; // Output SpirvSection header; @@ -193,13 +442,27 @@ namespace Nz { } - std::vector SpirvWriter::Generate(const ShaderAst& shader) + std::vector SpirvWriter::Generate(ShaderAst::StatementPtr& shader, const States& states) { - std::string error; - if (!ValidateShader(shader, &error)) - throw std::runtime_error("Invalid shader AST: " + error); + ShaderAst::StatementPtr* targetAstPtr = &shader; - m_context.shader = &shader; + ShaderAst::StatementPtr sanitizedAst; + if (!states.sanitized) + { + sanitizedAst = ShaderAst::Sanitize(shader); + targetAstPtr = &sanitizedAst; + } + + ShaderAst::StatementPtr optimizedAst; + if (states.optimize) + { + optimizedAst = ShaderAst::Optimize(*targetAstPtr); + targetAstPtr = &optimizedAst; + } + + ShaderAst::StatementPtr& targetAst = *targetAstPtr; + + m_context.states = &states; State state; m_currentState = &state; @@ -208,239 +471,47 @@ namespace Nz m_currentState = nullptr; }); - std::vector functionStatements; - - ShaderAstCloner cloner; - - PreVisitor preVisitor(state.constantTypeCache); - for (const auto& func : shader.GetFunctions()) - { - functionStatements.emplace_back(cloner.Clone(func.statement)); - preVisitor.Visit(func.statement); - } - // Register all extended instruction sets + PreVisitor preVisitor(states, state.constantTypeCache, state.funcs); + targetAst->Visit(preVisitor); + + m_currentState->preVisitor = &preVisitor; + for (const std::string& extInst : preVisitor.extInsts) - state.extensionInstructions[extInst] = AllocateResultId(); + state.extensionInstructionSet[extInst] = AllocateResultId(); - // Register all types - for (const auto& func : shader.GetFunctions()) - { - RegisterType(func.returnType); - for (const auto& param : func.parameters) - RegisterType(param.type); - } + // Assign function ID (required for forward declaration) + for (auto& func : state.funcs) + func.funcId = AllocateResultId(); - for (const auto& input : shader.GetInputs()) - RegisterPointerType(input.type, SpirvStorageClass::Input); - - for (const auto& output : shader.GetOutputs()) - RegisterPointerType(output.type, SpirvStorageClass::Output); - - for (const auto& uniform : shader.GetUniforms()) - RegisterPointerType(uniform.type, (IsSamplerType(uniform.type)) ? SpirvStorageClass::UniformConstant : SpirvStorageClass::Uniform); - - for (const auto& func : shader.GetFunctions()) - RegisterFunctionType(func.returnType, func.parameters); - - for (const auto& local : preVisitor.localVars) - RegisterType(local->type); - - for (const auto& builtin : preVisitor.builtinVars) - RegisterType(builtin->type); - - // Register result id and debug infos for global variables/functions - for (const auto& builtin : preVisitor.builtinVars) - { - SpirvConstantCache::Variable variable; - SpirvBuiltIn builtinDecoration; - switch (builtin->entry) - { - case ShaderNodes::BuiltinEntry::VertexPosition: - variable.debugName = "builtin_VertexPosition"; - variable.storageClass = SpirvStorageClass::Output; - - builtinDecoration = SpirvBuiltIn::Position; - break; - - default: - throw std::runtime_error("unexpected builtin type"); - } - - const ShaderExpressionType& builtinExprType = builtin->type; - assert(IsBasicType(builtinExprType)); - - ShaderNodes::BasicType builtinType = std::get(builtinExprType); - - variable.type = SpirvConstantCache::BuildPointerType(builtinType, variable.storageClass); - - UInt32 varId = m_currentState->constantTypeCache.Register(variable); - - ExtVar builtinData; - builtinData.pointerTypeId = GetPointerTypeId(builtinType, variable.storageClass); - builtinData.typeId = GetTypeId(builtinType); - builtinData.varId = varId; - - state.annotations.Append(SpirvOp::OpDecorate, builtinData.varId, SpvDecorationBuiltIn, builtinDecoration); - - state.builtinIds.emplace(builtin->entry, builtinData); - } - - for (const auto& input : shader.GetInputs()) - { - SpirvConstantCache::Variable variable; - variable.debugName = input.name; - variable.storageClass = SpirvStorageClass::Input; - variable.type = SpirvConstantCache::BuildPointerType(shader, input.type, variable.storageClass); - - UInt32 varId = m_currentState->constantTypeCache.Register(variable); - - ExtVar inputData; - inputData.pointerTypeId = GetPointerTypeId(input.type, variable.storageClass); - inputData.typeId = GetTypeId(input.type); - inputData.varId = varId; - - state.inputIds.emplace(input.name, std::move(inputData)); - - if (input.locationIndex) - state.annotations.Append(SpirvOp::OpDecorate, varId, SpvDecorationLocation, *input.locationIndex); - } - - for (const auto& output : shader.GetOutputs()) - { - SpirvConstantCache::Variable variable; - variable.debugName = output.name; - variable.storageClass = SpirvStorageClass::Output; - variable.type = SpirvConstantCache::BuildPointerType(shader, output.type, variable.storageClass); - - UInt32 varId = m_currentState->constantTypeCache.Register(variable); - - ExtVar outputData; - outputData.pointerTypeId = GetPointerTypeId(output.type, variable.storageClass); - outputData.typeId = GetTypeId(output.type); - outputData.varId = varId; - - state.outputIds.emplace(output.name, std::move(outputData)); - - if (output.locationIndex) - state.annotations.Append(SpirvOp::OpDecorate, varId, SpvDecorationLocation, *output.locationIndex); - } - - for (const auto& uniform : shader.GetUniforms()) - { - SpirvConstantCache::Variable variable; - variable.debugName = uniform.name; - variable.storageClass = (IsSamplerType(uniform.type)) ? SpirvStorageClass::UniformConstant : SpirvStorageClass::Uniform; - variable.type = SpirvConstantCache::BuildPointerType(shader, uniform.type, variable.storageClass); - - UInt32 varId = m_currentState->constantTypeCache.Register(variable); - - ExtVar uniformData; - uniformData.pointerTypeId = GetPointerTypeId(uniform.type, variable.storageClass); - uniformData.typeId = GetTypeId(uniform.type); - uniformData.varId = varId; - - state.uniformIds.emplace(uniform.name, std::move(uniformData)); - - if (uniform.bindingIndex) - { - state.annotations.Append(SpirvOp::OpDecorate, varId, SpvDecorationBinding, *uniform.bindingIndex); - state.annotations.Append(SpirvOp::OpDecorate, varId, SpvDecorationDescriptorSet, 0); - } - } - - for (const auto& func : shader.GetFunctions()) - { - auto& funcData = state.funcs.emplace_back(); - funcData.id = AllocateResultId(); - funcData.typeId = GetFunctionTypeId(func.returnType, func.parameters); - - state.debugInfo.Append(SpirvOp::OpName, funcData.id, func.name); - } - - std::size_t entryPointIndex = std::numeric_limits::max(); - - for (std::size_t funcIndex = 0; funcIndex < shader.GetFunctionCount(); ++funcIndex) - { - const auto& func = shader.GetFunction(funcIndex); - if (func.name == "main") - entryPointIndex = funcIndex; - - auto& funcData = state.funcs[funcIndex]; - - state.instructions.Append(SpirvOp::OpFunction, GetTypeId(func.returnType), funcData.id, 0, funcData.typeId); - - state.instructions.Append(SpirvOp::OpLabel, AllocateResultId()); - - for (const auto& param : func.parameters) - { - UInt32 paramResultId = AllocateResultId(); - funcData.paramsId.push_back(paramResultId); - - state.instructions.Append(SpirvOp::OpFunctionParameter, GetTypeId(param.type), paramResultId); - } - - SpirvAstVisitor visitor(*this); - visitor.Visit(functionStatements[funcIndex]); - - if (func.returnType == ShaderNodes::BasicType::Void) - state.instructions.Append(SpirvOp::OpReturn); - - state.instructions.Append(SpirvOp::OpFunctionEnd); - } - - assert(entryPointIndex != std::numeric_limits::max()); - - m_currentState->constantTypeCache.Write(m_currentState->annotations, m_currentState->constants, m_currentState->debugInfo); + SpirvAstVisitor visitor(*this, state.instructions, state.funcs); + targetAst->Visit(visitor); AppendHeader(); - SpvExecutionModel execModel; - const auto& entryFuncData = shader.GetFunction(entryPointIndex); - const auto& entryFunc = state.funcs[entryPointIndex]; - - assert(m_context.shader); - switch (m_context.shader->GetStage()) + for (auto&& [varIndex, extVar] : preVisitor.extVars) { - case ShaderStageType::Fragment: - execModel = SpvExecutionModelFragment; - break; - - case ShaderStageType::Vertex: - execModel = SpvExecutionModelVertex; - break; - - default: - throw std::runtime_error("not yet implemented"); + if (extVar.bindingIndex) + { + state.annotations.Append(SpirvOp::OpDecorate, extVar.pointerId, SpirvDecoration::Binding, *extVar.bindingIndex); + state.annotations.Append(SpirvOp::OpDecorate, extVar.pointerId, SpirvDecoration::DescriptorSet, 0); + } } - // OpEntryPoint Vertex %main "main" %outNormal %inNormals %outTexCoords %inTexCoord %_ %inPos + for (auto&& [varId, builtin] : preVisitor.builtinDecorations) + state.annotations.Append(SpirvOp::OpDecorate, varId, SpirvDecoration::BuiltIn, builtin); - state.header.AppendVariadic(SpirvOp::OpEntryPoint, [&](const auto& appender) - { - appender(execModel); - appender(entryFunc.id); - appender(entryFuncData.name); + for (auto&& [varId, location] : preVisitor.locationDecorations) + state.annotations.Append(SpirvOp::OpDecorate, varId, SpirvDecoration::Location, location); - for (const auto& [name, varData] : state.builtinIds) - appender(varData.varId); - - for (const auto& [name, varData] : state.inputIds) - appender(varData.varId); - - for (const auto& [name, varData] : state.outputIds) - appender(varData.varId); - }); - - if (m_context.shader->GetStage() == ShaderStageType::Fragment) - state.header.Append(SpirvOp::OpExecutionMode, entryFunc.id, SpvExecutionModeOriginUpperLeft); + m_currentState->constantTypeCache.Write(m_currentState->annotations, m_currentState->constants, m_currentState->debugInfo); std::vector ret; - MergeBlocks(ret, state.header); - MergeBlocks(ret, state.debugInfo); - MergeBlocks(ret, state.annotations); - MergeBlocks(ret, state.constants); - MergeBlocks(ret, state.instructions); + MergeSections(ret, state.header); + MergeSections(ret, state.debugInfo); + MergeSections(ret, state.annotations); + MergeSections(ret, state.constants); + MergeSections(ret, state.instructions); return ret; } @@ -450,207 +521,153 @@ namespace Nz m_environment = std::move(environment); } - UInt32 Nz::SpirvWriter::AllocateResultId() + UInt32 SpirvWriter::AllocateResultId() { return m_currentState->nextVarIndex++; } void SpirvWriter::AppendHeader() { - m_currentState->header.Append(SpvMagicNumber); //< Spir-V magic number + m_currentState->header.AppendRaw(SpirvMagicNumber); //< Spir-V magic number UInt32 version = (m_environment.spvMajorVersion << 16) | m_environment.spvMinorVersion << 8; - m_currentState->header.Append(version); //< Spir-V version number (1.0 for compatibility) - m_currentState->header.Append(0); //< Generator identifier (TODO: Register generator to Khronos) + m_currentState->header.AppendRaw(version); //< Spir-V version number (1.0 for compatibility) + m_currentState->header.AppendRaw(0); //< Generator identifier (TODO: Register generator to Khronos) - m_currentState->header.Append(m_currentState->nextVarIndex); //< Bound (ID count) - m_currentState->header.Append(0); //< Instruction schema (required to be 0 for now) + m_currentState->header.AppendRaw(m_currentState->nextVarIndex); //< Bound (ID count) + m_currentState->header.AppendRaw(0); //< Instruction schema (required to be 0 for now) - m_currentState->header.Append(SpirvOp::OpCapability, SpvCapabilityShader); + m_currentState->header.Append(SpirvOp::OpCapability, SpirvCapability::Shader); - for (const auto& [extInst, resultId] : m_currentState->extensionInstructions) + for (const auto& [extInst, resultId] : m_currentState->extensionInstructionSet) m_currentState->header.Append(SpirvOp::OpExtInstImport, resultId, extInst); - m_currentState->header.Append(SpirvOp::OpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450); - } + m_currentState->header.Append(SpirvOp::OpMemoryModel, SpirvAddressingModel::Logical, SpirvMemoryModel::GLSL450); - UInt32 SpirvWriter::GetConstantId(const ShaderConstantValue& value) const - { - return m_currentState->constantTypeCache.GetId(*SpirvConstantCache::BuildConstant(value)); - } - - UInt32 SpirvWriter::GetFunctionTypeId(ShaderExpressionType retType, const std::vector& parameters) - { - std::vector parameterTypes; - parameterTypes.reserve(parameters.size()); - - for (const auto& parameter : parameters) - parameterTypes.push_back(SpirvConstantCache::BuildType(*m_context.shader, parameter.type)); - - return m_currentState->constantTypeCache.GetId({ - SpirvConstantCache::Function { - SpirvConstantCache::BuildType(*m_context.shader, retType), - std::move(parameterTypes) - } - }); - } - - auto SpirvWriter::GetBuiltinVariable(ShaderNodes::BuiltinEntry builtin) const -> const ExtVar& - { - auto it = m_currentState->builtinIds.find(builtin); - assert(it != m_currentState->builtinIds.end()); - - return it->second; - } - - auto SpirvWriter::GetInputVariable(const std::string& name) const -> const ExtVar& - { - auto it = m_currentState->inputIds.find(name); - assert(it != m_currentState->inputIds.end()); - - return it->second; - } - - auto SpirvWriter::GetOutputVariable(const std::string& name) const -> const ExtVar& - { - auto it = m_currentState->outputIds.find(name); - assert(it != m_currentState->outputIds.end()); - - return it->second; - } - - auto SpirvWriter::GetUniformVariable(const std::string& name) const -> const ExtVar& - { - auto it = m_currentState->uniformIds.find(name); - assert(it != m_currentState->uniformIds.end()); - - return it.value(); - } - - SpirvSection& SpirvWriter::GetInstructions() - { - return m_currentState->instructions; - } - - UInt32 SpirvWriter::GetPointerTypeId(const ShaderExpressionType& type, SpirvStorageClass storageClass) const - { - return m_currentState->constantTypeCache.GetId(*SpirvConstantCache::BuildPointerType(*m_context.shader, type, storageClass)); - } - - UInt32 SpirvWriter::GetTypeId(const ShaderExpressionType& type) const - { - return m_currentState->constantTypeCache.GetId(*SpirvConstantCache::BuildType(*m_context.shader, type)); - } - - UInt32 SpirvWriter::ReadInputVariable(const std::string& name) - { - auto it = m_currentState->inputIds.find(name); - assert(it != m_currentState->inputIds.end()); - - return ReadVariable(it.value()); - } - - std::optional SpirvWriter::ReadInputVariable(const std::string& name, OnlyCache) - { - auto it = m_currentState->inputIds.find(name); - assert(it != m_currentState->inputIds.end()); - - return ReadVariable(it.value(), OnlyCache{}); - } - - UInt32 SpirvWriter::ReadLocalVariable(const std::string& name) - { - auto it = m_currentState->varToResult.find(name); - assert(it != m_currentState->varToResult.end()); - - return it->second; - } - - std::optional SpirvWriter::ReadLocalVariable(const std::string& name, OnlyCache) - { - auto it = m_currentState->varToResult.find(name); - if (it == m_currentState->varToResult.end()) - return {}; - - return it->second; - } - - UInt32 SpirvWriter::ReadUniformVariable(const std::string& name) - { - auto it = m_currentState->uniformIds.find(name); - assert(it != m_currentState->uniformIds.end()); - - return ReadVariable(it.value()); - } - - std::optional SpirvWriter::ReadUniformVariable(const std::string& name, OnlyCache) - { - auto it = m_currentState->uniformIds.find(name); - assert(it != m_currentState->uniformIds.end()); - - return ReadVariable(it.value(), OnlyCache{}); - } - - UInt32 SpirvWriter::ReadVariable(ExtVar& var) - { - if (!var.valueId.has_value()) + for (auto& func : m_currentState->funcs) { - UInt32 resultId = AllocateResultId(); - m_currentState->instructions.Append(SpirvOp::OpLoad, var.typeId, resultId, var.varId); + m_currentState->debugInfo.Append(SpirvOp::OpName, func.funcId, func.name); - var.valueId = resultId; + if (func.entryPointData) + { + auto& entryPointData = func.entryPointData.value(); + + SpirvExecutionModel execModel; + + switch (entryPointData.stageType) + { + case ShaderStageType::Fragment: + execModel = SpirvExecutionModel::Fragment; + break; + + case ShaderStageType::Vertex: + execModel = SpirvExecutionModel::Vertex; + break; + + default: + throw std::runtime_error("not yet implemented"); + } + + m_currentState->header.AppendVariadic(SpirvOp::OpEntryPoint, [&](const auto& appender) + { + appender(execModel); + appender(func.funcId); + appender(func.name); + + for (const auto& input : entryPointData.inputs) + appender(input.varId); + + for (const auto& output : entryPointData.outputs) + appender(output.varId); + }); + } } - return var.valueId.value(); - } - - std::optional SpirvWriter::ReadVariable(const ExtVar& var, OnlyCache) - { - if (!var.valueId.has_value()) - return {}; - - return var.valueId.value(); - } - - UInt32 SpirvWriter::RegisterConstant(const ShaderConstantValue& value) - { - return m_currentState->constantTypeCache.Register(*SpirvConstantCache::BuildConstant(value)); - } - - UInt32 SpirvWriter::RegisterFunctionType(ShaderExpressionType retType, const std::vector& parameters) - { - std::vector parameterTypes; - parameterTypes.reserve(parameters.size()); - - for (const auto& parameter : parameters) - parameterTypes.push_back(SpirvConstantCache::BuildType(*m_context.shader, parameter.type)); - - return m_currentState->constantTypeCache.Register({ - SpirvConstantCache::Function { - SpirvConstantCache::BuildType(*m_context.shader, retType), - std::move(parameterTypes) + // Write execution modes + for (auto& func : m_currentState->funcs) + { + if (func.entryPointData) + { + for (SpirvExecutionMode executionMode : func.entryPointData->executionModes) + m_currentState->header.Append(SpirvOp::OpExecutionMode, func.funcId, executionMode); } - }); + } } - UInt32 SpirvWriter::RegisterPointerType(ShaderExpressionType type, SpirvStorageClass storageClass) + SpirvConstantCache::TypePtr SpirvWriter::BuildFunctionType(const ShaderAst::DeclareFunctionStatement& functionNode) { - return m_currentState->constantTypeCache.Register(*SpirvConstantCache::BuildPointerType(*m_context.shader, type, storageClass)); + std::vector parameterTypes; + parameterTypes.reserve(functionNode.parameters.size()); + + for (const auto& parameter : functionNode.parameters) + parameterTypes.push_back(parameter.type); + + return m_currentState->constantTypeCache.BuildFunctionType(functionNode.returnType, parameterTypes); } - UInt32 SpirvWriter::RegisterType(ShaderExpressionType type) + UInt32 SpirvWriter::GetConstantId(const ShaderAst::ConstantValue& value) const + { + return m_currentState->constantTypeCache.GetId(*m_currentState->constantTypeCache.BuildConstant(value)); + } + + UInt32 SpirvWriter::GetExtendedInstructionSet(const std::string& instructionSetName) const + { + auto it = m_currentState->extensionInstructionSet.find(instructionSetName); + assert(it != m_currentState->extensionInstructionSet.end()); + + return it->second; + } + + UInt32 SpirvWriter::GetExtVarPointerId(std::size_t extVarIndex) const + { + auto it = m_currentState->preVisitor->extVars.find(extVarIndex); + assert(it != m_currentState->preVisitor->extVars.end()); + + return it->second.pointerId; + } + + UInt32 SpirvWriter::GetFunctionTypeId(const ShaderAst::DeclareFunctionStatement& functionNode) + { + return m_currentState->constantTypeCache.GetId({ *BuildFunctionType(functionNode) }); + } + + UInt32 SpirvWriter::GetPointerTypeId(const ShaderAst::ExpressionType& type, SpirvStorageClass storageClass) const + { + return m_currentState->constantTypeCache.GetId(*m_currentState->constantTypeCache.BuildPointerType(type, storageClass)); + } + + UInt32 SpirvWriter::GetTypeId(const ShaderAst::ExpressionType& type) const + { + return m_currentState->constantTypeCache.GetId(*m_currentState->constantTypeCache.BuildType(type)); + } + + bool SpirvWriter::IsOptionEnabled(std::size_t optionIndex) const + { + return TestBit(m_context.states->enabledOptions, optionIndex); + } + + UInt32 SpirvWriter::RegisterConstant(const ShaderAst::ConstantValue& value) + { + return m_currentState->constantTypeCache.Register(*m_currentState->constantTypeCache.BuildConstant(value)); + } + + UInt32 SpirvWriter::RegisterFunctionType(const ShaderAst::DeclareFunctionStatement& functionNode) + { + return m_currentState->constantTypeCache.Register({ *BuildFunctionType(functionNode) }); + } + + UInt32 SpirvWriter::RegisterPointerType(ShaderAst::ExpressionType type, SpirvStorageClass storageClass) + { + return m_currentState->constantTypeCache.Register(*m_currentState->constantTypeCache.BuildPointerType(type, storageClass)); + } + + UInt32 SpirvWriter::RegisterType(ShaderAst::ExpressionType type) { assert(m_currentState); - return m_currentState->constantTypeCache.Register(*SpirvConstantCache::BuildType(*m_context.shader, type)); + return m_currentState->constantTypeCache.Register(*m_currentState->constantTypeCache.BuildType(type)); } - void SpirvWriter::WriteLocalVariable(std::string name, UInt32 resultId) - { - assert(m_currentState); - m_currentState->varToResult.insert_or_assign(std::move(name), resultId); - } - - void SpirvWriter::MergeBlocks(std::vector& output, const SpirvSection& from) + void SpirvWriter::MergeSections(std::vector& output, const SpirvSection& from) { const std::vector& bytecode = from.GetBytecode(); diff --git a/src/Nazara/Utility/AbstractImage.cpp b/src/Nazara/Utility/AbstractImage.cpp index 72a0f7335..1004aa4e1 100644 --- a/src/Nazara/Utility/AbstractImage.cpp +++ b/src/Nazara/Utility/AbstractImage.cpp @@ -22,6 +22,6 @@ namespace Nz bool AbstractImage::IsCubemap() const { - return GetType() == ImageType_Cubemap; + return GetType() == ImageType::Cubemap; } } diff --git a/src/Nazara/Utility/Animation.cpp b/src/Nazara/Utility/Animation.cpp index 635c96694..e51170d33 100644 --- a/src/Nazara/Utility/Animation.cpp +++ b/src/Nazara/Utility/Animation.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -36,19 +37,16 @@ namespace Nz return true; } - Animation::~Animation() - { - OnAnimationRelease(this); - - Destroy(); - } + Animation::Animation() = default; + Animation::Animation(Animation&&) noexcept = default; + Animation::~Animation() = default; bool Animation::AddSequence(const Sequence& sequence) { NazaraAssert(m_impl, "Animation not created"); NazaraAssert(sequence.frameCount > 0, "Sequence frame count must be over zero"); - if (m_impl->type == AnimationType_Skeletal) + if (m_impl->type == AnimationType::Skeletal) { std::size_t endFrame = sequence.firstFrame + sequence.frameCount - 1; if (endFrame >= m_impl->frameCount) @@ -80,7 +78,7 @@ namespace Nz void Animation::AnimateSkeleton(Skeleton* targetSkeleton, std::size_t frameA, std::size_t frameB, float interpolation) const { NazaraAssert(m_impl, "Animation not created"); - NazaraAssert(m_impl->type == AnimationType_Skeletal, "Animation is not skeletal"); + NazaraAssert(m_impl->type == AnimationType::Skeletal, "Animation is not skeletal"); NazaraAssert(targetSkeleton && targetSkeleton->IsValid(), "Invalid skeleton"); NazaraAssert(targetSkeleton->GetJointCount() == m_impl->jointCount, "Skeleton joint does not match animation joint count"); NazaraAssert(frameA < m_impl->frameCount, "FrameA is out of range"); @@ -106,24 +104,18 @@ namespace Nz Destroy(); - m_impl = new AnimationImpl; + m_impl = std::make_unique(); m_impl->frameCount = frameCount; m_impl->jointCount = jointCount; m_impl->sequenceJoints.resize(frameCount*jointCount); - m_impl->type = AnimationType_Skeletal; + m_impl->type = AnimationType::Skeletal; return true; } void Animation::Destroy() { - if (m_impl) - { - OnAnimationDestroy(this); - - delete m_impl; - m_impl = nullptr; - } + m_impl.reset(); } void Animation::EnableLoopPointInterpolation(bool loopPointInterpolation) @@ -215,7 +207,7 @@ namespace Nz SequenceJoint* Animation::GetSequenceJoints(std::size_t frameIndex) { NazaraAssert(m_impl, "Animation not created"); - NazaraAssert(m_impl->type == AnimationType_Skeletal, "Animation is not skeletal"); + NazaraAssert(m_impl->type == AnimationType::Skeletal, "Animation is not skeletal"); return &m_impl->sequenceJoints[frameIndex*m_impl->jointCount]; } @@ -223,7 +215,7 @@ namespace Nz const SequenceJoint* Animation::GetSequenceJoints(std::size_t frameIndex) const { NazaraAssert(m_impl, "Animation not created"); - NazaraAssert(m_impl->type == AnimationType_Skeletal, "Animation is not skeletal"); + NazaraAssert(m_impl->type == AnimationType::Skeletal, "Animation is not skeletal"); return &m_impl->sequenceJoints[frameIndex*m_impl->jointCount]; } @@ -289,46 +281,29 @@ namespace Nz m_impl->sequences.erase(it); } - AnimationRef Animation::LoadFromFile(const std::filesystem::path& filePath, const AnimationParams& params) + Animation& Animation::operator=(Animation&&) noexcept = default; + + std::shared_ptr Animation::LoadFromFile(const std::filesystem::path& filePath, const AnimationParams& params) { - return AnimationLoader::LoadFromFile(filePath, params); + Utility* utility = Utility::Instance(); + NazaraAssert(utility, "Utility module has not been initialized"); + + return utility->GetAnimationLoader().LoadFromFile(filePath, params); } - AnimationRef Animation::LoadFromMemory(const void* data, std::size_t size, const AnimationParams& params) + std::shared_ptr Animation::LoadFromMemory(const void* data, std::size_t size, const AnimationParams& params) { - return AnimationLoader::LoadFromMemory(data, size, params); + Utility* utility = Utility::Instance(); + NazaraAssert(utility, "Utility module has not been initialized"); + + return utility->GetAnimationLoader().LoadFromMemory(data, size, params); } - AnimationRef Animation::LoadFromStream(Stream& stream, const AnimationParams& params) + std::shared_ptr Animation::LoadFromStream(Stream& stream, const AnimationParams& params) { - return AnimationLoader::LoadFromStream(stream, params); + Utility* utility = Utility::Instance(); + NazaraAssert(utility, "Utility module has not been initialized"); + + return utility->GetAnimationLoader().LoadFromStream(stream, params); } - - bool Animation::Initialize() - { - if (!AnimationLibrary::Initialize()) - { - NazaraError("Failed to initialise library"); - return false; - } - - if (!AnimationManager::Initialize()) - { - NazaraError("Failed to initialise manager"); - return false; - } - - return true; - } - - void Animation::Uninitialize() - { - AnimationManager::Uninitialize(); - AnimationLibrary::Uninitialize(); - } - - AnimationLibrary::LibraryMap Animation::s_library; - AnimationLoader::LoaderList Animation::s_loaders; - AnimationManager::ManagerMap Animation::s_managerMap; - AnimationManager::ManagerParams Animation::s_managerParameters; } diff --git a/src/Nazara/Utility/Buffer.cpp b/src/Nazara/Utility/Buffer.cpp index 22ec561e9..a07e85e1d 100644 --- a/src/Nazara/Utility/Buffer.cpp +++ b/src/Nazara/Utility/Buffer.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include #include @@ -24,25 +25,18 @@ namespace Nz Buffer::Buffer(BufferType type, UInt32 size, DataStorage storage, BufferUsageFlags usage) : Buffer(type) { - ErrorFlags flags(ErrorFlag_ThrowException, true); + ErrorFlags flags(ErrorMode::ThrowException, true); Create(size, storage, usage); } - Buffer::~Buffer() - { - OnBufferRelease(this); - - Destroy(); - } - - bool Buffer::CopyContent(const BufferRef& buffer) + bool Buffer::CopyContent(const Buffer& buffer) { NazaraAssert(m_impl, "Invalid buffer"); - NazaraAssert(!buffer && !buffer->IsValid(), "Invalid source buffer"); + NazaraAssert(buffer.IsValid(), "Invalid source buffer"); - BufferMapper mapper(*buffer, BufferAccess_ReadOnly); - return Fill(mapper.GetPointer(), 0, buffer->GetSize()); + BufferMapper mapper(buffer, BufferAccess::ReadOnly); + return Fill(mapper.GetPointer(), 0, buffer.GetSize()); } bool Buffer::Create(UInt32 size, DataStorage storage, BufferUsageFlags usage) @@ -56,7 +50,7 @@ namespace Nz return false; } - std::unique_ptr impl(s_bufferFactories[storage](this, m_type)); + std::unique_ptr impl = s_bufferFactories[UnderlyingCast(storage)](this, m_type); if (!impl->Initialize(size, usage)) { NazaraError("Failed to create buffer"); @@ -72,12 +66,7 @@ namespace Nz void Buffer::Destroy() { - if (m_impl) - { - OnBufferDestroy(this); - - m_impl.reset(); - } + m_impl.reset(); } bool Buffer::Fill(const void* data, UInt32 offset, UInt32 size) @@ -99,7 +88,7 @@ namespace Nz void* Buffer::Map(BufferAccess access, UInt32 offset, UInt32 size) const { NazaraAssert(m_impl, "Invalid buffer"); - NazaraAssert(access == BufferAccess_ReadOnly, "Buffer access must be read-only when used const"); + NazaraAssert(access == BufferAccess::ReadOnly, "Buffer access must be read-only when used const"); NazaraAssert(offset + size <= m_size, "Exceeding buffer size"); return m_impl->Map(access, offset, (size == 0) ? m_size - offset : size); @@ -118,7 +107,7 @@ namespace Nz return false; } - void* ptr = m_impl->Map(BufferAccess_ReadOnly, 0, m_size); + void* ptr = m_impl->Map(BufferAccess::ReadOnly, 0, m_size); if (!ptr) { NazaraError("Failed to map buffer"); @@ -130,7 +119,7 @@ namespace Nz m_impl->Unmap(); }); - std::unique_ptr impl(s_bufferFactories[storage](this, m_type)); + std::unique_ptr impl(s_bufferFactories[UnderlyingCast(storage)](this, m_type)); if (!impl->Initialize(m_size, m_usage)) { NazaraError("Failed to create buffer"); @@ -160,19 +149,19 @@ namespace Nz bool Buffer::IsStorageSupported(DataStorage storage) { - return s_bufferFactories[storage] != nullptr; + return s_bufferFactories[UnderlyingCast(storage)] != nullptr; } void Buffer::SetBufferFactory(DataStorage storage, BufferFactory func) { - s_bufferFactories[storage] = func; + s_bufferFactories[UnderlyingCast(storage)] = func; } bool Buffer::Initialize() { - SetBufferFactory(DataStorage_Software, [](Buffer* parent, BufferType type) -> AbstractBuffer* + SetBufferFactory(DataStorage::Software, [](Buffer* parent, BufferType type) -> std::unique_ptr { - return new SoftwareBuffer(parent, type); + return std::make_unique(parent, type); }); return true; @@ -183,5 +172,5 @@ namespace Nz std::fill(s_bufferFactories.begin(), s_bufferFactories.end(), nullptr); } - std::array Buffer::s_bufferFactories; + std::array Buffer::s_bufferFactories; } diff --git a/src/Nazara/Utility/FieldOffsets.cpp b/src/Nazara/Utility/FieldOffsets.cpp index 5e9f229bb..c9aca38e9 100644 --- a/src/Nazara/Utility/FieldOffsets.cpp +++ b/src/Nazara/Utility/FieldOffsets.cpp @@ -26,8 +26,8 @@ namespace Nz std::size_t FieldOffsets::AddFieldArray(StructFieldType type, std::size_t arraySize) { std::size_t fieldAlignement = GetAlignement(m_layout, type); - if (m_layout == StructLayout_Std140) - fieldAlignement = Align(fieldAlignement, GetAlignement(StructLayout_Std140, StructFieldType_Float4)); + if (m_layout == StructLayout::Std140) + fieldAlignement = Align(fieldAlignement, GetAlignement(StructLayout::Std140, StructFieldType::Float4)); m_largestFieldAlignment = std::max(fieldAlignement, m_largestFieldAlignment); @@ -46,9 +46,9 @@ namespace Nz assert(rows >= 2 && rows <= 4); if (columnMajor) - return AddFieldArray(static_cast(cellType + rows - 1), columns); + return AddFieldArray(static_cast(UnderlyingCast(cellType) + rows - 1), columns); else - return AddFieldArray(static_cast(cellType + columns - 1), rows); + return AddFieldArray(static_cast(UnderlyingCast(cellType) + columns - 1), rows); } std::size_t FieldOffsets::AddMatrixArray(StructFieldType cellType, unsigned int columns, unsigned int rows, bool columnMajor, std::size_t arraySize) @@ -58,16 +58,16 @@ namespace Nz assert(rows >= 2 && rows <= 4); if (columnMajor) - return AddFieldArray(static_cast(cellType + rows - 1), columns * arraySize); + return AddFieldArray(static_cast(UnderlyingCast(cellType) + rows - 1), columns * arraySize); else - return AddFieldArray(static_cast(cellType + columns - 1), rows * arraySize); + return AddFieldArray(static_cast(UnderlyingCast(cellType) + columns - 1), rows * arraySize); } std::size_t FieldOffsets::AddStruct(const FieldOffsets& fieldStruct) { std::size_t fieldAlignement = fieldStruct.GetLargestFieldAlignement(); - if (m_layout == StructLayout_Std140) - fieldAlignement = Align(fieldAlignement, GetAlignement(StructLayout_Std140, StructFieldType_Float4)); + if (m_layout == StructLayout::Std140) + fieldAlignement = Align(fieldAlignement, GetAlignement(StructLayout::Std140, StructFieldType::Float4)); m_largestFieldAlignment = std::max(m_largestFieldAlignment, fieldAlignement); @@ -84,8 +84,8 @@ namespace Nz assert(arraySize > 0); std::size_t fieldAlignement = fieldStruct.GetLargestFieldAlignement(); - if (m_layout == StructLayout_Std140) - fieldAlignement = Align(fieldAlignement, GetAlignement(StructLayout_Std140, StructFieldType_Float4)); + if (m_layout == StructLayout::Std140) + fieldAlignement = Align(fieldAlignement, GetAlignement(StructLayout::Std140, StructFieldType::Float4)); m_largestFieldAlignment = std::max(m_largestFieldAlignment, fieldAlignement); diff --git a/src/Nazara/Utility/Font.cpp b/src/Nazara/Utility/Font.cpp index aa91678af..b27750050 100644 --- a/src/Nazara/Utility/Font.cpp +++ b/src/Nazara/Utility/Font.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include namespace Nz @@ -329,7 +330,7 @@ namespace Nz return s_defaultAtlas; } - const FontRef& Font::GetDefault() + const std::shared_ptr& Font::GetDefault() { // Nous n'initialisons la police par défaut qu'à la demande pour qu'elle prenne // les paramètres par défaut (qui peuvent avoir étés changés par l'utilisateur), @@ -355,19 +356,28 @@ namespace Nz return s_defaultMinimumStepSize; } - FontRef Font::OpenFromFile(const std::filesystem::path& filePath, const FontParams& params) + std::shared_ptr Font::OpenFromFile(const std::filesystem::path& filePath, const FontParams& params) { - return FontLoader::LoadFromFile(filePath, params); + Utility* utility = Utility::Instance(); + NazaraAssert(utility, "Utility module has not been initialized"); + + return utility->GetFontLoader().LoadFromFile(filePath, params); } - FontRef Font::OpenFromMemory(const void* data, std::size_t size, const FontParams& params) + std::shared_ptr Font::OpenFromMemory(const void* data, std::size_t size, const FontParams& params) { - return FontLoader::LoadFromMemory(data, size, params); + Utility* utility = Utility::Instance(); + NazaraAssert(utility, "Utility module has not been initialized"); + + return utility->GetFontLoader().LoadFromMemory(data, size, params); } - FontRef Font::OpenFromStream(Stream& stream, const FontParams& params) + std::shared_ptr Font::OpenFromStream(Stream& stream, const FontParams& params) { - return FontLoader::LoadFromStream(stream, params); + Utility* utility = Utility::Instance(); + NazaraAssert(utility, "Utility module has not been initialized"); + + return utility->GetFontLoader().LoadFromStream(stream, params); } void Font::SetDefaultAtlas(const std::shared_ptr& atlas) @@ -401,10 +411,10 @@ namespace Nz sizeStylePart <<= 2; // Store bold and italic flags (other style are handled directly by a TextDrawer) - if (style & TextStyle_Bold) + if (style & TextStyle::Bold) sizeStylePart |= 1 << 0; - if (style & TextStyle_Italic) + if (style & TextStyle::Italic) sizeStylePart |= 1 << 1; return (sizeStylePart << 32) | reinterpret_cast(outlineThickness); @@ -488,16 +498,16 @@ namespace Nz glyph.requireFauxItalic = false; TextStyleFlags supportedStyle = style; - if (style & TextStyle_Bold && !m_data->SupportsStyle(TextStyle_Bold)) + if (style & TextStyle::Bold && !m_data->SupportsStyle(TextStyle::Bold)) { glyph.requireFauxBold = true; - supportedStyle &= ~TextStyle_Bold; + supportedStyle &= ~TextStyle::Bold; } - if (style & TextStyle_Italic && !m_data->SupportsStyle(TextStyle_Italic)) + if (style & TextStyle::Italic && !m_data->SupportsStyle(TextStyle::Italic)) { glyph.requireFauxItalic = true; - supportedStyle &= ~TextStyle_Italic; + supportedStyle &= ~TextStyle::Italic; } float supportedOutlineThickness = outlineThickness; @@ -572,13 +582,7 @@ namespace Nz bool Font::Initialize() { - if (!FontLibrary::Initialize()) - { - NazaraError("Failed to initialise library"); - return false; - } - - s_defaultAtlas.reset(new GuillotineImageAtlas); + s_defaultAtlas = std::make_shared(); s_defaultGlyphBorder = 1; s_defaultMinimumStepSize = 1; @@ -588,14 +592,11 @@ namespace Nz void Font::Uninitialize() { s_defaultAtlas.reset(); - s_defaultFont.Reset(); - FontLibrary::Uninitialize(); + s_defaultFont.reset(); } std::shared_ptr Font::s_defaultAtlas; - FontRef Font::s_defaultFont; - FontLibrary::LibraryMap Font::s_library; - FontLoader::LoaderList Font::s_loaders; + std::shared_ptr Font::s_defaultFont; unsigned int Font::s_defaultGlyphBorder; -unsigned int Font::s_defaultMinimumStepSize; + unsigned int Font::s_defaultMinimumStepSize; } diff --git a/src/Nazara/Utility/Formats/DDSLoader.cpp b/src/Nazara/Utility/Formats/DDSLoader.cpp index b269e0daa..8f8c8a174 100644 --- a/src/Nazara/Utility/Formats/DDSLoader.cpp +++ b/src/Nazara/Utility/Formats/DDSLoader.cpp @@ -18,7 +18,7 @@ namespace Nz DDSLoader() = delete; ~DDSLoader() = delete; - static bool IsSupported(const std::string& extension) + static bool IsSupported(const std::string_view& extension) { return (extension == "dds"); } @@ -27,23 +27,23 @@ namespace Nz { bool skip; if (parameters.custom.GetBooleanParameter("SkipNativeDDSLoader", &skip) && skip) - return Ternary_False; + return Ternary::False; ByteStream byteStream(&stream); - byteStream.SetDataEndianness(Endianness_LittleEndian); + byteStream.SetDataEndianness(Endianness::LittleEndian); UInt32 magic; byteStream >> magic; - return (magic == DDS_Magic) ? Ternary_True : Ternary_False; + return (magic == DDS_Magic) ? Ternary::True : Ternary::False; } - static ImageRef Load(Stream& stream, const ImageParams& parameters) + static std::shared_ptr Load(Stream& stream, const ImageParams& parameters) { NazaraUnused(parameters); ByteStream byteStream(&stream); - byteStream.SetDataEndianness(Endianness_LittleEndian); + byteStream.SetDataEndianness(Endianness::LittleEndian); UInt32 magic; byteStream >> magic; @@ -88,7 +88,7 @@ namespace Nz if (!IdentifyPixelFormat(header, headerDX10, &format)) return nullptr; - ImageRef image = Image::New(type, format, width, height, depth, levelCount); + std::shared_ptr image = std::make_shared(type, format, width, height, depth, levelCount); // Read all mipmap levels for (unsigned int i = 0; i < image->GetLevelCount(); i++) @@ -114,7 +114,7 @@ namespace Nz } - if (parameters.loadFormat != PixelFormat_Undefined) + if (parameters.loadFormat != PixelFormat::Undefined) image->Convert(parameters.loadFormat); return image; @@ -131,9 +131,9 @@ namespace Nz return false; } else if (header.flags & DDSD_HEIGHT) - *type = ImageType_2D_Array; + *type = ImageType::E2D_Array; else - *type = ImageType_1D_Array; + *type = ImageType::E1D_Array; } else { @@ -145,7 +145,7 @@ namespace Nz return false; } - *type = ImageType_Cubemap; + *type = ImageType::Cubemap; } else if (headerExt.resourceDimension == D3D10_RESOURCE_DIMENSION_BUFFER) { @@ -153,11 +153,11 @@ namespace Nz return false; } else if (headerExt.resourceDimension == D3D10_RESOURCE_DIMENSION_TEXTURE1D) - *type = ImageType_1D; + *type = ImageType::E1D; else if (header.ddsCaps[1] & DDSCAPS2_VOLUME || header.flags & DDSD_DEPTH || headerExt.resourceDimension == D3D10_RESOURCE_DIMENSION_TEXTURE3D) - *type = ImageType_3D; + *type = ImageType::E3D; else - *type = ImageType_2D; + *type = ImageType::E2D; } return true; @@ -167,7 +167,7 @@ namespace Nz { if (header.format.flags & (DDPF_RGB | DDPF_ALPHA | DDPF_ALPHAPIXELS | DDPF_LUMINANCE)) { - PixelFormatDescription info(PixelFormatContent_ColorRGBA, header.format.bpp, PixelFormatSubType_Unsigned); + PixelFormatDescription info(PixelFormatContent::ColorRGBA, header.format.bpp, PixelFormatSubType::Unsigned); if (header.format.flags & DDPF_RGB) { @@ -191,15 +191,15 @@ namespace Nz switch (header.format.fourCC) { case D3DFMT_DXT1: - *format = PixelFormat_DXT1; + *format = PixelFormat::DXT1; break; case D3DFMT_DXT3: - *format = PixelFormat_DXT3; + *format = PixelFormat::DXT3; break; case D3DFMT_DXT5: - *format = PixelFormat_DXT3; + *format = PixelFormat::DXT3; break; case D3DFMT_DX10: @@ -207,30 +207,35 @@ namespace Nz switch (headerExt.dxgiFormat) { case DXGI_FORMAT_R32G32B32A32_FLOAT: - *format = PixelFormat_RGBA32F; + *format = PixelFormat::RGBA32F; break; case DXGI_FORMAT_R32G32B32A32_UINT: - *format = PixelFormat_RGBA32UI; + *format = PixelFormat::RGBA32UI; break; case DXGI_FORMAT_R32G32B32A32_SINT: - *format = PixelFormat_RGBA32I; + *format = PixelFormat::RGBA32I; break; case DXGI_FORMAT_R32G32B32_FLOAT: - *format = PixelFormat_RGB32F; + *format = PixelFormat::RGB32F; break; case DXGI_FORMAT_R32G32B32_UINT: - //*format = PixelFormat_RGB32U; + //*format = PixelFormat::RGB32U; return false; case DXGI_FORMAT_R32G32B32_SINT: - *format = PixelFormat_RGB32I; + *format = PixelFormat::RGB32I; break; case DXGI_FORMAT_R16G16B16A16_SNORM: case DXGI_FORMAT_R16G16B16A16_SINT: case DXGI_FORMAT_R16G16B16A16_UINT: - *format = PixelFormat_RGBA16I; + *format = PixelFormat::RGBA16I; break; case DXGI_FORMAT_R16G16B16A16_UNORM: - *format = PixelFormat_RGBA16UI; + *format = PixelFormat::RGBA16UI; + break; + + default: + //TODO + NazaraError("TODO"); break; } break; @@ -262,14 +267,14 @@ namespace Nz namespace Loaders { - void RegisterDDSLoader() + ImageLoader::Entry GetImageLoader_DDS() { - ImageLoader::RegisterLoader(DDSLoader::IsSupported, DDSLoader::Check, DDSLoader::Load); - } + ImageLoader::Entry loaderEntry; + loaderEntry.extensionSupport = DDSLoader::IsSupported; + loaderEntry.streamChecker = DDSLoader::Check; + loaderEntry.streamLoader = DDSLoader::Load; - void UnregisterDDSLoader() - { - ImageLoader::UnregisterLoader(DDSLoader::IsSupported, DDSLoader::Check, DDSLoader::Load); + return loaderEntry; } } } diff --git a/src/Nazara/Utility/Formats/DDSLoader.hpp b/src/Nazara/Utility/Formats/DDSLoader.hpp index 97dca0e83..563eafb03 100644 --- a/src/Nazara/Utility/Formats/DDSLoader.hpp +++ b/src/Nazara/Utility/Formats/DDSLoader.hpp @@ -8,14 +8,11 @@ #define NAZARA_LOADERS_DDS_HPP #include +#include -namespace Nz +namespace Nz::Loaders { - namespace Loaders - { - void RegisterDDSLoader(); - void UnregisterDDSLoader(); - } + ImageLoader::Entry GetImageLoader_DDS(); } #endif // NAZARA_LOADERS_DDS_HPP diff --git a/src/Nazara/Utility/Formats/FreeTypeLoader.cpp b/src/Nazara/Utility/Formats/FreeTypeLoader.cpp index b98b3cdf4..c6ce3b504 100644 --- a/src/Nazara/Utility/Formats/FreeTypeLoader.cpp +++ b/src/Nazara/Utility/Formats/FreeTypeLoader.cpp @@ -3,7 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include -#include +#include #include FT_FREETYPE_H #include FT_BITMAP_H #include FT_STROKER_H @@ -145,7 +145,7 @@ namespace Nz const FT_Pos boldStrength = 2 << 6; - bool embolden = (style & TextStyle_Bold) != 0; + bool embolden = (style & TextStyle::Bold) != 0; bool hasOutlineFormat = (glyph->format == FT_GLYPH_FORMAT_OUTLINE); dst->advance = (embolden) ? boldStrength >> 6 : 0; @@ -202,7 +202,7 @@ namespace Nz if (width > 0 && height > 0) { - dst->image.Create(ImageType_2D, PixelFormat_A8, width, height); + dst->image.Create(ImageType::E2D, PixelFormat::A8, width, height); UInt8* pixels = dst->image.GetPixels(); const UInt8* data = bitmap.buffer; @@ -324,7 +324,7 @@ namespace Nz bool SetFile(const std::filesystem::path& filePath) { std::unique_ptr file = std::make_unique(); - if (!file->Open(filePath, OpenMode_ReadOnly)) + if (!file->Open(filePath, OpenMode::ReadOnly)) { NazaraError("Failed to open stream from file: " + Error::GetLastError()); return false; @@ -363,7 +363,7 @@ namespace Nz bool SupportsStyle(TextStyleFlags style) const override { ///TODO - return style == TextStyle_Regular || style == TextStyle_Bold; + return style == TextStyle_Regular || style == TextStyle::Bold; } private: @@ -384,10 +384,10 @@ namespace Nz mutable unsigned int m_characterSize; }; - bool IsSupported(const std::string& extension) + bool IsSupported(const std::string_view& extension) { ///FIXME: Je suppose qu'il en manque quelques unes.. - static std::set supportedExtensions = { + static std::set supportedExtensions = { "afm", "bdf", "cff", "cid", "dfont", "fnt", "fon", "otf", "pfa", "pfb", "pfm", "pfr", "sfnt", "ttc", "tte", "ttf" }; @@ -398,18 +398,18 @@ namespace Nz { bool skip; if (parameters.custom.GetBooleanParameter("SkipNativeFreeTypeLoader", &skip) && skip) - return Ternary_False; + return Ternary::False; FreeTypeStream face; face.SetStream(stream); if (face.Check()) - return Ternary_True; + return Ternary::True; else - return Ternary_False; + return Ternary::False; } - FontRef LoadFile(const std::filesystem::path& filePath, const FontParams& parameters) + std::shared_ptr LoadFile(const std::filesystem::path& filePath, const FontParams& parameters) { NazaraUnused(parameters); @@ -426,7 +426,7 @@ namespace Nz return nullptr; } - FontRef font = Font::New(); + std::shared_ptr font = std::make_shared(); if (font->Create(face.get())) { face.release(); @@ -436,7 +436,7 @@ namespace Nz return nullptr; } - FontRef LoadMemory(const void* data, std::size_t size, const FontParams& parameters) + std::shared_ptr LoadMemory(const void* data, std::size_t size, const FontParams& parameters) { NazaraUnused(parameters); @@ -449,7 +449,7 @@ namespace Nz return nullptr; } - FontRef font = Font::New(); + std::shared_ptr font = std::make_shared(); if (font->Create(face.get())) { face.release(); @@ -459,7 +459,7 @@ namespace Nz return nullptr; } - FontRef LoadStream(Stream& stream, const FontParams& parameters) + std::shared_ptr LoadStream(Stream& stream, const FontParams& parameters) { NazaraUnused(parameters); @@ -472,7 +472,7 @@ namespace Nz return nullptr; } - FontRef font = Font::New(); + std::shared_ptr font = std::make_shared(); if (font->Create(face.get())) { face.release(); @@ -485,27 +485,36 @@ namespace Nz namespace Loaders { - void RegisterFreeType() + bool InitializeFreeType() { - if (FT_Init_FreeType(&s_library) == 0) + NazaraAssert(!s_libraryOwner, "double initialization for FreeType"); + if (FT_Init_FreeType(&s_library) != 0) { - s_libraryOwner = std::make_shared(); - FontLoader::RegisterLoader(IsSupported, Check, LoadStream, LoadFile, LoadMemory); - } - else - { - s_library = nullptr; // On s'assure que le pointeur ne pointe pas sur n'importe quoi - NazaraWarning("Failed to initialize FreeType library"); + NazaraWarning("failed to initialize FreeType library"); + return false; } + + s_libraryOwner = std::make_shared(); + return true; } - void UnregisterFreeType() + FontLoader::Entry GetFontLoader_FreeType() { - if (s_library) - { - FontLoader::UnregisterLoader(IsSupported, Check, LoadStream, LoadFile, LoadMemory); - s_libraryOwner.reset(); - } + NazaraAssert(s_libraryOwner, "FreeType has not been initialized"); + + FontLoader::Entry entry; + entry.extensionSupport = IsSupported; + entry.fileLoader = LoadFile; + entry.memoryLoader = LoadMemory; + entry.streamChecker = Check; + entry.streamLoader = LoadStream; + + return entry; + } + + void UninitializeFreeType() + { + s_libraryOwner.reset(); } } } diff --git a/src/Nazara/Utility/Formats/FreeTypeLoader.hpp b/src/Nazara/Utility/Formats/FreeTypeLoader.hpp index c26e63c4a..d37b1ac8f 100644 --- a/src/Nazara/Utility/Formats/FreeTypeLoader.hpp +++ b/src/Nazara/Utility/Formats/FreeTypeLoader.hpp @@ -8,14 +8,13 @@ #define NAZARA_LOADERS_FREETYPE_HPP #include +#include -namespace Nz +namespace Nz::Loaders { - namespace Loaders - { - void RegisterFreeType(); - void UnregisterFreeType(); - } + bool InitializeFreeType(); + FontLoader::Entry GetFontLoader_FreeType(); + void UninitializeFreeType(); } #endif // NAZARA_LOADERS_FREETYPE_HPP diff --git a/src/Nazara/Utility/Formats/MD2Loader.cpp b/src/Nazara/Utility/Formats/MD2Loader.cpp index 890572d35..395007750 100644 --- a/src/Nazara/Utility/Formats/MD2Loader.cpp +++ b/src/Nazara/Utility/Formats/MD2Loader.cpp @@ -20,7 +20,7 @@ namespace Nz { namespace { - bool IsSupported(const std::string& extension) + bool IsSupported(const std::string_view& extension) { return (extension == "md2"); } @@ -29,7 +29,7 @@ namespace Nz { bool skip; if (parameters.custom.GetBooleanParameter("SkipNativeMD2Loader", &skip) && skip) - return Ternary_False; + return Ternary::False; UInt32 magic[2]; if (stream.Read(&magic[0], 2*sizeof(UInt32)) == 2*sizeof(UInt32)) @@ -40,13 +40,13 @@ namespace Nz #endif if (magic[0] == md2Ident && magic[1] == 8) - return Ternary_True; + return Ternary::True; } - return Ternary_False; + return Ternary::False; } - MeshRef Load(Stream& stream, const MeshParams& parameters) + std::shared_ptr Load(Stream& stream, const MeshParams& parameters) { MD2_Header header; if (stream.Read(&header, sizeof(MD2_Header)) != sizeof(MD2_Header)) @@ -80,7 +80,7 @@ namespace Nz } // Since the engine no longer supports keyframe animations, let's make a static mesh - MeshRef mesh = Nz::Mesh::New(); + std::shared_ptr mesh = std::make_shared(); if (!mesh->CreateStatic()) { NazaraInternalError("Failed to create mesh"); @@ -107,7 +107,7 @@ namespace Nz } } - IndexBufferRef indexBuffer = IndexBuffer::New(false, header.num_tris*3, parameters.storage, parameters.indexBufferFlags); + std::shared_ptr indexBuffer = std::make_shared(false, header.num_tris*3, parameters.storage, parameters.indexBufferFlags); // Extract triangles data std::vector triangles(header.num_tris); @@ -116,7 +116,7 @@ namespace Nz stream.Read(&triangles[0], header.num_tris*sizeof(MD2_Triangle)); // And convert them into an index buffer - BufferMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite); + BufferMapper indexMapper(*indexBuffer, BufferAccess::DiscardAndWrite); UInt16* index = static_cast(indexMapper.GetPointer()); for (unsigned int i = 0; i < header.num_tris; ++i) @@ -158,8 +158,8 @@ namespace Nz } #endif - VertexBufferRef vertexBuffer = VertexBuffer::New(parameters.vertexDeclaration, header.num_vertices, parameters.storage, parameters.vertexBufferFlags); - StaticMeshRef subMesh = StaticMesh::New(vertexBuffer, indexBuffer); + std::shared_ptr vertexBuffer = std::make_shared(parameters.vertexDeclaration, header.num_vertices, parameters.storage, parameters.vertexBufferFlags); + std::shared_ptr subMesh = std::make_shared(vertexBuffer, indexBuffer); // Extracting vertices stream.SetCursorPos(header.offset_frames); @@ -186,10 +186,10 @@ namespace Nz scale *= ScaleAdjust; translate *= ScaleAdjust; - VertexMapper vertexMapper(vertexBuffer, BufferAccess_DiscardAndWrite); + VertexMapper vertexMapper(*vertexBuffer, BufferAccess::DiscardAndWrite); // Loading texture coordinates - if (auto uvPtr = vertexMapper.GetComponentPtr(VertexComponent_TexCoord)) + if (auto uvPtr = vertexMapper.GetComponentPtr(VertexComponent::TexCoord)) { const unsigned int indexFix[3] = {0, 2, 1}; @@ -214,7 +214,7 @@ namespace Nz Nz::Matrix4f matrix = Matrix4f::Transform(translate, rotationQuat, scale); matrix *= parameters.matrix; - if (auto normalPtr = vertexMapper.GetComponentPtr(VertexComponent_Normal)) + if (auto normalPtr = vertexMapper.GetComponentPtr(VertexComponent::Normal)) { Nz::Matrix4f normalMatrix = Matrix4f::Rotate(rotationQuat); normalMatrix *= parameters.matrix; @@ -227,7 +227,7 @@ namespace Nz } } - auto posPtr = vertexMapper.GetComponentPtr(VertexComponent_Position); + auto posPtr = vertexMapper.GetComponentPtr(VertexComponent::Position); assert(posPtr); for (unsigned int v = 0; v < header.num_vertices; ++v) @@ -244,7 +244,7 @@ namespace Nz subMesh->GenerateAABB(); - if (parameters.vertexDeclaration->HasComponentOfType(VertexComponent_Tangent)) + if (parameters.vertexDeclaration->HasComponentOfType(VertexComponent::Tangent)) subMesh->GenerateTangents(); mesh->AddSubMesh(subMesh); @@ -258,14 +258,14 @@ namespace Nz namespace Loaders { - void RegisterMD2() + MeshLoader::Entry GetMeshLoader_MD2() { - MeshLoader::RegisterLoader(IsSupported, Check, Load); - } + MeshLoader::Entry loader; + loader.extensionSupport = IsSupported; + loader.streamChecker = Check; + loader.streamLoader = Load; - void UnregisterMD2() - { - MeshLoader::UnregisterLoader(IsSupported, Check, Load); + return loader; } } } diff --git a/src/Nazara/Utility/Formats/MD2Loader.hpp b/src/Nazara/Utility/Formats/MD2Loader.hpp index 208a8bbf5..a72dac946 100644 --- a/src/Nazara/Utility/Formats/MD2Loader.hpp +++ b/src/Nazara/Utility/Formats/MD2Loader.hpp @@ -8,14 +8,11 @@ #define NAZARA_LOADERS_MD2_HPP #include +#include -namespace Nz +namespace Nz::Loaders { - namespace Loaders - { - void RegisterMD2(); - void UnregisterMD2(); - } + MeshLoader::Entry GetMeshLoader_MD2(); } #endif // NAZARA_LOADERS_MD2_HPP diff --git a/src/Nazara/Utility/Formats/MD5AnimLoader.cpp b/src/Nazara/Utility/Formats/MD5AnimLoader.cpp index f069322ab..7afa29a0d 100644 --- a/src/Nazara/Utility/Formats/MD5AnimLoader.cpp +++ b/src/Nazara/Utility/Formats/MD5AnimLoader.cpp @@ -12,7 +12,7 @@ namespace Nz { namespace { - bool IsSupported(const std::string& extension) + bool IsSupported(const std::string_view& extension) { return (extension == "md5anim"); } @@ -21,13 +21,13 @@ namespace Nz { bool skip; if (parameters.custom.GetBooleanParameter("SkipNativeMD5AnimLoader", &skip) && skip) - return Ternary_False; + return Ternary::False; MD5AnimParser parser(stream); return parser.Check(); } - AnimationRef Load(Stream& stream, const AnimationParams& /*parameters*/) + std::shared_ptr Load(Stream& stream, const AnimationParams& /*parameters*/) { ///TODO: Utiliser les paramètres MD5AnimParser parser(stream); @@ -45,7 +45,7 @@ namespace Nz std::size_t jointCount = parser.GetJointCount(); // À ce stade, nous sommes censés avoir assez d'informations pour créer l'animation - AnimationRef animation = Animation::New(); + std::shared_ptr animation = std::make_shared(); animation->CreateSkeletal(frameCount, jointCount); Sequence sequence; @@ -90,14 +90,14 @@ namespace Nz namespace Loaders { - void RegisterMD5Anim() + AnimationLoader::Entry GetAnimationLoader_MD5Anim() { - AnimationLoader::RegisterLoader(IsSupported, Check, Load); - } + AnimationLoader::Entry loader; + loader.extensionSupport = IsSupported; + loader.streamChecker = Check; + loader.streamLoader = Load; - void UnregisterMD5Anim() - { - AnimationLoader::UnregisterLoader(IsSupported, Check, Load); + return loader; } } } diff --git a/src/Nazara/Utility/Formats/MD5AnimLoader.hpp b/src/Nazara/Utility/Formats/MD5AnimLoader.hpp index e84729106..e53ec55fe 100644 --- a/src/Nazara/Utility/Formats/MD5AnimLoader.hpp +++ b/src/Nazara/Utility/Formats/MD5AnimLoader.hpp @@ -8,14 +8,11 @@ #define NAZARA_LOADERS_MD5ANIM_HPP #include +#include -namespace Nz +namespace Nz::Loaders { - namespace Loaders - { - void RegisterMD5Anim(); - void UnregisterMD5Anim(); - } + AnimationLoader::Entry GetAnimationLoader_MD5Anim(); } #endif // NAZARA_LOADERS_MD5ANIM_HPP diff --git a/src/Nazara/Utility/Formats/MD5AnimParser.cpp b/src/Nazara/Utility/Formats/MD5AnimParser.cpp index 8a79d753d..d0bb520ec 100644 --- a/src/Nazara/Utility/Formats/MD5AnimParser.cpp +++ b/src/Nazara/Utility/Formats/MD5AnimParser.cpp @@ -25,7 +25,7 @@ namespace Nz MD5AnimParser::~MD5AnimParser() { // Reset stream flags - if ((m_streamFlags & StreamOption_Text) == 0) + if ((m_streamFlags & StreamOption::Text) == 0) m_stream.EnableTextMode(false); } @@ -37,11 +37,11 @@ namespace Nz if (std::sscanf(&m_currentLine[0], " MD5Version %u", &version) == 1) { if (version == 10) - return Ternary_True; + return Ternary::True; } } - return Ternary_False; + return Ternary::False; } UInt32 MD5AnimParser::GetAnimatedComponentCount() const diff --git a/src/Nazara/Utility/Formats/MD5MeshLoader.cpp b/src/Nazara/Utility/Formats/MD5MeshLoader.cpp index 18f6c028e..7a6ba60e1 100644 --- a/src/Nazara/Utility/Formats/MD5MeshLoader.cpp +++ b/src/Nazara/Utility/Formats/MD5MeshLoader.cpp @@ -20,7 +20,7 @@ namespace Nz { namespace { - bool IsSupported(const std::string& extension) + bool IsSupported(const std::string_view& extension) { return (extension == "md5mesh"); } @@ -29,13 +29,13 @@ namespace Nz { bool skip; if (parameters.custom.GetBooleanParameter("SkipNativeMD5MeshLoader", &skip) && skip) - return Ternary_False; + return Ternary::False; MD5MeshParser parser(stream); return parser.Check(); } - MeshRef Load(Stream& stream, const MeshParams& parameters) + std::shared_ptr Load(Stream& stream, const MeshParams& parameters) { MD5MeshParser parser(stream); if (!parser.Parse()) @@ -62,7 +62,7 @@ namespace Nz if (parameters.animated) { - MeshRef mesh = Mesh::New(); + std::shared_ptr mesh = std::make_shared(); mesh->CreateSkeletal(jointCount); Skeleton* skeleton = mesh->GetSkeleton(); @@ -96,11 +96,11 @@ namespace Nz bool largeIndices = (vertexCount > std::numeric_limits::max()); - IndexBufferRef indexBuffer = IndexBuffer::New(largeIndices, UInt32(indexCount), parameters.storage, parameters.indexBufferFlags); - VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent_Skinning), UInt32(vertexCount), parameters.storage, parameters.vertexBufferFlags); + std::shared_ptr indexBuffer = std::make_shared(largeIndices, UInt32(indexCount), parameters.storage, parameters.indexBufferFlags); + std::shared_ptr vertexBuffer = std::make_shared(VertexDeclaration::Get(VertexLayout::XYZ_Normal_UV_Tangent_Skinning), UInt32(vertexCount), parameters.storage, parameters.vertexBufferFlags); // Index buffer - IndexMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite); + IndexMapper indexMapper(*indexBuffer, BufferAccess::DiscardAndWrite); // Le format définit un set de triangles nous permettant de retrouver facilement les indices // Cependant les sommets des triangles ne sont pas spécifiés dans le même ordre que ceux du moteur @@ -128,7 +128,7 @@ namespace Nz std::vector tempWeights; - BufferMapper vertexMapper(vertexBuffer, BufferAccess_WriteOnly); + BufferMapper vertexMapper(*vertexBuffer, BufferAccess::WriteOnly); SkeletalMeshVertex* vertices = static_cast(vertexMapper.GetPointer()); for (const MD5MeshParser::Vertex& vertex : md5Mesh.vertices) @@ -203,7 +203,7 @@ namespace Nz mesh->SetMaterialData(i, std::move(matData)); // Submesh - SkeletalMeshRef subMesh = SkeletalMesh::New(vertexBuffer, indexBuffer); + std::shared_ptr subMesh = std::make_shared(vertexBuffer, indexBuffer); subMesh->GenerateNormalsAndTangents(); subMesh->SetMaterialIndex(i); @@ -224,7 +224,7 @@ namespace Nz } else { - MeshRef mesh = Mesh::New(); + std::shared_ptr mesh = std::make_shared(); if (!mesh->CreateStatic()) // Ne devrait jamais échouer { NazaraInternalError("Failed to create mesh"); @@ -241,9 +241,9 @@ namespace Nz // Index buffer bool largeIndices = (vertexCount > std::numeric_limits::max()); - IndexBufferRef indexBuffer = IndexBuffer::New(largeIndices, UInt32(indexCount), parameters.storage, parameters.indexBufferFlags); + std::shared_ptr indexBuffer = std::make_shared(largeIndices, UInt32(indexCount), parameters.storage, parameters.indexBufferFlags); - IndexMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite); + IndexMapper indexMapper(*indexBuffer, BufferAccess::DiscardAndWrite); IndexIterator index = indexMapper.begin(); for (const MD5MeshParser::Triangle& triangle : md5Mesh.triangles) @@ -259,11 +259,11 @@ namespace Nz indexBuffer->Optimize(); // Vertex buffer - VertexBufferRef vertexBuffer = VertexBuffer::New(parameters.vertexDeclaration, UInt32(vertexCount), parameters.storage, parameters.vertexBufferFlags); + std::shared_ptr vertexBuffer = std::make_shared(parameters.vertexDeclaration, UInt32(vertexCount), parameters.storage, parameters.vertexBufferFlags); - VertexMapper vertexMapper(vertexBuffer, BufferAccess_DiscardAndWrite); + VertexMapper vertexMapper(*vertexBuffer, BufferAccess::DiscardAndWrite); - auto posPtr = vertexMapper.GetComponentPtr(VertexComponent_Position); + auto posPtr = vertexMapper.GetComponentPtr(VertexComponent::Position); for (const MD5MeshParser::Vertex& md5Vertex : md5Mesh.vertices) { @@ -281,7 +281,7 @@ namespace Nz *posPtr++ = matrix * finalPos; } - if (auto uvPtr = vertexMapper.GetComponentPtr(VertexComponent_TexCoord)) + if (auto uvPtr = vertexMapper.GetComponentPtr(VertexComponent::TexCoord)) { for (const MD5MeshParser::Vertex& md5Vertex : md5Mesh.vertices) *uvPtr++ = parameters.texCoordOffset + md5Vertex.uv * parameters.texCoordScale; @@ -290,13 +290,13 @@ namespace Nz vertexMapper.Unmap(); // Submesh - StaticMeshRef subMesh = StaticMesh::New(vertexBuffer, indexBuffer); + std::shared_ptr subMesh = std::make_shared(vertexBuffer, indexBuffer); subMesh->GenerateAABB(); subMesh->SetMaterialIndex(i); - if (parameters.vertexDeclaration->HasComponentOfType(VertexComponent_Normal)) + if (parameters.vertexDeclaration->HasComponentOfType(VertexComponent::Normal)) { - if (parameters.vertexDeclaration->HasComponentOfType(VertexComponent_Tangent)) + if (parameters.vertexDeclaration->HasComponentOfType(VertexComponent::Tangent)) subMesh->GenerateNormalsAndTangents(); else subMesh->GenerateNormals(); @@ -321,14 +321,14 @@ namespace Nz namespace Loaders { - void RegisterMD5Mesh() + MeshLoader::Entry GetMeshLoader_MD5Mesh() { - MeshLoader::RegisterLoader(IsSupported, Check, Load); - } + MeshLoader::Entry loader; + loader.extensionSupport = IsSupported; + loader.streamChecker = Check; + loader.streamLoader = Load; - void UnregisterMD5Mesh() - { - MeshLoader::UnregisterLoader(IsSupported, Check, Load); + return loader; } } } diff --git a/src/Nazara/Utility/Formats/MD5MeshLoader.hpp b/src/Nazara/Utility/Formats/MD5MeshLoader.hpp index 0a0fb5af4..cc5d5f30b 100644 --- a/src/Nazara/Utility/Formats/MD5MeshLoader.hpp +++ b/src/Nazara/Utility/Formats/MD5MeshLoader.hpp @@ -8,14 +8,11 @@ #define NAZARA_LOADERS_MD5MESH_HPP #include +#include -namespace Nz +namespace Nz::Loaders { - namespace Loaders - { - void RegisterMD5Mesh(); - void UnregisterMD5Mesh(); - } + MeshLoader::Entry GetMeshLoader_MD5Mesh(); } #endif // NAZARA_LOADERS_MD5MESH_HPP diff --git a/src/Nazara/Utility/Formats/MD5MeshParser.cpp b/src/Nazara/Utility/Formats/MD5MeshParser.cpp index a2d00dc3e..abd7bce4f 100644 --- a/src/Nazara/Utility/Formats/MD5MeshParser.cpp +++ b/src/Nazara/Utility/Formats/MD5MeshParser.cpp @@ -25,7 +25,7 @@ namespace Nz MD5MeshParser::~MD5MeshParser() { // Reset stream flags - if ((m_streamFlags & StreamOption_Text) == 0) + if ((m_streamFlags & StreamOption::Text) == 0) m_stream.EnableTextMode(false); } @@ -37,11 +37,11 @@ namespace Nz if (std::sscanf(&m_currentLine[0], " MD5Version %u", &version) == 1) { if (version == 10) - return Ternary_True; + return Ternary::True; } } - return Ternary_False; + return Ternary::False; } const MD5MeshParser::Joint* MD5MeshParser::GetJoints() const diff --git a/src/Nazara/Utility/Formats/MTLParser.cpp b/src/Nazara/Utility/Formats/MTLParser.cpp index 1d64820cf..8b9aa50c3 100644 --- a/src/Nazara/Utility/Formats/MTLParser.cpp +++ b/src/Nazara/Utility/Formats/MTLParser.cpp @@ -35,7 +35,7 @@ namespace Nz // Force stream in text mode, reset it at the end Nz::CallOnExit resetTextMode; - if ((stream.GetStreamOptions() & StreamOption_Text) == 0) + if ((stream.GetStreamOptions() & StreamOption::Text) == 0) { stream.EnableTextMode(true); @@ -72,6 +72,7 @@ namespace Nz else UnrecognizedLine(); #endif + break; } } @@ -489,7 +490,7 @@ namespace Nz // Force stream in text mode, reset it at the end Nz::CallOnExit resetTextMode; - if ((stream.GetStreamOptions() & StreamOption_Text) == 0) + if ((stream.GetStreamOptions() & StreamOption::Text) == 0) { stream.EnableTextMode(true); diff --git a/src/Nazara/Utility/Formats/OBJLoader.cpp b/src/Nazara/Utility/Formats/OBJLoader.cpp index 7967fa7ed..9b14409c9 100644 --- a/src/Nazara/Utility/Formats/OBJLoader.cpp +++ b/src/Nazara/Utility/Formats/OBJLoader.cpp @@ -22,7 +22,7 @@ namespace Nz { namespace { - bool IsSupported(const std::string& extension) + bool IsSupported(const std::string_view& extension) { return (extension == "obj"); } @@ -33,19 +33,19 @@ namespace Nz bool skip; if (parameters.custom.GetBooleanParameter("SkipNativeOBJLoader", &skip) && skip) - return Ternary_False; + return Ternary::False; OBJParser parser; if (!parser.Check(stream)) - return Ternary_False; + return Ternary::False; - return Ternary_Unknown; + return Ternary::Unknown; } - bool ParseMTL(Mesh* mesh, const std::filesystem::path& filePath, const std::string* materials, const OBJParser::Mesh* meshes, std::size_t meshCount) + bool ParseMTL(Mesh& mesh, const std::filesystem::path& filePath, const std::string* materials, const OBJParser::Mesh* meshes, std::size_t meshCount) { File file(filePath); - if (!file.Open(OpenMode_ReadOnly | OpenMode_Text)) + if (!file.Open(OpenMode::ReadOnly | OpenMode::Text)) { NazaraError("Failed to open MTL file (" + file.GetPath().generic_u8string() + ')'); return false; @@ -140,20 +140,24 @@ namespace Nz // Some default settings data.SetParameter(MaterialData::Blending, true); data.SetParameter(MaterialData::DepthWrite, true); - data.SetParameter(MaterialData::DstBlend, static_cast(BlendFunc_InvSrcAlpha)); - data.SetParameter(MaterialData::SrcBlend, static_cast(BlendFunc_SrcAlpha)); + data.SetParameter(MaterialData::BlendDstAlpha, static_cast(BlendFunc::Zero)); + data.SetParameter(MaterialData::BlendDstColor, static_cast(BlendFunc::InvSrcAlpha)); + data.SetParameter(MaterialData::BlendModeAlpha, static_cast(BlendEquation::Add)); + data.SetParameter(MaterialData::BlendModeColor, static_cast(BlendEquation::Add)); + data.SetParameter(MaterialData::BlendSrcAlpha, static_cast(BlendFunc::One)); + data.SetParameter(MaterialData::BlendSrcColor, static_cast(BlendFunc::SrcAlpha)); } it = materialCache.emplace(matName, std::move(data)).first; } - mesh->SetMaterialData(meshes[i].material, it->second); + mesh.SetMaterialData(meshes[i].material, it->second); } return true; } - MeshRef Load(Stream& stream, const MeshParams& parameters) + std::shared_ptr Load(Stream& stream, const MeshParams& parameters) { long long reservedVertexCount; if (!parameters.custom.GetIntegerParameter("NativeOBJLoader_VertexCount", &reservedVertexCount)) @@ -166,7 +170,7 @@ namespace Nz return nullptr; } - MeshRef mesh = Mesh::New(); + std::shared_ptr mesh = std::make_shared(); mesh->CreateStatic(); const std::string* materials = parser.GetMaterials(); @@ -250,11 +254,11 @@ namespace Nz } // Création des buffers - IndexBufferRef indexBuffer = IndexBuffer::New(vertexCount > std::numeric_limits::max(), std::size_t(indices.size()), parameters.storage, parameters.indexBufferFlags); - VertexBufferRef vertexBuffer = VertexBuffer::New(parameters.vertexDeclaration, std::size_t(vertexCount), parameters.storage, parameters.vertexBufferFlags); + std::shared_ptr indexBuffer = std::make_shared(vertexCount > std::numeric_limits::max(), std::size_t(indices.size()), parameters.storage, parameters.indexBufferFlags); + std::shared_ptr vertexBuffer = std::make_shared(parameters.vertexDeclaration, std::size_t(vertexCount), parameters.storage, parameters.vertexBufferFlags); // Remplissage des indices - IndexMapper indexMapper(indexBuffer, BufferAccess_WriteOnly); + IndexMapper indexMapper(*indexBuffer, BufferAccess::WriteOnly); for (std::size_t j = 0; j < indices.size(); ++j) indexMapper.Set(j, UInt32(indices[j])); @@ -273,11 +277,11 @@ namespace Nz bool hasNormals = true; bool hasTexCoords = true; - VertexMapper vertexMapper(vertexBuffer, BufferAccess_DiscardAndWrite); + VertexMapper vertexMapper(*vertexBuffer, BufferAccess::DiscardAndWrite); - auto normalPtr = vertexMapper.GetComponentPtr(VertexComponent_Normal); - auto posPtr = vertexMapper.GetComponentPtr(VertexComponent_Position); - auto uvPtr = vertexMapper.GetComponentPtr(VertexComponent_TexCoord); + auto normalPtr = vertexMapper.GetComponentPtr(VertexComponent::Normal); + auto posPtr = vertexMapper.GetComponentPtr(VertexComponent::Position); + auto uvPtr = vertexMapper.GetComponentPtr(VertexComponent::TexCoord); if (!normalPtr) hasNormals = false; @@ -317,7 +321,7 @@ namespace Nz vertexMapper.Unmap(); - StaticMeshRef subMesh = StaticMesh::New(vertexBuffer, indexBuffer); + std::shared_ptr subMesh = std::make_shared(std::move(vertexBuffer), indexBuffer); subMesh->GenerateAABB(); subMesh->SetMaterialIndex(meshes[i].material); @@ -340,8 +344,8 @@ namespace Nz std::filesystem::path mtlLib = parser.GetMtlLib(); if (!mtlLib.empty()) { - ErrorFlags flags(ErrorFlag_ThrowExceptionDisabled); - ParseMTL(mesh, stream.GetDirectory() / mtlLib, materials, meshes, meshCount); + ErrorFlags flags(ErrorMode::ThrowExceptionDisabled); + ParseMTL(*mesh, stream.GetDirectory() / mtlLib, materials, meshes, meshCount); } return mesh; @@ -350,14 +354,14 @@ namespace Nz namespace Loaders { - void RegisterOBJLoader() + MeshLoader::Entry GetMeshLoader_OBJ() { - MeshLoader::RegisterLoader(IsSupported, Check, Load); - } + MeshLoader::Entry loader; + loader.extensionSupport = IsSupported; + loader.streamChecker = Check; + loader.streamLoader = Load; - void UnregisterOBJLoader() - { - MeshLoader::UnregisterLoader(IsSupported, Check, Load); + return loader; } } } diff --git a/src/Nazara/Utility/Formats/OBJLoader.hpp b/src/Nazara/Utility/Formats/OBJLoader.hpp index 2f3c2f8e5..c1fc7f86b 100644 --- a/src/Nazara/Utility/Formats/OBJLoader.hpp +++ b/src/Nazara/Utility/Formats/OBJLoader.hpp @@ -8,14 +8,11 @@ #define NAZARA_LOADERS_OBJ_HPP #include +#include -namespace Nz +namespace Nz::Loaders { - namespace Loaders - { - void RegisterOBJLoader(); - void UnregisterOBJLoader(); - } + MeshLoader::Entry GetMeshLoader_OBJ(); } #endif // NAZARA_LOADERS_OBJ_HPP diff --git a/src/Nazara/Utility/Formats/OBJParser.cpp b/src/Nazara/Utility/Formats/OBJParser.cpp index f5e7b4f76..fe63efe31 100644 --- a/src/Nazara/Utility/Formats/OBJParser.cpp +++ b/src/Nazara/Utility/Formats/OBJParser.cpp @@ -23,7 +23,7 @@ namespace Nz // Force stream in text mode, reset it at the end Nz::CallOnExit resetTextMode; - if ((stream.GetStreamOptions() & StreamOption_Text) == 0) + if ((stream.GetStreamOptions() & StreamOption::Text) == 0) { stream.EnableTextMode(true); @@ -95,7 +95,7 @@ namespace Nz // Force stream in text mode, reset it at the end Nz::CallOnExit resetTextMode; - if ((stream.GetStreamOptions() & StreamOption_Text) == 0) + if ((stream.GetStreamOptions() & StreamOption::Text) == 0) { stream.EnableTextMode(true); @@ -493,7 +493,7 @@ namespace Nz // Force stream in text mode, reset it at the end Nz::CallOnExit resetTextMode; - if ((stream.GetStreamOptions() & StreamOption_Text) == 0) + if ((stream.GetStreamOptions() & StreamOption::Text) == 0) { stream.EnableTextMode(true); diff --git a/src/Nazara/Utility/Formats/OBJSaver.cpp b/src/Nazara/Utility/Formats/OBJSaver.cpp index 9945d5f55..c18ed1a8e 100644 --- a/src/Nazara/Utility/Formats/OBJSaver.cpp +++ b/src/Nazara/Utility/Formats/OBJSaver.cpp @@ -51,7 +51,7 @@ namespace Nz T* m_buffer; }; - bool IsSupported(const std::string& extension) + bool IsSupported(const std::string_view& extension) { return (extension == "obj"); } @@ -142,21 +142,21 @@ namespace Nz OBJParser::Mesh* meshes = objFormat.SetMeshCount(meshCount); for (std::size_t i = 0; i < meshCount; ++i) { - const StaticMesh* staticMesh = static_cast(mesh.GetSubMesh(i)); + const StaticMesh& staticMesh = static_cast(*mesh.GetSubMesh(i)); - std::size_t triangleCount = staticMesh->GetTriangleCount(); + std::size_t triangleCount = staticMesh.GetTriangleCount(); meshes[i].faces.resize(triangleCount); - meshes[i].material = staticMesh->GetMaterialIndex(); + meshes[i].material = staticMesh.GetMaterialIndex(); meshes[i].name = "mesh_" + std::to_string(i); meshes[i].vertices.resize(triangleCount * 3); { VertexMapper vertexMapper(staticMesh); - SparsePtr normalPtr = vertexMapper.GetComponentPtr(VertexComponent_Normal); - SparsePtr positionPtr = vertexMapper.GetComponentPtr(VertexComponent_Position); - SparsePtr texCoordsPtr = vertexMapper.GetComponentPtr(VertexComponent_TexCoord); + SparsePtr normalPtr = vertexMapper.GetComponentPtr(VertexComponent::Normal); + SparsePtr positionPtr = vertexMapper.GetComponentPtr(VertexComponent::Position); + SparsePtr texCoordsPtr = vertexMapper.GetComponentPtr(VertexComponent::TexCoord); std::size_t faceIndex = 0; TriangleIterator triangle(staticMesh); @@ -190,7 +190,7 @@ namespace Nz if (!mtlPath.empty()) { - File mtlFile(mtlPath, OpenMode_WriteOnly | OpenMode_Truncate); + File mtlFile(mtlPath, OpenMode::WriteOnly | OpenMode::Truncate); if (mtlFile.IsOpen()) mtlFormat.Save(mtlFile); } @@ -201,14 +201,13 @@ namespace Nz namespace Loaders { - void RegisterOBJSaver() + MeshSaver::Entry GetMeshSaver_OBJ() { - MeshSaver::RegisterSaver(IsSupported, SaveToStream); - } + MeshSaver::Entry entry; + entry.formatSupport = IsSupported; + entry.streamSaver = SaveToStream; - void UnregisterOBJSaver() - { - MeshSaver::UnregisterSaver(IsSupported, SaveToStream); + return entry; } } } diff --git a/src/Nazara/Utility/Formats/OBJSaver.hpp b/src/Nazara/Utility/Formats/OBJSaver.hpp index c67e04f48..21f199b5d 100644 --- a/src/Nazara/Utility/Formats/OBJSaver.hpp +++ b/src/Nazara/Utility/Formats/OBJSaver.hpp @@ -8,14 +8,11 @@ #define NAZARA_FORMATS_OBJSAVER_HPP #include +#include -namespace Nz +namespace Nz::Loaders { - namespace Loaders - { - void RegisterOBJSaver(); - void UnregisterOBJSaver(); - } + MeshSaver::Entry GetMeshSaver_OBJ(); } #endif // NAZARA_FORMATS_OBJSAVER_HPP diff --git a/src/Nazara/Utility/Formats/PCXLoader.cpp b/src/Nazara/Utility/Formats/PCXLoader.cpp index 1dd8e8c64..d2faec125 100644 --- a/src/Nazara/Utility/Formats/PCXLoader.cpp +++ b/src/Nazara/Utility/Formats/PCXLoader.cpp @@ -40,7 +40,7 @@ namespace Nz static_assert(sizeof(pcx_header) == (6+48+54)*sizeof(UInt8) + 10*sizeof(UInt16), "pcx_header struct must be packed"); - bool IsSupported(const std::string& extension) + bool IsSupported(const std::string_view& extension) { return (extension == "pcx"); } @@ -49,19 +49,19 @@ namespace Nz { bool skip; if (parameters.custom.GetBooleanParameter("SkipNativePCXLoader", &skip) && skip) - return Ternary_False; + return Ternary::False; UInt8 manufacturer; if (stream.Read(&manufacturer, 1) == 1) { if (manufacturer == 0x0a) - return Ternary_True; + return Ternary::True; } - return Ternary_False; + return Ternary::False; } - ImageRef Load(Stream& stream, const ImageParams& parameters) + std::shared_ptr Load(Stream& stream, const ImageParams& parameters) { NazaraUnused(parameters); @@ -91,8 +91,8 @@ namespace Nz unsigned int width = header.xmax - header.xmin+1; unsigned int height = header.ymax - header.ymin+1; - ImageRef image = Image::New(); - if (!image->Create(ImageType_2D, PixelFormat_RGB8, width, height, 1, (parameters.levelCount > 0) ? parameters.levelCount : 1)) + std::shared_ptr image = std::make_shared(); + if (!image->Create(ImageType::E2D, PixelFormat::RGB8, width, height, 1, (parameters.levelCount > 0) ? parameters.levelCount : 1)) { NazaraError("Failed to create image"); return nullptr; @@ -333,7 +333,7 @@ namespace Nz return nullptr; } - if (parameters.loadFormat != PixelFormat_Undefined) + if (parameters.loadFormat != PixelFormat::Undefined) image->Convert(parameters.loadFormat); return image; @@ -342,14 +342,14 @@ namespace Nz namespace Loaders { - void RegisterPCX() + ImageLoader::Entry GetImageLoader_PCX() { - ImageLoader::RegisterLoader(IsSupported, Check, Load); - } + ImageLoader::Entry loaderEntry; + loaderEntry.extensionSupport = IsSupported; + loaderEntry.streamChecker = Check; + loaderEntry.streamLoader = Load; - void UnregisterPCX() - { - ImageLoader::UnregisterLoader(IsSupported, Check, Load); + return loaderEntry; } } } diff --git a/src/Nazara/Utility/Formats/PCXLoader.hpp b/src/Nazara/Utility/Formats/PCXLoader.hpp index 2b83a8526..86e9dd8d4 100644 --- a/src/Nazara/Utility/Formats/PCXLoader.hpp +++ b/src/Nazara/Utility/Formats/PCXLoader.hpp @@ -8,14 +8,11 @@ #define NAZARA_LOADERS_PCX_HPP #include +#include -namespace Nz +namespace Nz::Loaders { - namespace Loaders - { - void RegisterPCX(); - void UnregisterPCX(); - } + ImageLoader::Entry GetImageLoader_PCX(); } #endif // NAZARA_LOADERS_PCX_HPP diff --git a/src/Nazara/Utility/Formats/STBLoader.cpp b/src/Nazara/Utility/Formats/STBLoader.cpp index 023572033..0d20bd6d3 100644 --- a/src/Nazara/Utility/Formats/STBLoader.cpp +++ b/src/Nazara/Utility/Formats/STBLoader.cpp @@ -3,13 +3,14 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include -#include #include #include #include #include #include #include +#define STB_IMAGE_IMPLEMENTATION +#include #include namespace Nz @@ -36,9 +37,9 @@ namespace Nz static stbi_io_callbacks callbacks = {Read, Skip, Eof}; - bool IsSupported(const std::string& extension) + bool IsSupported(const std::string_view& extension) { - static std::unordered_set supportedExtensions = {"bmp", "gif", "hdr", "jpg", "jpeg", "pic", "png", "ppm", "pgm", "psd", "tga"}; + static std::unordered_set supportedExtensions = {"bmp", "gif", "hdr", "jpg", "jpeg", "pic", "png", "ppm", "pgm", "psd", "tga"}; return supportedExtensions.find(extension) != supportedExtensions.end(); } @@ -46,16 +47,16 @@ namespace Nz { bool skip; if (parameters.custom.GetBooleanParameter("SkipNativeSTBLoader", &skip) && skip) - return Ternary_False; + return Ternary::False; int width, height, bpp; if (stbi_info_from_callbacks(&callbacks, &stream, &width, &height, &bpp)) - return Ternary_True; + return Ternary::True; else - return Ternary_False; + return Ternary::False; } - ImageRef Load(Stream& stream, const ImageParams& parameters) + std::shared_ptr Load(Stream& stream, const ImageParams& parameters) { // Je charge tout en RGBA8 et je converti ensuite via la méthode Convert // Ceci à cause d'un bug de STB lorsqu'il s'agit de charger certaines images (ex: JPG) en "default" @@ -65,7 +66,7 @@ namespace Nz if (!ptr) { NazaraError("Failed to load image: " + std::string(stbi_failure_reason())); - return nullptr; + return {}; } CallOnExit freeStbiImage([ptr]() @@ -73,19 +74,25 @@ namespace Nz stbi_image_free(ptr); }); - ImageRef image = Image::New(); - if (!image->Create(ImageType_2D, PixelFormat_RGBA8, width, height, 1, (parameters.levelCount > 0) ? parameters.levelCount : 1)) + std::shared_ptr image = std::make_shared(); + if (!image->Create(ImageType::E2D, PixelFormat::RGBA8, width, height, 1, (parameters.levelCount > 0) ? parameters.levelCount : 1)) { NazaraError("Failed to create image"); - return nullptr; + return {}; } image->Update(ptr); freeStbiImage.CallAndReset(); - if (parameters.loadFormat != PixelFormat_Undefined) - image->Convert(parameters.loadFormat); + if (parameters.loadFormat != PixelFormat::Undefined) + { + if (!image->Convert(parameters.loadFormat)) + { + NazaraError("Failed to convert image to required format"); + return {}; + } + } return image; } @@ -93,14 +100,14 @@ namespace Nz namespace Loaders { - void RegisterSTBLoader() + ImageLoader::Entry GetImageLoader_STB() { - ImageLoader::RegisterLoader(IsSupported, Check, Load); - } + ImageLoader::Entry loaderEntry; + loaderEntry.extensionSupport = IsSupported; + loaderEntry.streamChecker = Check; + loaderEntry.streamLoader = Load; - void UnregisterSTBLoader() - { - ImageLoader::UnregisterLoader(IsSupported, Check, Load); + return loaderEntry; } } } diff --git a/src/Nazara/Utility/Formats/STBLoader.hpp b/src/Nazara/Utility/Formats/STBLoader.hpp index e1e87b998..673fc7149 100644 --- a/src/Nazara/Utility/Formats/STBLoader.hpp +++ b/src/Nazara/Utility/Formats/STBLoader.hpp @@ -8,14 +8,11 @@ #define NAZARA_FORMATS_STBLOADER_HPP #include +#include -namespace Nz +namespace Nz::Loaders { - namespace Loaders - { - void RegisterSTBLoader(); - void UnregisterSTBLoader(); - } + ImageLoader::Entry GetImageLoader_STB(); } #endif // NAZARA_FORMATS_STBLOADER_HPP diff --git a/src/Nazara/Utility/Formats/STBSaver.cpp b/src/Nazara/Utility/Formats/STBSaver.cpp index 4dc30171a..bee72a675 100644 --- a/src/Nazara/Utility/Formats/STBSaver.cpp +++ b/src/Nazara/Utility/Formats/STBSaver.cpp @@ -2,11 +2,13 @@ // This file is part of the "Nazara Engine - Utility module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include #include #include #include +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include #include namespace Nz @@ -15,36 +17,36 @@ namespace Nz { using FormatHandler = bool(*)(const Image& image, const ImageParams& parameters, Stream& stream); - std::map s_formatHandlers; + std::map s_formatHandlers; int ConvertToFloatFormat(Image& image) { switch (image.GetFormat()) { - case PixelFormat_R32F: + case PixelFormat::R32F: return 1; - case PixelFormat_RG32F: + case PixelFormat::RG32F: return 2; - case PixelFormat_RGB32F: + case PixelFormat::RGB32F: return 3; - case PixelFormat_RGBA32F: + case PixelFormat::RGBA32F: return 4; default: { if (PixelFormatInfo::HasAlpha(image.GetFormat())) { - if (!image.Convert(PixelFormat_RGBA32F)) + if (!image.Convert(PixelFormat::RGBA32F)) break; return 4; } else { - if (!image.Convert(PixelFormat_RGB32F)) + if (!image.Convert(PixelFormat::RGB32F)) break; return 3; @@ -59,32 +61,32 @@ namespace Nz { switch (image.GetFormat()) { - case PixelFormat_L8: - case PixelFormat_R8: + case PixelFormat::L8: + case PixelFormat::R8: return 1; - case PixelFormat_LA8: - case PixelFormat_RG8: + case PixelFormat::LA8: + case PixelFormat::RG8: return 2; - case PixelFormat_RGB8: + case PixelFormat::RGB8: return 3; - case PixelFormat_RGBA8: + case PixelFormat::RGBA8: return 4; default: { if (PixelFormatInfo::HasAlpha(image.GetFormat())) { - if (!image.Convert(PixelFormat_RGBA8)) + if (!image.Convert(PixelFormat::RGBA8)) break; return 4; } else { - if (!image.Convert(PixelFormat_RGB8)) + if (!image.Convert(PixelFormat::RGB8)) break; return 3; @@ -102,7 +104,7 @@ namespace Nz throw std::runtime_error("Failed to write to stream"); } - bool FormatQuerier(const std::string& extension) + bool FormatQuerier(const std::string_view& extension) { return s_formatHandlers.find(extension) != s_formatHandlers.end(); } @@ -118,9 +120,9 @@ namespace Nz } ImageType type = image.GetType(); - if (type != ImageType_1D && type != ImageType_2D) + if (type != ImageType::E1D && type != ImageType::E2D) { - NazaraError("Image type 0x" + NumberToString(type, 16) + " is not in a supported format"); + NazaraError("Image type 0x" + NumberToString(UnderlyingCast(type), 16) + " is not in a supported format"); return false; } @@ -262,22 +264,20 @@ namespace Nz namespace Loaders { - void RegisterSTBSaver() + ImageSaver::Entry GetImageSaver_STB() { - s_formatHandlers["bmp"] = &SaveBMP; - s_formatHandlers["hdr"] = &SaveHDR; - s_formatHandlers["jpg"] = &SaveJPEG; + s_formatHandlers["bmp"] = &SaveBMP; + s_formatHandlers["hdr"] = &SaveHDR; + s_formatHandlers["jpg"] = &SaveJPEG; s_formatHandlers["jpeg"] = &SaveJPEG; - s_formatHandlers["png"] = &SavePNG; - s_formatHandlers["tga"] = &SaveTGA; + s_formatHandlers["png"] = &SavePNG; + s_formatHandlers["tga"] = &SaveTGA; - ImageSaver::RegisterSaver(FormatQuerier, SaveToStream); - } + ImageSaver::Entry entry; + entry.formatSupport = FormatQuerier; + entry.streamSaver = SaveToStream; - void UnregisterSTBSaver() - { - ImageSaver::UnregisterSaver(FormatQuerier, SaveToStream); - s_formatHandlers.clear(); + return entry; } } } diff --git a/src/Nazara/Utility/Formats/STBSaver.hpp b/src/Nazara/Utility/Formats/STBSaver.hpp index bb4ad5d1b..d459d4346 100644 --- a/src/Nazara/Utility/Formats/STBSaver.hpp +++ b/src/Nazara/Utility/Formats/STBSaver.hpp @@ -8,14 +8,11 @@ #define NAZARA_FORMATS_STBSAVER_HPP #include +#include -namespace Nz +namespace Nz::Loaders { - namespace Loaders - { - void RegisterSTBSaver(); - void UnregisterSTBSaver(); - } + ImageSaver::Entry GetImageSaver_STB(); } #endif // NAZARA_FORMATS_STBSAVER_HPP diff --git a/src/Nazara/Utility/GuillotineImageAtlas.cpp b/src/Nazara/Utility/GuillotineImageAtlas.cpp index ee1101c91..1876bbfa4 100644 --- a/src/Nazara/Utility/GuillotineImageAtlas.cpp +++ b/src/Nazara/Utility/GuillotineImageAtlas.cpp @@ -75,7 +75,7 @@ namespace Nz UInt32 GuillotineImageAtlas::GetStorage() const { - return DataStorage_Software; + return static_cast(DataStorage::Software); } bool GuillotineImageAtlas::Insert(const Image& image, Rectui* rect, bool* flipped, unsigned int* layerIndex) @@ -161,10 +161,10 @@ namespace Nz AbstractImage* GuillotineImageAtlas::ResizeImage(AbstractImage* oldImage, const Vector2ui& size) const { - std::unique_ptr newImage(new Image(ImageType_2D, PixelFormat_A8, size.x, size.y)); + std::unique_ptr newImage(new Image(ImageType::E2D, PixelFormat::A8, size.x, size.y)); if (oldImage) { - newImage->Copy(static_cast(oldImage), Rectui(size), Vector2ui(0, 0)); // Copie des anciennes données + newImage->Copy(static_cast(*oldImage), Rectui(size), Vector2ui(0, 0)); // Copie des anciennes données } return newImage.release(); diff --git a/src/Nazara/Utility/Image.cpp b/src/Nazara/Utility/Image.cpp index a74eab3cd..d81cdb9df 100644 --- a/src/Nazara/Utility/Image.cpp +++ b/src/Nazara/Utility/Image.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -46,7 +47,7 @@ namespace Nz Image::Image(ImageType type, PixelFormat format, unsigned int width, unsigned int height, unsigned int depth, UInt8 levelCount) : m_sharedImage(&emptyImage) { - ErrorFlags flags(ErrorFlag_ThrowException); + ErrorFlags flags(ErrorMode::ThrowException); Create(type, format, width, height, depth, levelCount); } @@ -66,8 +67,6 @@ namespace Nz Image::~Image() { - OnImageRelease(this); - Destroy(); } @@ -102,7 +101,7 @@ namespace Nz unsigned int height = m_sharedImage->height; // Les images 3D et cubemaps sont stockés de la même façon - unsigned int depth = (m_sharedImage->type == ImageType_Cubemap) ? 6 : m_sharedImage->depth; + unsigned int depth = (m_sharedImage->type == ImageType::Cubemap) ? 6 : m_sharedImage->depth; for (unsigned int i = 0; i < levels.size(); ++i) { @@ -132,7 +131,7 @@ namespace Nz if (height > 1) height >>= 1; - if (depth > 1 && m_sharedImage->type != ImageType_Cubemap) + if (depth > 1 && m_sharedImage->type != ImageType::Cubemap) depth >>= 1; } @@ -144,13 +143,13 @@ namespace Nz return true; } - void Image::Copy(const Image* source, const Boxui& srcBox, const Vector3ui& dstPos) + void Image::Copy(const Image& source, const Boxui& srcBox, const Vector3ui& dstPos) { - NazaraAssert(IsValid(), "Invalid image"); - NazaraAssert(source && source->IsValid(), "Invalid source image"); - NazaraAssert(source->GetFormat() == m_sharedImage->format, "Image formats don't match"); + NazaraAssert(IsValid(), "invalid image"); + NazaraAssert(source.IsValid(), "invalid source image"); + NazaraAssert(source.GetFormat() == m_sharedImage->format, "image formats don't match"); - const UInt8* srcPtr = source->GetConstPixels(srcBox.x, srcBox.y, srcBox.z); + const UInt8* srcPtr = source.GetConstPixels(srcBox.x, srcBox.y, srcBox.z); #if NAZARA_UTILITY_SAFE if (!srcPtr) { @@ -162,7 +161,7 @@ namespace Nz UInt8 bpp = PixelFormatInfo::GetBytesPerPixel(m_sharedImage->format); UInt8* dstPtr = GetPixelPtr(m_sharedImage->levels[0].get(), bpp, dstPos.x, dstPos.y, dstPos.z, m_sharedImage->width, m_sharedImage->height); - Copy(dstPtr, srcPtr, m_sharedImage->format, srcBox.width, srcBox.height, srcBox.depth, m_sharedImage->width, m_sharedImage->height, source->GetWidth(), source->GetHeight()); + Copy(dstPtr, srcPtr, m_sharedImage->format, srcBox.width, srcBox.height, srcBox.depth, m_sharedImage->width, m_sharedImage->height, source.GetWidth(), source.GetHeight()); } bool Image::Create(ImageType type, PixelFormat format, unsigned int width, unsigned int height, unsigned int depth, UInt8 levelCount) @@ -196,7 +195,7 @@ namespace Nz switch (type) { - case ImageType_1D: + case ImageType::E1D: if (height > 1) { NazaraError("1D textures must be 1 tall"); @@ -210,8 +209,8 @@ namespace Nz } break; - case ImageType_1D_Array: - case ImageType_2D: + case ImageType::E1D_Array: + case ImageType::E2D: if (depth > 1) { NazaraError("2D textures must be 1 deep"); @@ -219,11 +218,11 @@ namespace Nz } break; - case ImageType_2D_Array: - case ImageType_3D: + case ImageType::E2D_Array: + case ImageType::E3D: break; - case ImageType_Cubemap: + case ImageType::Cubemap: if (depth > 1) { NazaraError("Cubemaps must be 1 deep"); @@ -249,7 +248,7 @@ namespace Nz unsigned int w = width; unsigned int h = height; - unsigned int d = (type == ImageType_Cubemap) ? 6 : depth; + unsigned int d = (type == ImageType::Cubemap) ? 6 : depth; for (unsigned int i = 0; i < levelCount; ++i) { @@ -264,7 +263,7 @@ namespace Nz if (h > 1) h >>= 1; - if (d > 1 && type != ImageType_Cubemap) + if (d > 1 && type != ImageType::Cubemap) d >>= 1; } catch (const std::exception& e) @@ -282,10 +281,7 @@ namespace Nz void Image::Destroy() { if (m_sharedImage != &emptyImage) - { - OnImageDestroy(this); ReleaseImage(); - } } bool Image::Fill(const Color& color) @@ -308,7 +304,7 @@ namespace Nz UInt8 bpp = PixelFormatInfo::GetBytesPerPixel(m_sharedImage->format); std::unique_ptr colorBuffer(new UInt8[bpp]); - if (!PixelFormatInfo::Convert(PixelFormat_RGBA8, m_sharedImage->format, &color.r, colorBuffer.get())) + if (!PixelFormatInfo::Convert(PixelFormat::RGBA8, m_sharedImage->format, &color.r, colorBuffer.get())) { NazaraError("Failed to convert RGBA8 to " + PixelFormatInfo::GetName(m_sharedImage->format)); return false; @@ -320,7 +316,7 @@ namespace Nz unsigned int height = m_sharedImage->height; // Les images 3D et cubemaps sont stockés de la même façon - unsigned int depth = (m_sharedImage->type == ImageType_Cubemap) ? 6 : m_sharedImage->depth; + unsigned int depth = (m_sharedImage->type == ImageType::Cubemap) ? 6 : m_sharedImage->depth; for (auto & level : levels) { @@ -342,7 +338,7 @@ namespace Nz if (height > 1U) height >>= 1; - if (depth > 1U && m_sharedImage->type != ImageType_Cubemap) + if (depth > 1U && m_sharedImage->type != ImageType::Cubemap) depth >>= 1; } @@ -386,7 +382,7 @@ namespace Nz UInt8 bpp = PixelFormatInfo::GetBytesPerPixel(m_sharedImage->format); std::unique_ptr colorBuffer(new UInt8[bpp]); - if (!PixelFormatInfo::Convert(PixelFormat_RGBA8, m_sharedImage->format, &color.r, colorBuffer.get())) + if (!PixelFormatInfo::Convert(PixelFormat::RGBA8, m_sharedImage->format, &color.r, colorBuffer.get())) { NazaraError("Failed to convert RGBA8 to " + PixelFormatInfo::GetName(m_sharedImage->format)); return false; @@ -446,7 +442,7 @@ namespace Nz return false; } - unsigned int depth = (m_sharedImage->type == ImageType_Cubemap) ? 6 : m_sharedImage->depth; + unsigned int depth = (m_sharedImage->type == ImageType::Cubemap) ? 6 : m_sharedImage->depth; if (z >= depth) { NazaraError("Z value exceeds depth (" + NumberToString(z) + " >= " + NumberToString(depth) + ')'); @@ -458,7 +454,7 @@ namespace Nz UInt8 bpp = PixelFormatInfo::GetBytesPerPixel(m_sharedImage->format); std::unique_ptr colorBuffer(new UInt8[bpp]); - if (!PixelFormatInfo::Convert(PixelFormat_RGBA8, m_sharedImage->format, &color.r, colorBuffer.get())) + if (!PixelFormatInfo::Convert(PixelFormat::RGBA8, m_sharedImage->format, &color.r, colorBuffer.get())) { NazaraError("Failed to convert RGBA8 to " + PixelFormatInfo::GetName(m_sharedImage->format)); return false; @@ -498,11 +494,11 @@ namespace Nz unsigned int width = m_sharedImage->width; unsigned int height = m_sharedImage->height; - unsigned int depth = (m_sharedImage->type == ImageType_Cubemap) ? 6 : m_sharedImage->depth; + unsigned int depth = (m_sharedImage->type == ImageType::Cubemap) ? 6 : m_sharedImage->depth; for (auto& level : m_sharedImage->levels) { UInt8* ptr = level.get(); - if (!PixelFormatInfo::Flip(PixelFlipping_Horizontally, m_sharedImage->format, width, height, depth, ptr, ptr)) + if (!PixelFormatInfo::Flip(PixelFlipping::Horizontally, m_sharedImage->format, width, height, depth, ptr, ptr)) { NazaraError("Failed to flip image"); return false; @@ -514,7 +510,7 @@ namespace Nz if (height > 1U) height >>= 1; - if (depth > 1U && m_sharedImage->type != ImageType_Cubemap) + if (depth > 1U && m_sharedImage->type != ImageType::Cubemap) depth >>= 1; } @@ -541,11 +537,11 @@ namespace Nz unsigned int width = m_sharedImage->width; unsigned int height = m_sharedImage->height; - unsigned int depth = (m_sharedImage->type == ImageType_Cubemap) ? 6 : m_sharedImage->depth; + unsigned int depth = (m_sharedImage->type == ImageType::Cubemap) ? 6 : m_sharedImage->depth; for (auto& level : m_sharedImage->levels) { UInt8* ptr = level.get(); - if (!PixelFormatInfo::Flip(PixelFlipping_Vertically, m_sharedImage->format, width, height, depth, ptr, ptr)) + if (!PixelFormatInfo::Flip(PixelFlipping::Vertically, m_sharedImage->format, width, height, depth, ptr, ptr)) { NazaraError("Failed to flip image"); return false; @@ -557,7 +553,7 @@ namespace Nz if (height > 1U) height >>= 1; - if (depth > 1U && m_sharedImage->type != ImageType_Cubemap) + if (depth > 1U && m_sharedImage->type != ImageType::Cubemap) depth >>= 1; } @@ -597,7 +593,7 @@ namespace Nz return nullptr; } - unsigned int depth = (m_sharedImage->type == ImageType_Cubemap) ? 6 : GetLevelSize(m_sharedImage->depth, level); + unsigned int depth = (m_sharedImage->type == ImageType::Cubemap) ? 6 : GetLevelSize(m_sharedImage->depth, level); if (z >= depth) { NazaraError("Z value exceeds depth (" + NumberToString(z) + " >= " + NumberToString(depth) + ')'); @@ -670,7 +666,7 @@ namespace Nz depth >>= 1; } - if (m_sharedImage->type == ImageType_Cubemap) + if (m_sharedImage->type == ImageType::Cubemap) size *= 6; return size * PixelFormatInfo::GetBytesPerPixel(m_sharedImage->format); @@ -678,7 +674,7 @@ namespace Nz std::size_t Image::GetMemoryUsage(UInt8 level) const { - return PixelFormatInfo::ComputeSize(m_sharedImage->format, GetLevelSize(m_sharedImage->width, level), GetLevelSize(m_sharedImage->height, level), ((m_sharedImage->type == ImageType_Cubemap) ? 6 : GetLevelSize(m_sharedImage->depth, level))); + return PixelFormatInfo::ComputeSize(m_sharedImage->format, GetLevelSize(m_sharedImage->width, level), GetLevelSize(m_sharedImage->height, level), ((m_sharedImage->type == ImageType::Cubemap) ? 6 : GetLevelSize(m_sharedImage->depth, level))); } Color Image::GetPixelColor(unsigned int x, unsigned int y, unsigned int z) const @@ -708,7 +704,7 @@ namespace Nz return Color(); } - unsigned int depth = (m_sharedImage->type == ImageType_Cubemap) ? 6 : m_sharedImage->depth; + unsigned int depth = (m_sharedImage->type == ImageType::Cubemap) ? 6 : m_sharedImage->depth; if (z >= depth) { NazaraError("Z value exceeds depth (" + NumberToString(z) + " >= " + NumberToString(depth) + ')'); @@ -719,7 +715,7 @@ namespace Nz const UInt8* pixel = GetPixelPtr(m_sharedImage->levels[0].get(), PixelFormatInfo::GetBytesPerPixel(m_sharedImage->format), x, y, z, m_sharedImage->width, m_sharedImage->height); Color color; - if (!PixelFormatInfo::Convert(m_sharedImage->format, PixelFormat_RGBA8, pixel, &color.r)) + if (!PixelFormatInfo::Convert(m_sharedImage->format, PixelFormat::RGBA8, pixel, &color.r)) NazaraError("Failed to convert image's format to RGBA8"); return color; @@ -758,7 +754,7 @@ namespace Nz return nullptr; } - unsigned int depth = (m_sharedImage->type == ImageType_Cubemap) ? 6 : GetLevelSize(m_sharedImage->depth, level); + unsigned int depth = (m_sharedImage->type == ImageType::Cubemap) ? 6 : GetLevelSize(m_sharedImage->depth, level); if (z >= depth) { NazaraError("Z value exceeds depth (" + NumberToString(z) + " >= " + NumberToString(depth) + ')'); @@ -820,7 +816,7 @@ namespace Nz const PixelFormatDescription& info = PixelFormatInfo::GetInfo(m_sharedImage->format); Bitset<> workingBitset; - std::size_t pixelCount = m_sharedImage->width * m_sharedImage->height * ((m_sharedImage->type == ImageType_Cubemap) ? 6 : m_sharedImage->depth); + std::size_t pixelCount = m_sharedImage->width * m_sharedImage->height * ((m_sharedImage->type == ImageType::Cubemap) ? 6 : m_sharedImage->depth); if (pixelCount == 0) return false; @@ -851,21 +847,21 @@ namespace Nz } // LoadArray - ImageRef Image::LoadArrayFromFile(const std::filesystem::path& filePath, const ImageParams& imageParams, const Vector2ui& atlasSize) + std::shared_ptr Image::LoadArrayFromFile(const std::filesystem::path& filePath, const ImageParams& imageParams, const Vector2ui& atlasSize) { - ImageRef image = Image::LoadFromFile(filePath, imageParams); + std::shared_ptr image = Image::LoadFromFile(filePath, imageParams); if (!image) { NazaraError("Failed to load image"); return nullptr; } - return LoadArrayFromImage(image, atlasSize); + return LoadArrayFromImage(*image, atlasSize); } - ImageRef Image::LoadArrayFromImage(const Image* image, const Vector2ui& atlasSize) + std::shared_ptr Image::LoadArrayFromImage(const Image& image, const Vector2ui& atlasSize) { - NazaraAssert(image && image->IsValid(), "Invalid image"); + NazaraAssert(image.IsValid(), "Invalid image"); #if NAZARA_UTILITY_SAFE if (atlasSize.x == 0) @@ -881,17 +877,17 @@ namespace Nz } #endif - ImageType type = image->GetType(); + ImageType type = image.GetType(); #if NAZARA_UTILITY_SAFE - if (type != ImageType_1D && type != ImageType_2D) + if (type != ImageType::E1D && type != ImageType::E2D) { - NazaraError("Image type not handled (0x" + NumberToString(type, 16) + ')'); + NazaraError("Image type not handled (0x" + NumberToString(UnderlyingCast(type), 16) + ')'); return nullptr; } #endif - Vector2ui imageSize(image->GetWidth(), image->GetHeight()); + Vector2ui imageSize(image.GetWidth(), image.GetHeight()); if (imageSize.x % atlasSize.x != 0) { @@ -907,12 +903,12 @@ namespace Nz unsigned int layerCount = atlasSize.x*atlasSize.y; - ImageRef arrayImage = New(); + std::shared_ptr arrayImage = std::make_shared(); // Selon le type de l'image de base, on va créer un array d'images 2D ou 1D - if (type == ImageType_2D) - arrayImage->Create(ImageType_2D_Array, image->GetFormat(), faceSize.x, faceSize.y, layerCount); + if (type == ImageType::E2D) + arrayImage->Create(ImageType::E2D_Array, image.GetFormat(), faceSize.x, faceSize.y, layerCount); else - arrayImage->Create(ImageType_1D_Array, image->GetFormat(), faceSize.x, layerCount); + arrayImage->Create(ImageType::E1D_Array, image.GetFormat(), faceSize.x, layerCount); if (!arrayImage->IsValid()) { @@ -928,57 +924,57 @@ namespace Nz return arrayImage; } - ImageRef Image::LoadArrayFromMemory(const void* data, std::size_t size, const ImageParams& imageParams, const Vector2ui& atlasSize) + std::shared_ptr Image::LoadArrayFromMemory(const void* data, std::size_t size, const ImageParams& imageParams, const Vector2ui& atlasSize) { - ImageRef image = Image::LoadFromMemory(data, size, imageParams); + std::shared_ptr image = Image::LoadFromMemory(data, size, imageParams); if (!image) { NazaraError("Failed to load image"); return nullptr; } - return LoadArrayFromImage(image, atlasSize); + return LoadArrayFromImage(*image, atlasSize); } - ImageRef Image::LoadArrayFromStream(Stream& stream, const ImageParams& imageParams, const Vector2ui& atlasSize) + std::shared_ptr Image::LoadArrayFromStream(Stream& stream, const ImageParams& imageParams, const Vector2ui& atlasSize) { - ImageRef image = Image::LoadFromStream(stream, imageParams); + std::shared_ptr image = Image::LoadFromStream(stream, imageParams); if (!image) { NazaraError("Failed to load image"); return nullptr; } - return LoadArrayFromImage(image, atlasSize); + return LoadArrayFromImage(*image, atlasSize); } - ImageRef Image::LoadCubemapFromFile(const std::filesystem::path& filePath, const ImageParams& imageParams, const CubemapParams& cubemapParams) + std::shared_ptr Image::LoadCubemapFromFile(const std::filesystem::path& filePath, const ImageParams& imageParams, const CubemapParams& cubemapParams) { - ImageRef image = Image::LoadFromFile(filePath, imageParams); + std::shared_ptr image = Image::LoadFromFile(filePath, imageParams); if (!image) { NazaraError("Failed to load image"); return nullptr; } - return LoadCubemapFromImage(image, cubemapParams); + return LoadCubemapFromImage(*image, cubemapParams); } - ImageRef Image::LoadCubemapFromImage(const Image* image, const CubemapParams& params) + std::shared_ptr Image::LoadCubemapFromImage(const Image& image, const CubemapParams& params) { - NazaraAssert(image && image->IsValid(), "Invalid image"); + NazaraAssert(image.IsValid(), "Invalid image"); #if NAZARA_UTILITY_SAFE - ImageType type = image->GetType(); - if (type != ImageType_2D) + ImageType type = image.GetType(); + if (type != ImageType::E2D) { - NazaraError("Image type not handled (0x" + NumberToString(type, 16) + ')'); + NazaraError("Image type not handled (0x" + NumberToString(UnderlyingCast(type), 16) + ')'); return nullptr; } #endif - unsigned int width = image->GetWidth(); - unsigned int height = image->GetHeight(); + unsigned int width = image.GetWidth(); + unsigned int height = image.GetHeight(); unsigned int faceSize = (params.faceSize == 0) ? std::max(width, height)/4 : params.faceSize; // Sans cette vérification, celles des rectangles pourrait réussir via un overflow @@ -1034,52 +1030,52 @@ namespace Nz return nullptr; } - ImageRef cubemap = New(); - if (!cubemap->Create(ImageType_Cubemap, image->GetFormat(), faceSize, faceSize)) + std::shared_ptr cubemap = std::make_shared(); + if (!cubemap->Create(ImageType::Cubemap, image.GetFormat(), faceSize, faceSize)) { NazaraError("Failed to create cubemap"); return nullptr; } - cubemap->Copy(image, Rectui(backPos.x, backPos.y, faceSize, faceSize), Vector3ui(0, 0, CubemapFace_NegativeZ)); - cubemap->Copy(image, Rectui(downPos.x, downPos.y, faceSize, faceSize), Vector3ui(0, 0, CubemapFace_NegativeY)); - cubemap->Copy(image, Rectui(forwardPos.x, forwardPos.y, faceSize, faceSize), Vector3ui(0, 0, CubemapFace_PositiveZ)); - cubemap->Copy(image, Rectui(leftPos.x, leftPos.y, faceSize, faceSize), Vector3ui(0, 0, CubemapFace_NegativeX)); - cubemap->Copy(image, Rectui(rightPos.x, rightPos.y, faceSize, faceSize), Vector3ui(0, 0, CubemapFace_PositiveX)); - cubemap->Copy(image, Rectui(upPos.x, upPos.y, faceSize, faceSize), Vector3ui(0, 0, CubemapFace_PositiveY)); + cubemap->Copy(image, Rectui(backPos.x, backPos.y, faceSize, faceSize), Vector3ui(0, 0, UnderlyingCast(CubemapFace::NegativeZ))); + cubemap->Copy(image, Rectui(downPos.x, downPos.y, faceSize, faceSize), Vector3ui(0, 0, UnderlyingCast(CubemapFace::NegativeY))); + cubemap->Copy(image, Rectui(forwardPos.x, forwardPos.y, faceSize, faceSize), Vector3ui(0, 0, UnderlyingCast(CubemapFace::PositiveZ))); + cubemap->Copy(image, Rectui(leftPos.x, leftPos.y, faceSize, faceSize), Vector3ui(0, 0, UnderlyingCast(CubemapFace::NegativeX))); + cubemap->Copy(image, Rectui(rightPos.x, rightPos.y, faceSize, faceSize), Vector3ui(0, 0, UnderlyingCast(CubemapFace::PositiveX))); + cubemap->Copy(image, Rectui(upPos.x, upPos.y, faceSize, faceSize), Vector3ui(0, 0, UnderlyingCast(CubemapFace::PositiveY))); return cubemap; } - ImageRef Image::LoadCubemapFromMemory(const void* data, std::size_t size, const ImageParams& imageParams, const CubemapParams& cubemapParams) + std::shared_ptr Image::LoadCubemapFromMemory(const void* data, std::size_t size, const ImageParams& imageParams, const CubemapParams& cubemapParams) { - ImageRef image = Image::LoadFromMemory(data, size, imageParams); + std::shared_ptr image = Image::LoadFromMemory(data, size, imageParams); if (!image) { NazaraError("Failed to load image"); return nullptr; } - return LoadCubemapFromImage(image, cubemapParams); + return LoadCubemapFromImage(*image, cubemapParams); } - ImageRef Image::LoadCubemapFromStream(Stream& stream, const ImageParams& imageParams, const CubemapParams& cubemapParams) + std::shared_ptr Image::LoadCubemapFromStream(Stream& stream, const ImageParams& imageParams, const CubemapParams& cubemapParams) { - ImageRef image = Image::LoadFromStream(stream, imageParams); + std::shared_ptr image = Image::LoadFromStream(stream, imageParams); if (!image) { NazaraError("Failed to load image"); return nullptr; } - return LoadCubemapFromImage(image, cubemapParams); + return LoadCubemapFromImage(*image, cubemapParams); } bool Image::LoadFaceFromFile(CubemapFace face, const std::filesystem::path& filePath, const ImageParams& params) { NazaraAssert(IsValid() && IsCubemap(), "Texture must be a valid cubemap"); - ImageRef image = Image::LoadFromFile(filePath, params); + std::shared_ptr image = Image::LoadFromFile(filePath, params); if (!image) { NazaraError("Failed to load image"); @@ -1099,7 +1095,7 @@ namespace Nz return false; } - Copy(image, Rectui(0, 0, faceSize, faceSize), Vector3ui(0, 0, face)); + Copy(*image, Rectui(0, 0, faceSize, faceSize), Vector3ui(0, 0, UnderlyingCast(face))); return true; } @@ -1107,7 +1103,7 @@ namespace Nz { NazaraAssert(IsValid() && IsCubemap(), "Texture must be a valid cubemap"); - ImageRef image = Image::LoadFromMemory(data, size, params); + std::shared_ptr image = Image::LoadFromMemory(data, size, params); if (!image) { NazaraError("Failed to load image"); @@ -1127,7 +1123,7 @@ namespace Nz return false; } - Copy(image, Rectui(0, 0, faceSize, faceSize), Vector3ui(0, 0, face)); + Copy(*image, Rectui(0, 0, faceSize, faceSize), Vector3ui(0, 0, UnderlyingCast(face))); return true; } @@ -1135,7 +1131,7 @@ namespace Nz { NazaraAssert(IsValid() && IsCubemap(), "Texture must be a valid cubemap"); - ImageRef image = Image::LoadFromStream(stream, params); + std::shared_ptr image = Image::LoadFromStream(stream, params); if (!image) { NazaraError("Failed to load image"); @@ -1155,18 +1151,24 @@ namespace Nz return false; } - Copy(image, Rectui(0, 0, faceSize, faceSize), Vector3ui(0, 0, face)); + Copy(*image, Rectui(0, 0, faceSize, faceSize), Vector3ui(0, 0, UnderlyingCast(face))); return true; } bool Image::SaveToFile(const std::filesystem::path& filePath, const ImageParams& params) { - return ImageSaver::SaveToFile(*this, filePath, params); + Utility* utility = Utility::Instance(); + NazaraAssert(utility, "Utility module has not been initialized"); + + return utility->GetImageSaver().SaveToFile(*this, filePath, params); } bool Image::SaveToStream(Stream& stream, const std::string& format, const ImageParams& params) { - return ImageSaver::SaveToStream(*this, stream, format, params); + Utility* utility = Utility::Instance(); + NazaraAssert(utility, "Utility module has not been initialized"); + + return utility->GetImageSaver().SaveToStream(*this, stream, format, params); } void Image::SetLevelCount(UInt8 levelCount) @@ -1227,7 +1229,7 @@ namespace Nz return false; } - unsigned int depth = (m_sharedImage->type == ImageType_Cubemap) ? 6 : m_sharedImage->depth; + unsigned int depth = (m_sharedImage->type == ImageType::Cubemap) ? 6 : m_sharedImage->depth; if (z >= depth) { NazaraError("Z value exceeds depth (" + NumberToString(z) + " >= " + NumberToString(depth) + ')'); @@ -1237,7 +1239,7 @@ namespace Nz UInt8* pixel = GetPixelPtr(m_sharedImage->levels[0].get(), PixelFormatInfo::GetBytesPerPixel(m_sharedImage->format), x, y, z, m_sharedImage->width, m_sharedImage->height); - if (!PixelFormatInfo::Convert(PixelFormat_RGBA8, m_sharedImage->format, &color.r, pixel)) + if (!PixelFormatInfo::Convert(PixelFormat::RGBA8, m_sharedImage->format, &color.r, pixel)) { NazaraError("Failed to convert RGBA8 to image's format"); return false; @@ -1312,9 +1314,9 @@ namespace Nz return false; } - unsigned int depth = (m_sharedImage->type == ImageType_Cubemap) ? 6 : GetLevelSize(m_sharedImage->depth, level); + unsigned int depth = (m_sharedImage->type == ImageType::Cubemap) ? 6 : GetLevelSize(m_sharedImage->depth, level); if (box.x+box.width > width || box.y+box.height > height || box.z+box.depth > depth || - (m_sharedImage->type == ImageType_Cubemap && box.depth > 1)) // Nous n'autorisons pas de modifier plus d'une face du cubemap à la fois + (m_sharedImage->type == ImageType::Cubemap && box.depth > 1)) // Nous n'autorisons pas de modifier plus d'une face du cubemap à la fois { NazaraError("Box dimensions are out of bounds"); return false; @@ -1413,36 +1415,45 @@ namespace Nz // Pour éviter que la profondeur ne soit comptée dans le calcul des niveaux switch (type) { - case ImageType_1D: - case ImageType_1D_Array: + case ImageType::E1D: + case ImageType::E1D_Array: return GetMaxLevel(width, 1U, 1U); - case ImageType_2D: - case ImageType_2D_Array: - case ImageType_Cubemap: + case ImageType::E2D: + case ImageType::E2D_Array: + case ImageType::Cubemap: return GetMaxLevel(width, height, 1U); - case ImageType_3D: + case ImageType::E3D: return GetMaxLevel(width, height, depth); } - NazaraError("Image type not handled (0x" + NumberToString(type, 16) + ')'); + NazaraError("Image type not handled (0x" + NumberToString(UnderlyingCast(type), 16) + ')'); return 0; } - ImageRef Image::LoadFromFile(const std::filesystem::path& filePath, const ImageParams& params) + std::shared_ptr Image::LoadFromFile(const std::filesystem::path& filePath, const ImageParams& params) { - return ImageLoader::LoadFromFile(filePath, params); + Utility* utility = Utility::Instance(); + NazaraAssert(utility, "Utility module has not been initialized"); + + return utility->GetImageLoader().LoadFromFile(filePath, params); } - ImageRef Image::LoadFromMemory(const void* data, std::size_t size, const ImageParams& params) + std::shared_ptr Image::LoadFromMemory(const void* data, std::size_t size, const ImageParams& params) { - return ImageLoader::LoadFromMemory(data, size, params); + Utility* utility = Utility::Instance(); + NazaraAssert(utility, "Utility module has not been initialized"); + + return utility->GetImageLoader().LoadFromMemory(data, size, params); } - ImageRef Image::LoadFromStream(Stream& stream, const ImageParams& params) + std::shared_ptr Image::LoadFromStream(Stream& stream, const ImageParams& params) { - return ImageLoader::LoadFromStream(stream, params); + Utility* utility = Utility::Instance(); + NazaraAssert(utility, "Utility module has not been initialized"); + + return utility->GetImageLoader().LoadFromStream(stream, params); } void Image::EnsureOwnership() @@ -1476,33 +1487,5 @@ namespace Nz m_sharedImage = &emptyImage; } - bool Image::Initialize() - { - if (!ImageLibrary::Initialize()) - { - NazaraError("Failed to initialise library"); - return false; - } - - if (!ImageManager::Initialize()) - { - NazaraError("Failed to initialise manager"); - return false; - } - - return true; - } - - void Image::Uninitialize() - { - ImageManager::Uninitialize(); - ImageLibrary::Uninitialize(); - } - - Image::SharedImage Image::emptyImage(0, ImageType_2D, PixelFormat_Undefined, Image::SharedImage::PixelContainer(), 0, 0, 0); - ImageLibrary::LibraryMap Image::s_library; - ImageLoader::LoaderList Image::s_loaders; - ImageManager::ManagerMap Image::s_managerMap; - ImageManager::ManagerParams Image::s_managerParameters; - ImageSaver::SaverList Image::s_savers; + Image::SharedImage Image::emptyImage(0, ImageType::E2D, PixelFormat::Undefined, Image::SharedImage::PixelContainer(), 0, 0, 0); } diff --git a/src/Nazara/Utility/IndexBuffer.cpp b/src/Nazara/Utility/IndexBuffer.cpp index b0cadc27c..79cffaf2f 100644 --- a/src/Nazara/Utility/IndexBuffer.cpp +++ b/src/Nazara/Utility/IndexBuffer.cpp @@ -13,42 +13,27 @@ namespace Nz { - IndexBuffer::IndexBuffer(bool largeIndices, BufferRef buffer) + IndexBuffer::IndexBuffer(bool largeIndices, std::shared_ptr buffer) { - ErrorFlags(ErrorFlag_ThrowException, true); + ErrorFlags(ErrorMode::ThrowException, true); Reset(largeIndices, std::move(buffer)); } - IndexBuffer::IndexBuffer(bool largeIndices, BufferRef buffer, std::size_t offset, std::size_t size) + IndexBuffer::IndexBuffer(bool largeIndices, std::shared_ptr buffer, std::size_t offset, std::size_t size) { - ErrorFlags(ErrorFlag_ThrowException, true); + ErrorFlags(ErrorMode::ThrowException, true); Reset(largeIndices, std::move(buffer), offset, size); } IndexBuffer::IndexBuffer(bool largeIndices, std::size_t length, DataStorage storage, BufferUsageFlags usage) { - ErrorFlags(ErrorFlag_ThrowException, true); + ErrorFlags(ErrorMode::ThrowException, true); Reset(largeIndices, length, storage, usage); } - IndexBuffer::IndexBuffer(const IndexBuffer& indexBuffer) : - RefCounted(), - m_buffer(indexBuffer.m_buffer), - m_endOffset(indexBuffer.m_endOffset), - m_indexCount(indexBuffer.m_indexCount), - m_startOffset(indexBuffer.m_startOffset), - m_largeIndices(indexBuffer.m_largeIndices) - { - } - - IndexBuffer::~IndexBuffer() - { - OnIndexBufferRelease(this); - } - unsigned int IndexBuffer::ComputeCacheMissCount() const { - IndexMapper mapper(this); + IndexMapper mapper(*this); return Nz::ComputeCacheMissCount(mapper.begin(), m_indexCount); } @@ -86,27 +71,27 @@ namespace Nz void IndexBuffer::Optimize() { - IndexMapper mapper(this); + IndexMapper mapper(*this); OptimizeIndices(mapper.begin(), m_indexCount); } void IndexBuffer::Reset() { - m_buffer.Reset(); + m_buffer.reset(); } - void IndexBuffer::Reset(bool largeIndices, BufferRef buffer) + void IndexBuffer::Reset(bool largeIndices, std::shared_ptr buffer) { NazaraAssert(buffer && buffer->IsValid(), "Invalid buffer"); Reset(largeIndices, buffer, 0, buffer->GetSize()); } - void IndexBuffer::Reset(bool largeIndices, BufferRef buffer, std::size_t offset, std::size_t size) + void IndexBuffer::Reset(bool largeIndices, std::shared_ptr buffer, std::size_t offset, std::size_t size) { NazaraAssert(buffer && buffer->IsValid(), "Invalid buffer"); - NazaraAssert(buffer->GetType() == BufferType_Index, "Buffer must be an index buffer"); + NazaraAssert(buffer->GetType() == BufferType::Index, "Buffer must be an index buffer"); NazaraAssert(size > 0, "Invalid size"); NazaraAssert(offset + size > buffer->GetSize(), "Virtual buffer exceed buffer bounds"); @@ -128,7 +113,7 @@ namespace Nz m_largeIndices = largeIndices; m_startOffset = 0; - m_buffer = Buffer::New(BufferType_Index, m_endOffset, storage, usage); + m_buffer = std::make_shared(BufferType::Index, m_endOffset, storage, usage); } void IndexBuffer::Reset(const IndexBuffer& indexBuffer) @@ -144,11 +129,4 @@ namespace Nz { m_buffer->Unmap(); } - - IndexBuffer& IndexBuffer::operator=(const IndexBuffer& indexBuffer) - { - Reset(indexBuffer); - - return *this; - } } diff --git a/src/Nazara/Utility/IndexMapper.cpp b/src/Nazara/Utility/IndexMapper.cpp index 7bc0ecb1e..efdfb921d 100644 --- a/src/Nazara/Utility/IndexMapper.cpp +++ b/src/Nazara/Utility/IndexMapper.cpp @@ -49,67 +49,50 @@ namespace Nz } } - IndexMapper::IndexMapper(IndexBuffer* indexBuffer, BufferAccess access, std::size_t indexCount) : - m_indexCount((indexCount != 0) ? indexCount : indexBuffer->GetIndexCount()) + IndexMapper::IndexMapper(IndexBuffer& indexBuffer, BufferAccess access, std::size_t indexCount) : + m_indexCount((indexCount != 0) ? indexCount : indexBuffer.GetIndexCount()) { - NazaraAssert(indexCount != 0 || indexBuffer, "Invalid index count with invalid index buffer"); + if (!m_mapper.Map(indexBuffer, access)) + NazaraError("Failed to map buffer"); ///TODO: Unexcepted - if (indexBuffer) + if (indexBuffer.HasLargeIndices()) { - if (!m_mapper.Map(indexBuffer, access)) - NazaraError("Failed to map buffer"); ///TODO: Unexcepted - - if (indexBuffer->HasLargeIndices()) - { - m_getter = Getter32; - if (access != BufferAccess_ReadOnly) - m_setter = Setter32; - else - m_setter = SetterError; - } + m_getter = Getter32; + if (access != BufferAccess::ReadOnly) + m_setter = Setter32; else - { - m_getter = Getter16; - if (access != BufferAccess_ReadOnly) - m_setter = Setter16; - else - m_setter = SetterError; - } + m_setter = SetterError; } else { - m_getter = GetterSequential; - m_setter = SetterError; + m_getter = Getter16; + if (access != BufferAccess::ReadOnly) + m_setter = Setter16; + else + m_setter = SetterError; } } - IndexMapper::IndexMapper(SubMesh* subMesh, BufferAccess access) : - IndexMapper(subMesh->GetIndexBuffer(), access, (subMesh->GetIndexBuffer()) ? 0 : subMesh->GetVertexCount()) + IndexMapper::IndexMapper(SubMesh& subMesh, BufferAccess access) : + IndexMapper(*subMesh.GetIndexBuffer(), access, (subMesh.GetIndexBuffer()) ? 0 : subMesh.GetVertexCount()) { } - IndexMapper::IndexMapper(const IndexBuffer* indexBuffer, BufferAccess access, std::size_t indexCount) : + IndexMapper::IndexMapper(const IndexBuffer& indexBuffer, BufferAccess access, std::size_t indexCount) : m_setter(SetterError), - m_indexCount((indexCount != 0) ? indexCount : indexBuffer->GetIndexCount()) + m_indexCount((indexCount != 0) ? indexCount : indexBuffer.GetIndexCount()) { - NazaraAssert(indexCount != 0 || indexBuffer, "Invalid index count with invalid index buffer"); + if (!m_mapper.Map(indexBuffer, access)) + NazaraError("Failed to map buffer"); ///TODO: Unexcepted - if (indexBuffer) - { - if (!m_mapper.Map(indexBuffer, access)) - NazaraError("Failed to map buffer"); ///TODO: Unexcepted - - if (indexBuffer->HasLargeIndices()) - m_getter = Getter32; - else - m_getter = Getter16; - } + if (indexBuffer.HasLargeIndices()) + m_getter = Getter32; else - m_getter = GetterSequential; + m_getter = Getter16; } - IndexMapper::IndexMapper(const SubMesh* subMesh, BufferAccess access) : - IndexMapper(subMesh->GetIndexBuffer(), access, (subMesh->GetIndexBuffer()) ? 0 : subMesh->GetVertexCount()) + IndexMapper::IndexMapper(const SubMesh& subMesh, BufferAccess access) : + IndexMapper(*subMesh.GetIndexBuffer(), access, (subMesh.GetIndexBuffer()) ? 0 : subMesh.GetVertexCount()) { } diff --git a/src/Nazara/Utility/Mesh.cpp b/src/Nazara/Utility/Mesh.cpp index 38ddcc512..93e5a08d9 100644 --- a/src/Nazara/Utility/Mesh.cpp +++ b/src/Nazara/Utility/Mesh.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -25,7 +26,7 @@ namespace Nz MeshParams::MeshParams() { if (!Buffer::IsStorageSupported(storage)) - storage = DataStorage_Software; + storage = DataStorage::Software; } bool MeshParams::IsValid() const @@ -48,7 +49,7 @@ namespace Nz return false; } - if (!vertexDeclaration->HasComponent(VertexComponent_Position)) + if (!vertexDeclaration->HasComponent(VertexComponent::Position)) { NazaraError("Vertex declaration must contains a vertex position"); return false; @@ -58,7 +59,7 @@ namespace Nz } - void Mesh::AddSubMesh(SubMesh* subMesh) + void Mesh::AddSubMesh(std::shared_ptr subMesh) { NazaraAssert(m_isValid, "Mesh should be created first"); NazaraAssert(subMesh, "Invalid submesh"); @@ -66,13 +67,13 @@ namespace Nz m_subMeshes.emplace_back(); SubMeshData& subMeshData = m_subMeshes.back(); - subMeshData.subMesh = subMesh; - subMeshData.onSubMeshInvalidated.Connect(subMesh->OnSubMeshInvalidateAABB, [this](const SubMesh* /*subMesh*/) { InvalidateAABB(); }); + subMeshData.subMesh = std::move(subMesh); + subMeshData.onSubMeshInvalidated.Connect(subMeshData.subMesh->OnSubMeshInvalidateAABB, [this](const SubMesh* /*subMesh*/) { InvalidateAABB(); }); InvalidateAABB(); } - void Mesh::AddSubMesh(const std::string& identifier, SubMesh* subMesh) + void Mesh::AddSubMesh(const std::string& identifier, std::shared_ptr subMesh) { NazaraAssert(m_isValid, "Mesh should be created first"); NazaraAssert(!identifier.empty(), "Identifier is empty"); @@ -82,161 +83,161 @@ namespace Nz std::size_t index = m_subMeshes.size(); - AddSubMesh(subMesh); + AddSubMesh(std::move(subMesh)); m_subMeshMap[identifier] = static_cast(index); } - SubMesh* Mesh::BuildSubMesh(const Primitive& primitive, const MeshParams& params) + std::shared_ptr Mesh::BuildSubMesh(const Primitive& primitive, const MeshParams& params) { NazaraAssert(m_isValid, "Mesh should be created first"); - NazaraAssert(m_animationType == AnimationType_Static, "Submesh building only works for static meshes"); + NazaraAssert(m_animationType == AnimationType::Static, "Submesh building only works for static meshes"); NazaraAssert(params.IsValid(), "Invalid parameters"); - NazaraAssert(params.vertexDeclaration->HasComponentOfType(VertexComponent_Position), "The vertex declaration doesn't have a Vector3 position component"); + NazaraAssert(params.vertexDeclaration->HasComponentOfType(VertexComponent::Position), "The vertex declaration doesn't have a Vector3 position component"); Boxf aabb; - IndexBufferRef indexBuffer; - VertexBufferRef vertexBuffer; + std::shared_ptr indexBuffer; + std::shared_ptr vertexBuffer; Matrix4f matrix(primitive.matrix); matrix *= params.matrix; - VertexDeclaration* declaration = params.vertexDeclaration; + const std::shared_ptr& declaration = params.vertexDeclaration; switch (primitive.type) { - case PrimitiveType_Box: + case PrimitiveType::Box: { unsigned int indexCount; unsigned int vertexCount; ComputeBoxIndexVertexCount(primitive.box.subdivision, &indexCount, &vertexCount); - indexBuffer = IndexBuffer::New(vertexCount > std::numeric_limits::max(), indexCount, params.storage, params.indexBufferFlags); - vertexBuffer = VertexBuffer::New(declaration, vertexCount, params.storage, params.vertexBufferFlags); + indexBuffer = std::make_shared(vertexCount > std::numeric_limits::max(), indexCount, params.storage, params.indexBufferFlags); + vertexBuffer = std::make_shared(declaration, vertexCount, params.storage, params.vertexBufferFlags); - VertexMapper vertexMapper(vertexBuffer, BufferAccess_WriteOnly); + VertexMapper vertexMapper(*vertexBuffer, BufferAccess::WriteOnly); VertexPointers pointers; - pointers.normalPtr = vertexMapper.GetComponentPtr(VertexComponent_Normal); - pointers.positionPtr = vertexMapper.GetComponentPtr(VertexComponent_Position); - pointers.tangentPtr = vertexMapper.GetComponentPtr(VertexComponent_Tangent); - pointers.uvPtr = vertexMapper.GetComponentPtr(VertexComponent_TexCoord); + pointers.normalPtr = vertexMapper.GetComponentPtr(VertexComponent::Normal); + pointers.positionPtr = vertexMapper.GetComponentPtr(VertexComponent::Position); + pointers.tangentPtr = vertexMapper.GetComponentPtr(VertexComponent::Tangent); + pointers.uvPtr = vertexMapper.GetComponentPtr(VertexComponent::TexCoord); - IndexMapper indexMapper(indexBuffer, BufferAccess_WriteOnly); + IndexMapper indexMapper(*indexBuffer, BufferAccess::WriteOnly); GenerateBox(primitive.box.lengths, primitive.box.subdivision, matrix, primitive.textureCoords, pointers, indexMapper.begin(), &aabb); break; } - case PrimitiveType_Cone: + case PrimitiveType::Cone: { unsigned int indexCount; unsigned int vertexCount; ComputeConeIndexVertexCount(primitive.cone.subdivision, &indexCount, &vertexCount); - indexBuffer = IndexBuffer::New(vertexCount > std::numeric_limits::max(), indexCount, params.storage, params.indexBufferFlags); - vertexBuffer = VertexBuffer::New(declaration, vertexCount, params.storage, params.vertexBufferFlags); + indexBuffer = std::make_shared(vertexCount > std::numeric_limits::max(), indexCount, params.storage, params.indexBufferFlags); + vertexBuffer = std::make_shared(declaration, vertexCount, params.storage, params.vertexBufferFlags); - VertexMapper vertexMapper(vertexBuffer, BufferAccess_WriteOnly); + VertexMapper vertexMapper(*vertexBuffer, BufferAccess::WriteOnly); VertexPointers pointers; - pointers.normalPtr = vertexMapper.GetComponentPtr(VertexComponent_Normal); - pointers.positionPtr = vertexMapper.GetComponentPtr(VertexComponent_Position); - pointers.tangentPtr = vertexMapper.GetComponentPtr(VertexComponent_Tangent); - pointers.uvPtr = vertexMapper.GetComponentPtr(VertexComponent_TexCoord); + pointers.normalPtr = vertexMapper.GetComponentPtr(VertexComponent::Normal); + pointers.positionPtr = vertexMapper.GetComponentPtr(VertexComponent::Position); + pointers.tangentPtr = vertexMapper.GetComponentPtr(VertexComponent::Tangent); + pointers.uvPtr = vertexMapper.GetComponentPtr(VertexComponent::TexCoord); - IndexMapper indexMapper(indexBuffer, BufferAccess_WriteOnly); + IndexMapper indexMapper(*indexBuffer, BufferAccess::WriteOnly); GenerateCone(primitive.cone.length, primitive.cone.radius, primitive.cone.subdivision, matrix, primitive.textureCoords, pointers, indexMapper.begin(), &aabb); break; } - case PrimitiveType_Plane: + case PrimitiveType::Plane: { unsigned int indexCount; unsigned int vertexCount; ComputePlaneIndexVertexCount(primitive.plane.subdivision, &indexCount, &vertexCount); - indexBuffer = IndexBuffer::New(vertexCount > std::numeric_limits::max(), indexCount, params.storage, params.indexBufferFlags); - vertexBuffer = VertexBuffer::New(declaration, vertexCount, params.storage, params.vertexBufferFlags); + indexBuffer = std::make_shared(vertexCount > std::numeric_limits::max(), indexCount, params.storage, params.indexBufferFlags); + vertexBuffer = std::make_shared(declaration, vertexCount, params.storage, params.vertexBufferFlags); - VertexMapper vertexMapper(vertexBuffer, BufferAccess_WriteOnly); + VertexMapper vertexMapper(*vertexBuffer, BufferAccess::WriteOnly); VertexPointers pointers; - pointers.normalPtr = vertexMapper.GetComponentPtr(VertexComponent_Normal); - pointers.positionPtr = vertexMapper.GetComponentPtr(VertexComponent_Position); - pointers.tangentPtr = vertexMapper.GetComponentPtr(VertexComponent_Tangent); - pointers.uvPtr = vertexMapper.GetComponentPtr(VertexComponent_TexCoord); + pointers.normalPtr = vertexMapper.GetComponentPtr(VertexComponent::Normal); + pointers.positionPtr = vertexMapper.GetComponentPtr(VertexComponent::Position); + pointers.tangentPtr = vertexMapper.GetComponentPtr(VertexComponent::Tangent); + pointers.uvPtr = vertexMapper.GetComponentPtr(VertexComponent::TexCoord); - IndexMapper indexMapper(indexBuffer, BufferAccess_WriteOnly); + IndexMapper indexMapper(*indexBuffer, BufferAccess::WriteOnly); GeneratePlane(primitive.plane.subdivision, primitive.plane.size, matrix, primitive.textureCoords, pointers, indexMapper.begin(), &aabb); break; } - case PrimitiveType_Sphere: + case PrimitiveType::Sphere: { switch (primitive.sphere.type) { - case SphereType_Cubic: + case SphereType::Cubic: { unsigned int indexCount; unsigned int vertexCount; ComputeCubicSphereIndexVertexCount(primitive.sphere.cubic.subdivision, &indexCount, &vertexCount); - indexBuffer = IndexBuffer::New(vertexCount > std::numeric_limits::max(), indexCount, params.storage, params.indexBufferFlags); - vertexBuffer = VertexBuffer::New(declaration, vertexCount, params.storage, params.vertexBufferFlags); + indexBuffer = std::make_shared(vertexCount > std::numeric_limits::max(), indexCount, params.storage, params.indexBufferFlags); + vertexBuffer = std::make_shared(declaration, vertexCount, params.storage, params.vertexBufferFlags); - VertexMapper vertexMapper(vertexBuffer, BufferAccess_ReadWrite); + VertexMapper vertexMapper(*vertexBuffer, BufferAccess::ReadWrite); VertexPointers pointers; - pointers.normalPtr = vertexMapper.GetComponentPtr(VertexComponent_Normal); - pointers.positionPtr = vertexMapper.GetComponentPtr(VertexComponent_Position); - pointers.tangentPtr = vertexMapper.GetComponentPtr(VertexComponent_Tangent); - pointers.uvPtr = vertexMapper.GetComponentPtr(VertexComponent_TexCoord); + pointers.normalPtr = vertexMapper.GetComponentPtr(VertexComponent::Normal); + pointers.positionPtr = vertexMapper.GetComponentPtr(VertexComponent::Position); + pointers.tangentPtr = vertexMapper.GetComponentPtr(VertexComponent::Tangent); + pointers.uvPtr = vertexMapper.GetComponentPtr(VertexComponent::TexCoord); - IndexMapper indexMapper(indexBuffer, BufferAccess_WriteOnly); + IndexMapper indexMapper(*indexBuffer, BufferAccess::WriteOnly); GenerateCubicSphere(primitive.sphere.size, primitive.sphere.cubic.subdivision, matrix, primitive.textureCoords, pointers, indexMapper.begin(), &aabb); break; } - case SphereType_Ico: + case SphereType::Ico: { unsigned int indexCount; unsigned int vertexCount; ComputeIcoSphereIndexVertexCount(primitive.sphere.ico.recursionLevel, &indexCount, &vertexCount); - indexBuffer = IndexBuffer::New(vertexCount > std::numeric_limits::max(), indexCount, params.storage, params.indexBufferFlags); - vertexBuffer = VertexBuffer::New(declaration, vertexCount, params.storage, params.vertexBufferFlags); + indexBuffer = std::make_shared(vertexCount > std::numeric_limits::max(), indexCount, params.storage, params.indexBufferFlags); + vertexBuffer = std::make_shared(declaration, vertexCount, params.storage, params.vertexBufferFlags); - VertexMapper vertexMapper(vertexBuffer, BufferAccess_WriteOnly); + VertexMapper vertexMapper(*vertexBuffer, BufferAccess::WriteOnly); VertexPointers pointers; - pointers.normalPtr = vertexMapper.GetComponentPtr(VertexComponent_Normal); - pointers.positionPtr = vertexMapper.GetComponentPtr(VertexComponent_Position); - pointers.tangentPtr = vertexMapper.GetComponentPtr(VertexComponent_Tangent); - pointers.uvPtr = vertexMapper.GetComponentPtr(VertexComponent_TexCoord); + pointers.normalPtr = vertexMapper.GetComponentPtr(VertexComponent::Normal); + pointers.positionPtr = vertexMapper.GetComponentPtr(VertexComponent::Position); + pointers.tangentPtr = vertexMapper.GetComponentPtr(VertexComponent::Tangent); + pointers.uvPtr = vertexMapper.GetComponentPtr(VertexComponent::TexCoord); - IndexMapper indexMapper(indexBuffer, BufferAccess_WriteOnly); + IndexMapper indexMapper(*indexBuffer, BufferAccess::WriteOnly); GenerateIcoSphere(primitive.sphere.size, primitive.sphere.ico.recursionLevel, matrix, primitive.textureCoords, pointers, indexMapper.begin(), &aabb); break; } - case SphereType_UV: + case SphereType::UV: { unsigned int indexCount; unsigned int vertexCount; ComputeUvSphereIndexVertexCount(primitive.sphere.uv.sliceCount, primitive.sphere.uv.stackCount, &indexCount, &vertexCount); - indexBuffer = IndexBuffer::New(vertexCount > std::numeric_limits::max(), indexCount, params.storage, params.indexBufferFlags); - vertexBuffer = VertexBuffer::New(declaration, vertexCount, params.storage, params.vertexBufferFlags); + indexBuffer = std::make_shared(vertexCount > std::numeric_limits::max(), indexCount, params.storage, params.indexBufferFlags); + vertexBuffer = std::make_shared(declaration, vertexCount, params.storage, params.vertexBufferFlags); - VertexMapper vertexMapper(vertexBuffer, BufferAccess_WriteOnly); + VertexMapper vertexMapper(*vertexBuffer, BufferAccess::WriteOnly); VertexPointers pointers; - pointers.normalPtr = vertexMapper.GetComponentPtr(VertexComponent_Normal); - pointers.positionPtr = vertexMapper.GetComponentPtr(VertexComponent_Position); - pointers.tangentPtr = vertexMapper.GetComponentPtr(VertexComponent_Tangent); - pointers.uvPtr = vertexMapper.GetComponentPtr(VertexComponent_TexCoord); + pointers.normalPtr = vertexMapper.GetComponentPtr(VertexComponent::Normal); + pointers.positionPtr = vertexMapper.GetComponentPtr(VertexComponent::Position); + pointers.tangentPtr = vertexMapper.GetComponentPtr(VertexComponent::Tangent); + pointers.uvPtr = vertexMapper.GetComponentPtr(VertexComponent::TexCoord); - IndexMapper indexMapper(indexBuffer, BufferAccess_WriteOnly); + IndexMapper indexMapper(*indexBuffer, BufferAccess::WriteOnly); GenerateUvSphere(primitive.sphere.size, primitive.sphere.uv.sliceCount, primitive.sphere.uv.stackCount, matrix, primitive.textureCoords, pointers, indexMapper.begin(), &aabb); break; } @@ -248,7 +249,7 @@ namespace Nz if (params.optimizeIndexBuffers) indexBuffer->Optimize(); - StaticMeshRef subMesh = StaticMesh::New(vertexBuffer, indexBuffer); + std::shared_ptr subMesh = std::make_shared(vertexBuffer, indexBuffer); subMesh->SetAABB(aabb); AddSubMesh(subMesh); @@ -265,7 +266,7 @@ namespace Nz { Destroy(); - m_animationType = AnimationType_Skeletal; + m_animationType = AnimationType::Skeletal; m_jointCount = jointCount; if (!m_skeleton.Create(jointCount)) { @@ -282,7 +283,7 @@ namespace Nz { Destroy(); - m_animationType = AnimationType_Static; + m_animationType = AnimationType::Static; m_isValid = true; return true; @@ -292,8 +293,6 @@ namespace Nz { if (m_isValid) { - OnMeshDestroy(this); - m_animationPath.clear(); m_materialData.clear(); m_materialData.resize(1); @@ -368,7 +367,7 @@ namespace Nz std::size_t Mesh::GetJointCount() const { NazaraAssert(m_isValid, "Mesh should be created first"); - NazaraAssert(m_animationType == AnimationType_Skeletal, "Mesh is not skeletal"); + NazaraAssert(m_animationType == AnimationType::Skeletal, "Mesh is not skeletal"); return m_jointCount; } @@ -399,7 +398,7 @@ namespace Nz Skeleton* Mesh::GetSkeleton() { NazaraAssert(m_isValid, "Mesh should be created first"); - NazaraAssert(m_animationType == AnimationType_Skeletal, "Mesh is not skeletal"); + NazaraAssert(m_animationType == AnimationType::Skeletal, "Mesh is not skeletal"); return &m_skeleton; } @@ -407,12 +406,12 @@ namespace Nz const Skeleton* Mesh::GetSkeleton() const { NazaraAssert(m_isValid, "Mesh should be created first"); - NazaraAssert(m_animationType == AnimationType_Skeletal, "Mesh is not skeletal"); + NazaraAssert(m_animationType == AnimationType::Skeletal, "Mesh is not skeletal"); return &m_skeleton; } - SubMesh* Mesh::GetSubMesh(const std::string& identifier) + const std::shared_ptr& Mesh::GetSubMesh(const std::string& identifier) const { NazaraAssert(m_isValid, "Mesh should be created first"); @@ -422,25 +421,7 @@ namespace Nz return m_subMeshes[it->second].subMesh; } - SubMesh* Mesh::GetSubMesh(std::size_t index) - { - NazaraAssert(m_isValid, "Mesh should be created first"); - NazaraAssert(index < m_subMeshes.size(), "Submesh index out of range"); - - return m_subMeshes[index].subMesh; - } - - const SubMesh* Mesh::GetSubMesh(const std::string& identifier) const - { - NazaraAssert(m_isValid, "Mesh should be created first"); - - auto it = m_subMeshMap.find(identifier); - NazaraAssert(it != m_subMeshMap.end(), "SubMesh " + identifier + " not found"); - - return m_subMeshes[it->second].subMesh; - } - - const SubMesh* Mesh::GetSubMesh(std::size_t index) const + const std::shared_ptr& Mesh::GetSubMesh(std::size_t index) const { NazaraAssert(m_isValid, "Mesh should be created first"); NazaraAssert(index < m_subMeshes.size(), "Submesh index out of range"); @@ -514,7 +495,7 @@ namespace Nz { NazaraAssert(m_isValid, "Mesh should be created first"); - return m_animationType != AnimationType_Static; + return m_animationType != AnimationType::Static; } bool Mesh::IsValid() const @@ -525,7 +506,7 @@ namespace Nz void Mesh::Recenter() { NazaraAssert(m_isValid, "Mesh should be created first"); - NazaraAssert(m_animationType == AnimationType_Static, "Mesh is not static"); + NazaraAssert(m_animationType == AnimationType::Static, "Mesh is not static"); // The center of our mesh is the center of our *global* AABB Vector3f center = GetAABB().GetCenter(); @@ -534,7 +515,7 @@ namespace Nz { StaticMesh& staticMesh = static_cast(*data.subMesh); - BufferMapper mapper(staticMesh.GetVertexBuffer(), BufferAccess_ReadWrite); + BufferMapper mapper(*staticMesh.GetVertexBuffer(), BufferAccess::ReadWrite); MeshVertex* vertices = static_cast(mapper.GetPointer()); std::size_t vertexCount = staticMesh.GetVertexCount(); @@ -577,12 +558,18 @@ namespace Nz bool Mesh::SaveToFile(const std::filesystem::path& filePath, const MeshParams& params) { - return MeshSaver::SaveToFile(*this, filePath, params); + Utility* utility = Utility::Instance(); + NazaraAssert(utility, "Utility module has not been initialized"); + + return utility->GetMeshSaver().SaveToFile(*this, filePath, params); } bool Mesh::SaveToStream(Stream& stream, const std::string& format, const MeshParams& params) { - return MeshSaver::SaveToStream(*this, stream, format, params); + Utility* utility = Utility::Instance(); + NazaraAssert(utility, "Utility module has not been initialized"); + + return utility->GetMeshSaver().SaveToStream(*this, stream, format, params); } void Mesh::SetAnimation(const std::filesystem::path& animationPath) @@ -614,7 +601,7 @@ namespace Nz if (matIndex >= matCount) { data.subMesh->SetMaterialIndex(0); // To prevent a crash - NazaraWarning("SubMesh " + PointerToString(data.subMesh) + " material index is over mesh new material count (" + NumberToString(matIndex) + " >= " + NumberToString(matCount) + "), setting it to first material"); + NazaraWarning("SubMesh " + PointerToString(data.subMesh.get()) + " material index is over mesh new material count (" + NumberToString(matIndex) + " >= " + NumberToString(matCount) + "), setting it to first material"); } } #endif @@ -623,13 +610,13 @@ namespace Nz void Mesh::Transform(const Matrix4f& matrix) { NazaraAssert(m_isValid, "Mesh should be created first"); - NazaraAssert(m_animationType == AnimationType_Static, "Mesh is not static"); + NazaraAssert(m_animationType == AnimationType::Static, "Mesh is not static"); for (SubMeshData& data : m_subMeshes) { StaticMesh& staticMesh = static_cast(*data.subMesh); - BufferMapper mapper(staticMesh.GetVertexBuffer(), BufferAccess_ReadWrite); + BufferMapper mapper(*staticMesh.GetVertexBuffer(), BufferAccess::ReadWrite); MeshVertex* vertices = static_cast(mapper.GetPointer()); Boxf aabb(vertices->position.x, vertices->position.y, vertices->position.z, 0.f, 0.f, 0.f); @@ -647,47 +634,27 @@ namespace Nz } } - MeshRef Mesh::LoadFromFile(const std::filesystem::path& filePath, const MeshParams& params) + std::shared_ptr Mesh::LoadFromFile(const std::filesystem::path& filePath, const MeshParams& params) { - return MeshLoader::LoadFromFile(filePath, params); + Utility* utility = Utility::Instance(); + NazaraAssert(utility, "Utility module has not been initialized"); + + return utility->GetMeshLoader().LoadFromFile(filePath, params); } - MeshRef Mesh::LoadFromMemory(const void* data, std::size_t size, const MeshParams& params) + std::shared_ptr Mesh::LoadFromMemory(const void* data, std::size_t size, const MeshParams& params) { - return MeshLoader::LoadFromMemory(data, size, params); + Utility* utility = Utility::Instance(); + NazaraAssert(utility, "Utility module has not been initialized"); + + return utility->GetMeshLoader().LoadFromMemory(data, size, params); } - MeshRef Mesh::LoadFromStream(Stream& stream, const MeshParams& params) + std::shared_ptr Mesh::LoadFromStream(Stream& stream, const MeshParams& params) { - return MeshLoader::LoadFromStream(stream, params); + Utility* utility = Utility::Instance(); + NazaraAssert(utility, "Utility module has not been initialized"); + + return utility->GetMeshLoader().LoadFromStream(stream, params); } - - bool Mesh::Initialize() - { - if (!MeshLibrary::Initialize()) - { - NazaraError("Failed to initialise library"); - return false; - } - - if (!MeshManager::Initialize()) - { - NazaraError("Failed to initialise manager"); - return false; - } - - return true; - } - - void Mesh::Uninitialize() - { - MeshManager::Uninitialize(); - MeshLibrary::Uninitialize(); - } - - MeshLibrary::LibraryMap Mesh::s_library; - MeshLoader::LoaderList Mesh::s_loaders; - MeshManager::ManagerMap Mesh::s_managerMap; - MeshManager::ManagerParams Mesh::s_managerParameters; - MeshSaver::SaverList Mesh::s_savers; } diff --git a/src/Nazara/Utility/Node.cpp b/src/Nazara/Utility/Node.cpp index 015ad3aeb..0b70e69f9 100644 --- a/src/Nazara/Utility/Node.cpp +++ b/src/Nazara/Utility/Node.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include namespace Nz @@ -136,7 +137,7 @@ namespace Nz NodeType Node::GetNodeType() const { - return NodeType_Default; + return NodeType::Default; } const Node* Node::GetParent() const @@ -148,17 +149,17 @@ namespace Nz { switch (coordSys) { - case CoordSys_Global: + case CoordSys::Global: if (!m_derivedUpdated) UpdateDerived(); return m_derivedPosition; - case CoordSys_Local: + case CoordSys::Local: return m_position; } - NazaraError("Coordinate system out of enum (0x" + NumberToString(coordSys, 16) + ')'); + NazaraError("Coordinate system out of enum (0x" + NumberToString(UnderlyingCast(coordSys), 16) + ')'); return Vector3f(); } @@ -174,17 +175,17 @@ namespace Nz { switch (coordSys) { - case CoordSys_Global: + case CoordSys::Global: if (!m_derivedUpdated) UpdateDerived(); return m_derivedRotation; - case CoordSys_Local: + case CoordSys::Local: return m_rotation; } - NazaraError("Coordinate system out of enum (0x" + NumberToString(coordSys, 16) + ')'); + NazaraError("Coordinate system out of enum (0x" + NumberToString(UnderlyingCast(coordSys), 16) + ')'); return Quaternionf(); } @@ -192,17 +193,17 @@ namespace Nz { switch (coordSys) { - case CoordSys_Global: + case CoordSys::Global: if (!m_derivedUpdated) UpdateDerived(); return m_derivedScale; - case CoordSys_Local: + case CoordSys::Local: return m_scale; } - NazaraError("Coordinate system out of enum (0x" + NumberToString(coordSys, 16) + ')'); + NazaraError("Coordinate system out of enum (0x" + NumberToString(UnderlyingCast(coordSys), 16) + ')'); return Vector3f(); } @@ -231,7 +232,7 @@ namespace Nz { switch (coordSys) { - case CoordSys_Global: + case CoordSys::Global: if (!nodeA.m_derivedUpdated) nodeA.UpdateDerived(); @@ -243,7 +244,7 @@ namespace Nz m_scale = ToLocalScale(Vector3f::Lerp(nodeA.m_derivedScale, nodeB.m_derivedScale, interpolation)); break; - case CoordSys_Local: + case CoordSys::Local: m_position = Vector3f::Lerp(nodeA.m_position, nodeB.m_position, interpolation); m_rotation = Quaternionf::Slerp(nodeA.m_rotation, nodeB.m_rotation, interpolation); m_scale = Vector3f::Lerp(nodeA.m_scale, nodeB.m_scale, interpolation); @@ -258,7 +259,7 @@ namespace Nz { switch (coordSys) { - case CoordSys_Global: + case CoordSys::Global: { if (m_parent) { @@ -273,7 +274,7 @@ namespace Nz break; } - case CoordSys_Local: + case CoordSys::Local: m_position += m_rotation * movement; break; } @@ -295,7 +296,7 @@ namespace Nz switch (coordSys) { - case CoordSys_Global: + case CoordSys::Global: { if (!m_derivedUpdated) UpdateDerived(); @@ -304,7 +305,7 @@ namespace Nz break; } - case CoordSys_Local: + case CoordSys::Local: m_rotation *= q; break; } @@ -449,9 +450,9 @@ namespace Nz if (m_parent) m_parent->AddChild(this); - SetRotation(m_derivedRotation, CoordSys_Global); - SetScale(m_derivedScale, CoordSys_Global); - SetPosition(m_derivedPosition, CoordSys_Global); + SetRotation(m_derivedRotation, CoordSys::Global); + SetScale(m_derivedScale, CoordSys::Global); + SetPosition(m_derivedPosition, CoordSys::Global); } else { @@ -477,7 +478,7 @@ namespace Nz { switch (coordSys) { - case CoordSys_Global: + case CoordSys::Global: if (m_parent && m_inheritPosition) { if (!m_parent->m_derivedUpdated) @@ -489,7 +490,7 @@ namespace Nz m_position = position - m_initialPosition; break; - case CoordSys_Local: + case CoordSys::Local: m_position = position; break; } @@ -510,7 +511,7 @@ namespace Nz switch (coordSys) { - case CoordSys_Global: + case CoordSys::Global: if (m_parent && m_inheritRotation) { Quaternionf rot(m_parent->GetRotation() * m_initialRotation); @@ -522,7 +523,7 @@ namespace Nz break; - case CoordSys_Local: + case CoordSys::Local: m_rotation = q; break; } @@ -540,14 +541,14 @@ namespace Nz { switch (coordSys) { - case CoordSys_Global: + case CoordSys::Global: if (m_parent && m_inheritScale) m_scale = scale / (m_initialScale * m_parent->GetScale()); else m_scale = scale / m_initialScale; break; - case CoordSys_Local: + case CoordSys::Local: m_scale = scale; break; } @@ -567,9 +568,9 @@ namespace Nz void Node::SetTransformMatrix(const Matrix4f& matrix) { - SetPosition(matrix.GetTranslation(), CoordSys_Global); - SetRotation(matrix.GetRotation(), CoordSys_Global); - SetScale(matrix.GetScale(), CoordSys_Global); + SetPosition(matrix.GetTranslation(), CoordSys::Global); + SetRotation(matrix.GetRotation(), CoordSys::Global); + SetScale(matrix.GetScale(), CoordSys::Global); m_transformMatrix = matrix; m_transformMatrixUpdated = true; diff --git a/src/Nazara/Utility/PixelFormat.cpp b/src/Nazara/Utility/PixelFormat.cpp index b169afd4f..9c17f8d7f 100644 --- a/src/Nazara/Utility/PixelFormat.cpp +++ b/src/Nazara/Utility/PixelFormat.cpp @@ -54,7 +54,7 @@ namespace Nz /**********************************A8***********************************/ template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -70,7 +70,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -84,7 +84,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { UInt16* ptr = reinterpret_cast(dst); while (start < end) @@ -106,7 +106,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { UInt16* ptr = reinterpret_cast(dst); while (start < end) @@ -125,7 +125,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -142,7 +142,7 @@ namespace Nz /**********************************BGR8***********************************/ template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -158,7 +158,16 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + { + //FIXME: Not correct + std::size_t count = end - start; + std::memcpy(dst, start, count); + return dst + count; + } + + template<> + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -171,7 +180,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -185,7 +194,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { UInt16* ptr = reinterpret_cast(dst); while (start < end) @@ -207,7 +216,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -222,7 +231,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { UInt16* ptr = reinterpret_cast(dst); while (start < end) @@ -244,7 +253,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -261,7 +270,7 @@ namespace Nz /**********************************BGRA8**********************************/ template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -274,7 +283,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -289,7 +298,16 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + { + //FIXME: Not correct + std::size_t count = end - start; + std::memcpy(dst, start, count); + return dst + count; + } + + template<> + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -302,7 +320,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -316,7 +334,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { UInt16* ptr = reinterpret_cast(dst); while (start < end) @@ -338,7 +356,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { UInt16* ptr = reinterpret_cast(dst); while (start < end) @@ -360,7 +378,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -375,7 +393,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -392,7 +410,7 @@ namespace Nz /***********************************L8************************************/ template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -407,7 +425,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -423,7 +441,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -437,7 +455,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { UInt16* ptr = reinterpret_cast(dst); while (start < end) @@ -461,7 +479,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -476,7 +494,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { UInt16* ptr = reinterpret_cast(dst); while (start < end) @@ -500,7 +518,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -517,7 +535,7 @@ namespace Nz /***********************************LA8***********************************/ template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -530,7 +548,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -545,7 +563,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -561,7 +579,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -574,7 +592,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { UInt16* ptr = reinterpret_cast(dst); while (start < end) @@ -595,7 +613,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -610,7 +628,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { UInt16* ptr = reinterpret_cast(dst); while (start < end) @@ -631,7 +649,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -648,7 +666,7 @@ namespace Nz /*********************************RGBA4***********************************/ template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -667,7 +685,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -688,7 +706,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -710,7 +728,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -733,7 +751,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -757,7 +775,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { UInt16* ptr = reinterpret_cast(dst); while (start < end) @@ -787,7 +805,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -808,7 +826,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -831,7 +849,7 @@ namespace Nz /*********************************RGB5A1**********************************/ template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -850,7 +868,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -871,7 +889,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -893,7 +911,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -916,7 +934,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -940,7 +958,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -961,7 +979,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { UInt16* ptr = reinterpret_cast(dst); while (start < end) @@ -990,7 +1008,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -1013,7 +1031,7 @@ namespace Nz /**********************************RGB8***********************************/ template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -1028,7 +1046,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -1044,7 +1062,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -1057,7 +1075,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -1071,7 +1089,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { UInt16* ptr = reinterpret_cast(dst); while (start < end) @@ -1093,7 +1111,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { UInt16* ptr = reinterpret_cast(dst); while (start < end) @@ -1115,7 +1133,16 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + { + //FIXME: Not correct + std::size_t count = end - start; + std::memcpy(dst, start, count); + return dst + count; + } + + template<> + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -1132,7 +1159,7 @@ namespace Nz /**********************************RGBA8**********************************/ template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -1145,7 +1172,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -1160,7 +1187,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -1176,7 +1203,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -1189,7 +1216,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -1203,7 +1230,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { UInt16* ptr = reinterpret_cast(dst); while (start < end) @@ -1225,7 +1252,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { while (start < end) { @@ -1240,7 +1267,7 @@ namespace Nz } template<> - UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) { UInt16* ptr = reinterpret_cast(dst); while (start < end) @@ -1261,26 +1288,30 @@ namespace Nz return dst; } - template + template<> + UInt8* ConvertPixels(const UInt8* start, const UInt8* end, UInt8* dst) + { + //FIXME: Not correct + std::size_t count = end - start; + std::memcpy(dst, start, count); + return dst + count; + } + + + template void RegisterConverter() { - PixelFormatInfo::SetConvertFunction(format1, format2, &ConvertPixels); + PixelFormatInfo::SetConvertFunction(Format1, Format2, &ConvertPixels); } } bool PixelFormatInfo::Flip(PixelFlipping flipping, PixelFormat format, unsigned int width, unsigned int height, unsigned int depth, const void* src, void* dst) { - #if NAZARA_UTILITY_SAFE - if (!IsValid(format)) - { - NazaraError("Invalid pixel format"); - return false; - } - #endif + NazaraAssert(IsValid(format), "invalid pixel format"); - auto it = s_flipFunctions[flipping].find(format); - if (it != s_flipFunctions[flipping].end()) - it->second(width, height, depth, reinterpret_cast(src), reinterpret_cast(dst)); + auto& flipFunction = s_flipFunctions[UnderlyingCast(format)][UnderlyingCast(flipping)]; + if (flipFunction) + flipFunction(width, height, depth, reinterpret_cast(src), reinterpret_cast(dst)); else { // Flipping générique @@ -1297,7 +1328,7 @@ namespace Nz unsigned int lineStride = width*bpp; switch (flipping) { - case PixelFlipping_Horizontally: + case PixelFlipping::Horizontally: { if (src == dst) { @@ -1326,7 +1357,7 @@ namespace Nz break; } - case PixelFlipping_Vertically: + case PixelFlipping::Vertically: { if (src == dst) { @@ -1366,7 +1397,7 @@ namespace Nz PixelFormat PixelFormatInfo::IdentifyFormat(const PixelFormatDescription& info) { - for (unsigned int i = 0; i <= PixelFormat_Max; ++i) + for (unsigned int i = 0; i < PixelFormatCount; ++i) { PixelFormatDescription& info2 = s_pixelFormatInfos[i]; if (info.bitsPerPixel == info2.bitsPerPixel && info.content == info2.content && @@ -1375,309 +1406,326 @@ namespace Nz return static_cast(i); } - return PixelFormat_Undefined; + return PixelFormat::Undefined; } bool PixelFormatInfo::Initialize() { + auto SetupPixelFormat = [](PixelFormat format, PixelFormatDescription&& desc) + { + s_pixelFormatInfos[UnderlyingCast(format)] = std::move(desc); + }; + + Bitset<> b8(0xFF); + b8.Resize(128); + Bitset<> b32(0xFFFFFFFF); b32.Resize(128); // Setup informations about every pixel format - s_pixelFormatInfos[PixelFormat_A8] = PixelFormatDescription("A8", PixelFormatContent_ColorRGBA, 0, 0, 0, 0xFF, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_BGR8] = PixelFormatDescription("BGR8", PixelFormatContent_ColorRGBA, 0x0000FF, 0x00FF00, 0xFF0000, 0, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_BGRA8] = PixelFormatDescription("BGRA8", PixelFormatContent_ColorRGBA, 0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_DXT1] = PixelFormatDescription("DXT1", PixelFormatContent_ColorRGBA, 8, PixelFormatSubType_Compressed); - s_pixelFormatInfos[PixelFormat_DXT3] = PixelFormatDescription("DXT3", PixelFormatContent_ColorRGBA, 16, PixelFormatSubType_Compressed); - s_pixelFormatInfos[PixelFormat_DXT5] = PixelFormatDescription("DXT5", PixelFormatContent_ColorRGBA, 16, PixelFormatSubType_Compressed); - s_pixelFormatInfos[PixelFormat_L8] = PixelFormatDescription("L8", PixelFormatContent_ColorRGBA, 0xFF, 0xFF, 0xFF, 0, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_LA8] = PixelFormatDescription("LA8", PixelFormatContent_ColorRGBA, 0xFF00, 0xFF00, 0xFF00, 0x00FF, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_R8] = PixelFormatDescription("R8", PixelFormatContent_ColorRGBA, 0xFF, 0, 0, 0, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_R8I] = PixelFormatDescription("R8I", PixelFormatContent_ColorRGBA, 0xFF, 0, 0, 0, PixelFormatSubType_Int); - s_pixelFormatInfos[PixelFormat_R8UI] = PixelFormatDescription("R8UI", PixelFormatContent_ColorRGBA, 0xFF, 0, 0, 0, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_R16] = PixelFormatDescription("R16", PixelFormatContent_ColorRGBA, 0xFFFF, 0, 0, 0, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_R16F] = PixelFormatDescription("R16F", PixelFormatContent_ColorRGBA, 0xFFFF, 0, 0, 0, PixelFormatSubType_Half); - s_pixelFormatInfos[PixelFormat_R16I] = PixelFormatDescription("R16I", PixelFormatContent_ColorRGBA, 0xFFFF, 0, 0, 0, PixelFormatSubType_Int); - s_pixelFormatInfos[PixelFormat_R16UI] = PixelFormatDescription("R16UI", PixelFormatContent_ColorRGBA, 0xFFFF, 0, 0, 0, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_R32F] = PixelFormatDescription("R32F", PixelFormatContent_ColorRGBA, 0xFFFFFFFF, 0, 0, 0, PixelFormatSubType_Float); - s_pixelFormatInfos[PixelFormat_R32I] = PixelFormatDescription("R32I", PixelFormatContent_ColorRGBA, 0xFFFFFFFF, 0, 0, 0, PixelFormatSubType_Int); - s_pixelFormatInfos[PixelFormat_R32UI] = PixelFormatDescription("R32UI", PixelFormatContent_ColorRGBA, 0xFFFFFFFF, 0, 0, 0, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_RG8] = PixelFormatDescription("RG8", PixelFormatContent_ColorRGBA, 0xFF00, 0x00FF, 0, 0, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_RG8I] = PixelFormatDescription("RG8I", PixelFormatContent_ColorRGBA, 0xFF00, 0x00FF, 0, 0, PixelFormatSubType_Int); - s_pixelFormatInfos[PixelFormat_RG8UI] = PixelFormatDescription("RG8UI", PixelFormatContent_ColorRGBA, 0xFF00, 0x00FF, 0, 0, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_RG16] = PixelFormatDescription("RG16", PixelFormatContent_ColorRGBA, 0xFFFF0000, 0x0000FFFF, 0, 0, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_RG16F] = PixelFormatDescription("RG16F", PixelFormatContent_ColorRGBA, 0xFFFF0000, 0x0000FFFF, 0, 0, PixelFormatSubType_Half); - s_pixelFormatInfos[PixelFormat_RG16I] = PixelFormatDescription("RG16I", PixelFormatContent_ColorRGBA, 0xFFFF0000, 0x0000FFFF, 0, 0, PixelFormatSubType_Int); - s_pixelFormatInfos[PixelFormat_RG16UI] = PixelFormatDescription("RG16UI", PixelFormatContent_ColorRGBA, 0xFFFF0000, 0x0000FFFF, 0, 0, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_RG32F] = PixelFormatDescription("RG32F", PixelFormatContent_ColorRGBA, 0xFFFFFFFF00000000, 0x00000000FFFFFFFF, 0, 0, PixelFormatSubType_Float); - s_pixelFormatInfos[PixelFormat_RG32I] = PixelFormatDescription("RG32I", PixelFormatContent_ColorRGBA, 0xFFFFFFFF00000000, 0x00000000FFFFFFFF, 0, 0, PixelFormatSubType_Int); - s_pixelFormatInfos[PixelFormat_RG32UI] = PixelFormatDescription("RG32UI", PixelFormatContent_ColorRGBA, 0xFFFFFFFF00000000, 0x00000000FFFFFFFF, 0, 0, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_RGB8] = PixelFormatDescription("RGB8", PixelFormatContent_ColorRGBA, 0xFF000000, 0x00FF0000, 0x0000FF00, 0, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_RGB16F] = PixelFormatDescription("RGB16F", PixelFormatContent_ColorRGBA, 0xFFFF00000000, 0x0000FFFF0000, 0x00000000FFFF, 0, PixelFormatSubType_Half); - s_pixelFormatInfos[PixelFormat_RGB16I] = PixelFormatDescription("RGB16I", PixelFormatContent_ColorRGBA, 0xFFFF00000000, 0x0000FFFF0000, 0x00000000FFFF, 0, PixelFormatSubType_Int); - s_pixelFormatInfos[PixelFormat_RGB16UI] = PixelFormatDescription("RGB16UI", PixelFormatContent_ColorRGBA, 0xFFFF000000000000, 0x0000FFFF00000000, 0x00000000FFFF0000, 0, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_RGB32F] = PixelFormatDescription("RGB32F", PixelFormatContent_ColorRGBA, b32, b32 >> 32, b32 >> 64, 0, PixelFormatSubType_Float); - s_pixelFormatInfos[PixelFormat_RGB32I] = PixelFormatDescription("RGB32I", PixelFormatContent_ColorRGBA, b32, b32 >> 32, b32 >> 64, 0, PixelFormatSubType_Int); - s_pixelFormatInfos[PixelFormat_RGB32UI] = PixelFormatDescription("RGB32UI", PixelFormatContent_ColorRGBA, b32, b32 >> 32, b32 >> 64, 0, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_RGBA4] = PixelFormatDescription("RGBA4", PixelFormatContent_ColorRGBA, 0xF000, 0x0F00, 0x00F0, 0x000F, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_RGB5A1] = PixelFormatDescription("RGB5A1", PixelFormatContent_ColorRGBA, 0xF800, 0x07C0, 0x003E, 0x0001, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_RGBA8] = PixelFormatDescription("RGBA8", PixelFormatContent_ColorRGBA, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_RGBA16F] = PixelFormatDescription("RGBA16F", PixelFormatContent_ColorRGBA, 0xFFFF000000000000, 0x0000FFFF00000000, 0x00000000FFFF0000, 0x000000000000FFFF, PixelFormatSubType_Half); - s_pixelFormatInfos[PixelFormat_RGBA16I] = PixelFormatDescription("RGBA16I", PixelFormatContent_ColorRGBA, 0xFFFF000000000000, 0x0000FFFF00000000, 0x00000000FFFF0000, 0x000000000000FFFF, PixelFormatSubType_Int); - s_pixelFormatInfos[PixelFormat_RGBA16UI] = PixelFormatDescription("RGBA16UI", PixelFormatContent_ColorRGBA, 0xFFFF000000000000, 0x0000FFFF00000000, 0x00000000FFFF0000, 0x000000000000FFFF, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_RGBA32F] = PixelFormatDescription("RGBA32F", PixelFormatContent_ColorRGBA, b32, b32 >> 32, b32 >> 64, b32 >> 96, PixelFormatSubType_Float); - s_pixelFormatInfos[PixelFormat_RGBA32I] = PixelFormatDescription("RGBA32I", PixelFormatContent_ColorRGBA, b32, b32 >> 32, b32 >> 64, b32 >> 96, PixelFormatSubType_Int); - s_pixelFormatInfos[PixelFormat_RGBA32UI] = PixelFormatDescription("RGBA32UI", PixelFormatContent_ColorRGBA, b32, b32 >> 32, b32 >> 64, b32 >> 96, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_Depth16] = PixelFormatDescription("Depth16", PixelFormatContent_DepthStencil, 0xFFFF, 0, 0, 0, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_Depth24] = PixelFormatDescription("Depth24", PixelFormatContent_DepthStencil, 0xFFFFFF, 0, 0, 0, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_Depth24Stencil8] = PixelFormatDescription("Depth24Stencil8", PixelFormatContent_DepthStencil, 0xFFFFFF00, 0x000000FF, 0, 0, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_Depth32] = PixelFormatDescription("Depth32", PixelFormatContent_DepthStencil, 0xFFFFFFFF, 0, 0, 0, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_Stencil1] = PixelFormatDescription("Stencil1", PixelFormatContent_Stencil, 0x1, 0, 0, 0, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_Stencil4] = PixelFormatDescription("Stencil4", PixelFormatContent_Stencil, 0xF, 0, 0, 0, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_Stencil8] = PixelFormatDescription("Stencil8", PixelFormatContent_Stencil, 0xFF, 0, 0, 0, PixelFormatSubType_Unsigned); - s_pixelFormatInfos[PixelFormat_Stencil16] = PixelFormatDescription("Stencil16", PixelFormatContent_Stencil, 0xFFFF, 0, 0, 0, PixelFormatSubType_Unsigned); + SetupPixelFormat(PixelFormat::A8, PixelFormatDescription("A8", PixelFormatContent::ColorRGBA, 0, 0, 0, 0xFF, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::BGR8, PixelFormatDescription("BGR8", PixelFormatContent::ColorRGBA, 0x0000FF, 0x00FF00, 0xFF0000, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::BGR8_SRGB, PixelFormatDescription("BGR8_SRGB", PixelFormatContent::ColorRGBA, 0x0000FF, 0x00FF00, 0xFF0000, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::BGRA8, PixelFormatDescription("BGRA8", PixelFormatContent::ColorRGBA, 0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::BGRA8_SRGB, PixelFormatDescription("BGRA8_SRGB", PixelFormatContent::ColorRGBA, 0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::DXT1, PixelFormatDescription("DXT1", PixelFormatContent::ColorRGBA, 8, PixelFormatSubType::Compressed)); + SetupPixelFormat(PixelFormat::DXT3, PixelFormatDescription("DXT3", PixelFormatContent::ColorRGBA, 16, PixelFormatSubType::Compressed)); + SetupPixelFormat(PixelFormat::DXT5, PixelFormatDescription("DXT5", PixelFormatContent::ColorRGBA, 16, PixelFormatSubType::Compressed)); + SetupPixelFormat(PixelFormat::L8, PixelFormatDescription("L8", PixelFormatContent::ColorRGBA, 0xFF, 0xFF, 0xFF, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::LA8, PixelFormatDescription("LA8", PixelFormatContent::ColorRGBA, 0xFF00, 0xFF00, 0xFF00, 0x00FF, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::R8, PixelFormatDescription("R8", PixelFormatContent::ColorRGBA, 0xFF, 0, 0, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::R8I, PixelFormatDescription("R8I", PixelFormatContent::ColorRGBA, 0xFF, 0, 0, 0, PixelFormatSubType::Int)); + SetupPixelFormat(PixelFormat::R8UI, PixelFormatDescription("R8UI", PixelFormatContent::ColorRGBA, 0xFF, 0, 0, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::R16, PixelFormatDescription("R16", PixelFormatContent::ColorRGBA, 0xFFFF, 0, 0, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::R16F, PixelFormatDescription("R16F", PixelFormatContent::ColorRGBA, 0xFFFF, 0, 0, 0, PixelFormatSubType::Half)); + SetupPixelFormat(PixelFormat::R16I, PixelFormatDescription("R16I", PixelFormatContent::ColorRGBA, 0xFFFF, 0, 0, 0, PixelFormatSubType::Int)); + SetupPixelFormat(PixelFormat::R16UI, PixelFormatDescription("R16UI", PixelFormatContent::ColorRGBA, 0xFFFF, 0, 0, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::R32F, PixelFormatDescription("R32F", PixelFormatContent::ColorRGBA, 0xFFFFFFFF, 0, 0, 0, PixelFormatSubType::Float)); + SetupPixelFormat(PixelFormat::R32I, PixelFormatDescription("R32I", PixelFormatContent::ColorRGBA, 0xFFFFFFFF, 0, 0, 0, PixelFormatSubType::Int)); + SetupPixelFormat(PixelFormat::R32UI, PixelFormatDescription("R32UI", PixelFormatContent::ColorRGBA, 0xFFFFFFFF, 0, 0, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::RG8, PixelFormatDescription("RG8", PixelFormatContent::ColorRGBA, 0xFF00, 0x00FF, 0, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::RG8I, PixelFormatDescription("RG8I", PixelFormatContent::ColorRGBA, 0xFF00, 0x00FF, 0, 0, PixelFormatSubType::Int)); + SetupPixelFormat(PixelFormat::RG8UI, PixelFormatDescription("RG8UI", PixelFormatContent::ColorRGBA, 0xFF00, 0x00FF, 0, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::RG16, PixelFormatDescription("RG16", PixelFormatContent::ColorRGBA, 0xFFFF0000, 0x0000FFFF, 0, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::RG16F, PixelFormatDescription("RG16F", PixelFormatContent::ColorRGBA, 0xFFFF0000, 0x0000FFFF, 0, 0, PixelFormatSubType::Half)); + SetupPixelFormat(PixelFormat::RG16I, PixelFormatDescription("RG16I", PixelFormatContent::ColorRGBA, 0xFFFF0000, 0x0000FFFF, 0, 0, PixelFormatSubType::Int)); + SetupPixelFormat(PixelFormat::RG16UI, PixelFormatDescription("RG16UI", PixelFormatContent::ColorRGBA, 0xFFFF0000, 0x0000FFFF, 0, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::RG32F, PixelFormatDescription("RG32F", PixelFormatContent::ColorRGBA, 0xFFFFFFFF00000000, 0x00000000FFFFFFFF, 0, 0, PixelFormatSubType::Float)); + SetupPixelFormat(PixelFormat::RG32I, PixelFormatDescription("RG32I", PixelFormatContent::ColorRGBA, 0xFFFFFFFF00000000, 0x00000000FFFFFFFF, 0, 0, PixelFormatSubType::Int)); + SetupPixelFormat(PixelFormat::RG32UI, PixelFormatDescription("RG32UI", PixelFormatContent::ColorRGBA, 0xFFFFFFFF00000000, 0x00000000FFFFFFFF, 0, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::RGB8, PixelFormatDescription("RGB8", PixelFormatContent::ColorRGBA, 0xFF000000, 0x00FF0000, 0x0000FF00, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::RGB8_SRGB, PixelFormatDescription("RGB8_SRGB", PixelFormatContent::ColorRGBA, 0xFF000000, 0x00FF0000, 0x0000FF00, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::RGB16F, PixelFormatDescription("RGB16F", PixelFormatContent::ColorRGBA, 0xFFFF00000000, 0x0000FFFF0000, 0x00000000FFFF, 0, PixelFormatSubType::Half)); + SetupPixelFormat(PixelFormat::RGB16I, PixelFormatDescription("RGB16I", PixelFormatContent::ColorRGBA, 0xFFFF00000000, 0x0000FFFF0000, 0x00000000FFFF, 0, PixelFormatSubType::Int)); + SetupPixelFormat(PixelFormat::RGB16UI, PixelFormatDescription("RGB16UI", PixelFormatContent::ColorRGBA, 0xFFFF000000000000, 0x0000FFFF00000000, 0x00000000FFFF0000, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::RGB32F, PixelFormatDescription("RGB32F", PixelFormatContent::ColorRGBA, b32, b32 >> 32, b32 >> 64, 0, PixelFormatSubType::Float)); + SetupPixelFormat(PixelFormat::RGB32I, PixelFormatDescription("RGB32I", PixelFormatContent::ColorRGBA, b32, b32 >> 32, b32 >> 64, 0, PixelFormatSubType::Int)); + SetupPixelFormat(PixelFormat::RGB32UI, PixelFormatDescription("RGB32UI", PixelFormatContent::ColorRGBA, b32, b32 >> 32, b32 >> 64, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::RGBA4, PixelFormatDescription("RGBA4", PixelFormatContent::ColorRGBA, 0xF000, 0x0F00, 0x00F0, 0x000F, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::RGB5A1, PixelFormatDescription("RGB5A1", PixelFormatContent::ColorRGBA, 0xF800, 0x07C0, 0x003E, 0x0001, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::RGBA8, PixelFormatDescription("RGBA8", PixelFormatContent::ColorRGBA, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::RGBA8_SRGB, PixelFormatDescription("RGBA8_SRGB", PixelFormatContent::ColorRGBA, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::RGBA16F, PixelFormatDescription("RGBA16F", PixelFormatContent::ColorRGBA, 0xFFFF000000000000, 0x0000FFFF00000000, 0x00000000FFFF0000, 0x000000000000FFFF, PixelFormatSubType::Half)); + SetupPixelFormat(PixelFormat::RGBA16I, PixelFormatDescription("RGBA16I", PixelFormatContent::ColorRGBA, 0xFFFF000000000000, 0x0000FFFF00000000, 0x00000000FFFF0000, 0x000000000000FFFF, PixelFormatSubType::Int)); + SetupPixelFormat(PixelFormat::RGBA16UI, PixelFormatDescription("RGBA16UI", PixelFormatContent::ColorRGBA, 0xFFFF000000000000, 0x0000FFFF00000000, 0x00000000FFFF0000, 0x000000000000FFFF, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::RGBA32F, PixelFormatDescription("RGBA32F", PixelFormatContent::ColorRGBA, b32, b32 >> 32, b32 >> 64, b32 >> 96, PixelFormatSubType::Float)); + SetupPixelFormat(PixelFormat::RGBA32I, PixelFormatDescription("RGBA32I", PixelFormatContent::ColorRGBA, b32, b32 >> 32, b32 >> 64, b32 >> 96, PixelFormatSubType::Int)); + SetupPixelFormat(PixelFormat::RGBA32UI, PixelFormatDescription("RGBA32UI", PixelFormatContent::ColorRGBA, b32, b32 >> 32, b32 >> 64, b32 >> 96, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::Depth16, PixelFormatDescription("Depth16", PixelFormatContent::Depth, 0xFFFF, 0, 0, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::Depth16Stencil8, PixelFormatDescription("Depth16Stencil8", PixelFormatContent::DepthStencil, 0xFFFF0000, 0x0000FF00, 0, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::Depth24, PixelFormatDescription("Depth24", PixelFormatContent::Depth, 0xFFFFFF, 0, 0, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::Depth24Stencil8, PixelFormatDescription("Depth24Stencil8", PixelFormatContent::DepthStencil, 0xFFFFFF00, 0x000000FF, 0, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::Depth32F, PixelFormatDescription("Depth32F", PixelFormatContent::Depth, 0xFFFFFFFF, 0, 0, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::Depth32FStencil8, PixelFormatDescription("Depth32FStencil8", PixelFormatContent::DepthStencil, b32, b8 >> 32, 0, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::Stencil1, PixelFormatDescription("Stencil1", PixelFormatContent::Stencil, 0x1, 0, 0, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::Stencil4, PixelFormatDescription("Stencil4", PixelFormatContent::Stencil, 0xF, 0, 0, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::Stencil8, PixelFormatDescription("Stencil8", PixelFormatContent::Stencil, 0xFF, 0, 0, 0, PixelFormatSubType::Unsigned)); + SetupPixelFormat(PixelFormat::Stencil16, PixelFormatDescription("Stencil16", PixelFormatContent::Stencil, 0xFFFF, 0, 0, 0, PixelFormatSubType::Unsigned)); - for (unsigned int i = 0; i <= PixelFormat_Max; ++i) + for (unsigned int i = 0; i < PixelFormatCount; ++i) { if (!s_pixelFormatInfos[i].Validate()) NazaraWarning("Pixel format 0x" + NumberToString(i, 16) + " (" + GetName(static_cast(i)) + ") failed validation tests"); } - // Reset functions - std::memset(s_convertFunctions, 0, (PixelFormat_Max+1)*(PixelFormat_Max+1)*sizeof(PixelFormatInfo::ConvertFunction)); - /***********************************A8************************************/ - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); /**********************************BGR8***********************************/ - RegisterConverter(); - RegisterConverter(); - RegisterConverter();/* - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter();*/ - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();/* + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();*/ + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); /**********************************BGRA8**********************************/ - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter();/* - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter();*/ - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();/* + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();*/ + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); /**********************************DXT1***********************************/ ///TODO: Décompresseur DXT1 /* - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); */ /**********************************DXT3***********************************/ ///TODO: Décompresseur DXT3 /* - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); */ /**********************************DXT5***********************************/ ///TODO: Décompresseur DXT5 /* - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); */ /***********************************L8************************************/ - RegisterConverter(); - RegisterConverter(); - RegisterConverter();/* - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter();*/ - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();/* + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();*/ + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); /***********************************LA8***********************************/ - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter();/* - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter();*/ - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();/* + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();*/ + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); /**********************************RGBA4**********************************/ - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter();/* - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter();*/ - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();/* + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();*/ + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); /*********************************RGB5A1**********************************/ - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter();/* - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter();*/ - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();/* + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();*/ + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); /**********************************RGB8***********************************/ - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter();/* - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter();*/ - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();/* + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();*/ + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); /**********************************RGBA8**********************************/ - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter();/* - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); - RegisterConverter();*/ - RegisterConverter(); - RegisterConverter(); - RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();/* + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();*/ + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); return true; } void PixelFormatInfo::Uninitialize() { - for (unsigned int i = 0; i <= PixelFormat_Max; ++i) + for (std::size_t i = 0; i < PixelFormatCount; ++i) + { s_pixelFormatInfos[i].Clear(); + for (std::size_t j = 0; j < PixelFormatCount; ++j) + s_convertFunctions[i][j] = nullptr; - std::memset(s_convertFunctions, 0, (PixelFormat_Max+1)*(PixelFormat_Max+1)*sizeof(PixelFormatInfo::ConvertFunction)); - - for (unsigned int i = 0; i <= PixelFlipping_Max; ++i) - s_flipFunctions[i].clear(); + for (std::size_t j = 0; j < PixelFlippingCount; ++j) + s_flipFunctions[i][j] = nullptr; + } } - PixelFormatDescription PixelFormatInfo::s_pixelFormatInfos[PixelFormat_Max + 1]; - PixelFormatInfo::ConvertFunction PixelFormatInfo::s_convertFunctions[PixelFormat_Max+1][PixelFormat_Max+1]; - std::map PixelFormatInfo::s_flipFunctions[PixelFlipping_Max+1]; + std::array, PixelFormatCount> PixelFormatInfo::s_convertFunctions; + std::array, PixelFormatCount> PixelFormatInfo::s_flipFunctions; + std::array PixelFormatInfo::s_pixelFormatInfos; } diff --git a/src/Nazara/Utility/RichTextDrawer.cpp b/src/Nazara/Utility/RichTextDrawer.cpp index b11dce7b2..123c21e91 100644 --- a/src/Nazara/Utility/RichTextDrawer.cpp +++ b/src/Nazara/Utility/RichTextDrawer.cpp @@ -126,7 +126,7 @@ namespace Nz return m_bounds; } - Font* RichTextDrawer::GetFont(std::size_t index) const + const std::shared_ptr& RichTextDrawer::GetFont(std::size_t index) const { NazaraAssert(index < m_fonts.size(), "Font index out of range"); @@ -285,12 +285,12 @@ namespace Nz return *this; } - void RichTextDrawer::AppendNewLine(const Font* font, unsigned int characterSize, float lineSpacingOffset, std::size_t glyphIndex, float glyphPosition) const + void RichTextDrawer::AppendNewLine(const Font& font, unsigned int characterSize, float lineSpacingOffset, std::size_t glyphIndex, float glyphPosition) const { // Ensure we're appending from last line Line& lastLine = m_lines.back(); - const Font::SizeInfo& sizeInfo = font->GetSizeInfo(characterSize); + const Font::SizeInfo& sizeInfo = font.GetSizeInfo(characterSize); float previousDrawPos = m_drawPos.x; @@ -336,12 +336,12 @@ namespace Nz } } - bool RichTextDrawer::GenerateGlyph(Glyph& glyph, char32_t character, float outlineThickness, bool lineWrap, const Font* font, const Color& color, TextStyleFlags style, float lineSpacingOffset, unsigned int characterSize, int renderOrder, int* advance) const + bool RichTextDrawer::GenerateGlyph(Glyph& glyph, char32_t character, float outlineThickness, bool lineWrap, const Font& font, const Color& color, TextStyleFlags style, float lineSpacingOffset, unsigned int characterSize, int renderOrder, int* advance) const { - const Font::Glyph& fontGlyph = font->GetGlyph(characterSize, style, outlineThickness, character); + const Font::Glyph& fontGlyph = font.GetGlyph(characterSize, style, outlineThickness, character); if (fontGlyph.valid && fontGlyph.fauxOutlineThickness <= 0.f) { - glyph.atlas = font->GetAtlas()->GetLayer(fontGlyph.layerIndex); + glyph.atlas = font.GetAtlas()->GetLayer(fontGlyph.layerIndex); glyph.atlasRect = fontGlyph.atlasRect; glyph.color = color; glyph.flipped = fontGlyph.flipped; @@ -376,7 +376,7 @@ namespace Nz return false; }; - void RichTextDrawer::GenerateGlyphs(const Font* font, const Color& color, TextStyleFlags style, unsigned int characterSize, const Color& outlineColor, float characterSpacingOffset, float lineSpacingOffset, float outlineThickness, const std::string& text) const + void RichTextDrawer::GenerateGlyphs(const Font& font, const Color& color, TextStyleFlags style, unsigned int characterSize, const Color& outlineColor, float characterSpacingOffset, float lineSpacingOffset, float outlineThickness, const std::string& text) const { if (text.empty()) return; @@ -391,7 +391,7 @@ namespace Nz char32_t previousCharacter = 0; - const Font::SizeInfo& sizeInfo = font->GetSizeInfo(characterSize); + const Font::SizeInfo& sizeInfo = font.GetSizeInfo(characterSize); float lineHeight = GetLineHeight(lineSpacingOffset, sizeInfo); float heightDifference = lineHeight - m_lines.back().bounds.height; @@ -414,7 +414,7 @@ namespace Nz for (char32_t character : characters) { if (previousCharacter != 0) - m_drawPos.x += font->GetKerning(characterSize, previousCharacter, character); + m_drawPos.x += font.GetKerning(characterSize, previousCharacter, character); previousCharacter = character; @@ -500,7 +500,7 @@ namespace Nz NazaraUnused(font); #ifdef NAZARA_DEBUG - auto it = std::find_if(m_fonts.begin(), m_fonts.end(), [font](const auto& fontData) { return fontData.font == font; }); + auto it = std::find_if(m_fonts.begin(), m_fonts.end(), [font](const auto& fontData) { return fontData.font.get() == font; }); if (it == m_fonts.end()) { NazaraInternalError("Not listening to " + PointerToString(font)); @@ -522,7 +522,7 @@ namespace Nz NazaraUnused(font); #ifdef NAZARA_DEBUG - auto it = std::find_if(m_fonts.begin(), m_fonts.end(), [font](const auto& fontData) { return fontData.font == font; }); + auto it = std::find_if(m_fonts.begin(), m_fonts.end(), [font](const auto& fontData) { return fontData.font.get() == font; }); if (it == m_fonts.end()) { NazaraInternalError("Not listening to " + PointerToString(font)); @@ -539,7 +539,7 @@ namespace Nz NazaraUnused(font); #ifdef NAZARA_DEBUG - auto it = std::find_if(m_fonts.begin(), m_fonts.end(), [font](const auto& fontData) { return fontData.font == font; }); + auto it = std::find_if(m_fonts.begin(), m_fonts.end(), [font](const auto& fontData) { return fontData.font.get() == font; }); if (it == m_fonts.end()) { NazaraInternalError("Not listening to " + PointerToString(font)); @@ -573,7 +573,7 @@ namespace Nz assert(block.fontIndex < m_fonts.size()); const auto& fontData = m_fonts[block.fontIndex]; - GenerateGlyphs(fontData.font, block.color, block.style, block.characterSize, block.outlineColor, block.outlineThickness, block.characterSpacingOffset, block.lineSpacingOffset, block.text); + GenerateGlyphs(*fontData.font, block.color, block.style, block.characterSize, block.outlineColor, block.outlineThickness, block.characterSpacingOffset, block.lineSpacingOffset, block.text); } } else diff --git a/src/Nazara/Utility/SimpleTextDrawer.cpp b/src/Nazara/Utility/SimpleTextDrawer.cpp index 2ff89df99..fd1b18fd3 100644 --- a/src/Nazara/Utility/SimpleTextDrawer.cpp +++ b/src/Nazara/Utility/SimpleTextDrawer.cpp @@ -23,7 +23,7 @@ namespace Nz return m_bounds; } - Font* SimpleTextDrawer::GetFont(std::size_t index) const + const std::shared_ptr& SimpleTextDrawer::GetFont(std::size_t index) const { NazaraAssert(index == 0, "Font index out of range"); NazaraUnused(index); @@ -288,7 +288,7 @@ namespace Nz NazaraUnused(font); #ifdef NAZARA_DEBUG - if (m_font != font) + if (m_font.get() != font) { NazaraInternalError("Not listening to " + PointerToString(font)); return; @@ -309,7 +309,7 @@ namespace Nz NazaraUnused(font); #ifdef NAZARA_DEBUG - if (m_font != font) + if (m_font.get() != font) { NazaraInternalError("Not listening to " + PointerToString(font)); return; @@ -325,7 +325,7 @@ namespace Nz NazaraUnused(font); #ifdef NAZARA_DEBUG - if (m_font != font) + if (m_font.get() != font) { NazaraInternalError("Not listening to " + PointerToString(font)); return; diff --git a/src/Nazara/Utility/SkeletalMesh.cpp b/src/Nazara/Utility/SkeletalMesh.cpp index 21f89da26..da08488d4 100644 --- a/src/Nazara/Utility/SkeletalMesh.cpp +++ b/src/Nazara/Utility/SkeletalMesh.cpp @@ -8,53 +8,14 @@ namespace Nz { - SkeletalMesh::SkeletalMesh(VertexBuffer* vertexBuffer, const IndexBuffer* indexBuffer) : + SkeletalMesh::SkeletalMesh(std::shared_ptr vertexBuffer, std::shared_ptr indexBuffer) : m_aabb(Nz::Boxf::Zero()), - m_indexBuffer(indexBuffer), - m_vertexBuffer(vertexBuffer) + m_indexBuffer(std::move(indexBuffer)), + m_vertexBuffer(std::move(vertexBuffer)) { NazaraAssert(m_vertexBuffer, "Invalid vertex buffer"); } - SkeletalMesh::SkeletalMesh(const Mesh* /*parent*/) : - m_aabb(Nz::Boxf::Zero()) - { - } - - SkeletalMesh::~SkeletalMesh() - { - OnSkeletalMeshRelease(this); - - Destroy(); - } - - bool SkeletalMesh::Create(VertexBuffer* vertexBuffer) - { - Destroy(); - - #if NAZARA_UTILITY_SAFE - if (!vertexBuffer) - { - NazaraError("Invalid vertex buffer"); - return false; - } - #endif - - m_vertexBuffer = vertexBuffer; - return true; - } - - void SkeletalMesh::Destroy() - { - if (m_vertexBuffer) - { - OnSkeletalMeshDestroy(this); - - m_indexBuffer.Reset(); - m_vertexBuffer.Reset(); - } - } - const Boxf& SkeletalMesh::GetAABB() const { return m_aabb; @@ -62,20 +23,15 @@ namespace Nz AnimationType SkeletalMesh::GetAnimationType() const { - return AnimationType_Skeletal; + return AnimationType::Skeletal; } - const IndexBuffer* SkeletalMesh::GetIndexBuffer() const + const std::shared_ptr& SkeletalMesh::GetIndexBuffer() const { return m_indexBuffer; } - VertexBuffer* SkeletalMesh::GetVertexBuffer() - { - return m_vertexBuffer; - } - - const VertexBuffer* SkeletalMesh::GetVertexBuffer() const + const std::shared_ptr& SkeletalMesh::GetVertexBuffer() const { return m_vertexBuffer; } @@ -102,8 +58,8 @@ namespace Nz OnSubMeshInvalidateAABB(this); } - void SkeletalMesh::SetIndexBuffer(const IndexBuffer* indexBuffer) + void SkeletalMesh::SetIndexBuffer(std::shared_ptr indexBuffer) { - m_indexBuffer = indexBuffer; + m_indexBuffer = std::move(indexBuffer); } } diff --git a/src/Nazara/Utility/Skeleton.cpp b/src/Nazara/Utility/Skeleton.cpp index 6927c27cd..0e48b1cc2 100644 --- a/src/Nazara/Utility/Skeleton.cpp +++ b/src/Nazara/Utility/Skeleton.cpp @@ -18,58 +18,36 @@ namespace Nz bool jointMapUpdated = false; }; - Skeleton::Skeleton(const Skeleton& skeleton) : - RefCounted(), - m_impl(nullptr) + Skeleton::Skeleton() = default; + + Skeleton::Skeleton(const Skeleton& skeleton) { operator=(skeleton); } - Skeleton::~Skeleton() - { - OnSkeletonRelease(this); - - Destroy(); - } + Skeleton::Skeleton(Skeleton&&) noexcept = default; + Skeleton::~Skeleton() = default; bool Skeleton::Create(std::size_t jointCount) { - #if NAZARA_UTILITY_SAFE - if (jointCount == 0) - { - NazaraError("Joint count must be over zero"); - return false; - } - #endif + NazaraAssert(jointCount > 0, "joint count must be over zero"); - m_impl = new SkeletonImpl; - m_impl->joints.resize(jointCount, Joint(this)); + m_impl = std::make_unique(); + m_impl->joints.reserve(jointCount); + for (std::size_t i = 0; i < jointCount; ++i) + m_impl->joints.emplace_back(this); return true; } void Skeleton::Destroy() { - if (m_impl) - { - OnSkeletonDestroy(this); - - delete m_impl; - m_impl = nullptr; - } + m_impl.reset(); } const Boxf& Skeleton::GetAABB() const { - #if NAZARA_UTILITY_SAFE - if (!m_impl) - { - NazaraError("Skeleton not created"); - - static Boxf dummy; - return dummy; - } - #endif + NazaraAssert(m_impl, "skeleton must have been created"); if (!m_impl->aabbUpdated) { @@ -92,242 +70,111 @@ namespace Nz Joint* Skeleton::GetJoint(const std::string& jointName) { - #if NAZARA_UTILITY_SAFE - if (!m_impl) - { - NazaraError("Skeleton not created"); - return nullptr; - } - #endif + NazaraAssert(m_impl, "skeleton must have been created"); if (!m_impl->jointMapUpdated) UpdateJointMap(); auto it = m_impl->jointMap.find(jointName); - - #if NAZARA_UTILITY_SAFE - if (it == m_impl->jointMap.end()) - { - NazaraError("Joint not found"); - return nullptr; - } - #endif + NazaraAssert(it != m_impl->jointMap.end(), "joint not found"); InvalidateJoints(); - return &m_impl->joints[it->second]; } Joint* Skeleton::GetJoint(std::size_t index) { - #if NAZARA_UTILITY_SAFE - if (!m_impl) - { - NazaraError("Skeleton not created"); - return nullptr; - } - - if (index >= m_impl->joints.size()) - { - NazaraError("Joint index out of range (" + NumberToString(index) + " >= " + NumberToString(m_impl->joints.size()) + ')'); - return nullptr; - } - #endif + NazaraAssert(m_impl, "skeleton must have been created"); + NazaraAssert(index < m_impl->joints.size(), "joint index out of range"); InvalidateJoints(); - return &m_impl->joints[index]; } const Joint* Skeleton::GetJoint(const std::string& jointName) const { - #if NAZARA_UTILITY_SAFE - if (!m_impl) - { - NazaraError("Skeleton not created"); - return nullptr; - } - #endif + NazaraAssert(m_impl, "skeleton must have been created"); if (!m_impl->jointMapUpdated) UpdateJointMap(); auto it = m_impl->jointMap.find(jointName); - - #if NAZARA_UTILITY_SAFE - if (it == m_impl->jointMap.end()) - { - NazaraError("Joint not found"); - return nullptr; - } - #endif + NazaraAssert(it != m_impl->jointMap.end(), "joint not found"); return &m_impl->joints[it->second]; } const Joint* Skeleton::GetJoint(std::size_t index) const { - #if NAZARA_UTILITY_SAFE - if (!m_impl) - { - NazaraError("Skeleton not created"); - return nullptr; - } - - if (index >= m_impl->joints.size()) - { - NazaraError("Joint index out of range (" + NumberToString(index) + " >= " + NumberToString(m_impl->joints.size()) + ')'); - return nullptr; - } - #endif + NazaraAssert(m_impl, "skeleton must have been created"); + NazaraAssert(index < m_impl->joints.size(), "joint index out of range"); return &m_impl->joints[index]; } Joint* Skeleton::GetJoints() { - #if NAZARA_UTILITY_SAFE - if (!m_impl) - { - NazaraError("Skeleton not created"); - return nullptr; - } - #endif + NazaraAssert(m_impl, "skeleton must have been created"); + InvalidateJoints(); return &m_impl->joints[0]; } const Joint* Skeleton::GetJoints() const { - #if NAZARA_UTILITY_SAFE - if (!m_impl) - { - NazaraError("Skeleton not created"); - return nullptr; - } - #endif - + NazaraAssert(m_impl, "skeleton must have been created"); return &m_impl->joints[0]; } std::size_t Skeleton::GetJointCount() const { - #if NAZARA_UTILITY_SAFE - if (!m_impl) - { - NazaraError("Skeleton not created"); - return 0; - } - #endif - + NazaraAssert(m_impl, "skeleton must have been created"); return static_cast(m_impl->joints.size()); } - int Skeleton::GetJointIndex(const std::string& jointName) const + std::size_t Skeleton::GetJointIndex(const std::string& jointName) const { - #if NAZARA_UTILITY_SAFE - if (!m_impl) - { - NazaraError("Skeleton not created"); - return -1; - } - #endif + NazaraAssert(m_impl, "skeleton must have been created"); if (!m_impl->jointMapUpdated) UpdateJointMap(); auto it = m_impl->jointMap.find(jointName); - - #if NAZARA_UTILITY_SAFE - if (it == m_impl->jointMap.end()) - { - NazaraError("Joint not found"); - return -1; - } - #endif + NazaraAssert(it != m_impl->jointMap.end(), "joint not found"); return it->second; } void Skeleton::Interpolate(const Skeleton& skeletonA, const Skeleton& skeletonB, float interpolation) { - #if NAZARA_UTILITY_SAFE - if (!m_impl) - { - NazaraError("Skeleton not created"); - return; - } + NazaraAssert(m_impl, "skeleton must have been created"); + NazaraAssert(skeletonA.IsValid(), "first skeleton is invalid"); + NazaraAssert(skeletonB.IsValid(), "second skeleton is invalid"); + NazaraAssert(skeletonA.GetJointCount() == skeletonB.GetJointCount() && m_impl->joints.size() == skeletonA.GetJointCount(), "both skeletons must have the same number of joints"); - if (!skeletonA.IsValid()) - { - NazaraError("Skeleton A is invalid"); - return; - } - - if (!skeletonB.IsValid()) - { - NazaraError("Skeleton B is invalid"); - return; - } - - if (skeletonA.GetJointCount() != skeletonB.GetJointCount() || m_impl->joints.size() != skeletonA.GetJointCount()) - { - NazaraError("Skeletons must have the same joint count"); - return; - } - #endif - - Joint* jointsA = &skeletonA.m_impl->joints[0]; - Joint* jointsB = &skeletonB.m_impl->joints[0]; + const Joint* jointsA = &skeletonA.m_impl->joints[0]; + const Joint* jointsB = &skeletonB.m_impl->joints[0]; for (std::size_t i = 0; i < m_impl->joints.size(); ++i) - m_impl->joints[i].Interpolate(jointsA[i], jointsB[i], interpolation, CoordSys_Local); + m_impl->joints[i].Interpolate(jointsA[i], jointsB[i], interpolation, CoordSys::Local); InvalidateJoints(); } - void Skeleton::Interpolate(const Skeleton& skeletonA, const Skeleton& skeletonB, float interpolation, std::size_t* indices, std::size_t indiceCount) + void Skeleton::Interpolate(const Skeleton& skeletonA, const Skeleton& skeletonB, float interpolation, const std::size_t* indices, std::size_t indiceCount) { - #if NAZARA_UTILITY_SAFE - if (!m_impl) - { - NazaraError("Skeleton not created"); - return; - } - - if (!skeletonA.IsValid()) - { - NazaraError("Skeleton A is invalid"); - return; - } - - if (!skeletonB.IsValid()) - { - NazaraError("Skeleton B is invalid"); - return; - } - - if (skeletonA.GetJointCount() != skeletonB.GetJointCount() || m_impl->joints.size() != skeletonA.GetJointCount()) - { - NazaraError("Skeletons must have the same joint count"); - return; - } - #endif + NazaraAssert(m_impl, "skeleton must have been created"); + NazaraAssert(skeletonA.IsValid(), "first skeleton is invalid"); + NazaraAssert(skeletonB.IsValid(), "second skeleton is invalid"); + NazaraAssert(skeletonA.GetJointCount() == skeletonB.GetJointCount() && m_impl->joints.size() == skeletonA.GetJointCount(), "both skeletons must have the same number of joints"); const Joint* jointsA = &skeletonA.m_impl->joints[0]; const Joint* jointsB = &skeletonB.m_impl->joints[0]; for (std::size_t i = 0; i < indiceCount; ++i) { std::size_t index = indices[i]; + NazaraAssert(index < m_impl->joints.size(), "joint index out of range"); - #if NAZARA_UTILITY_SAFE - if (index >= m_impl->joints.size()) - { - NazaraError("Index #" + NumberToString(i) + " out of range (" + NumberToString(index) + " >= " + NumberToString(m_impl->joints.size()) + ')'); - return; - } - #endif - - m_impl->joints[index].Interpolate(jointsA[index], jointsB[index], interpolation, CoordSys_Local); + m_impl->joints[index].Interpolate(jointsA[index], jointsB[index], interpolation, CoordSys::Local); } InvalidateJoints(); @@ -347,7 +194,7 @@ namespace Nz if (skeleton.m_impl) { - m_impl = new SkeletonImpl; + m_impl = std::make_unique(); m_impl->jointMap = skeleton.m_impl->jointMap; m_impl->jointMapUpdated = skeleton.m_impl->jointMapUpdated; m_impl->joints = skeleton.m_impl->joints; @@ -376,6 +223,8 @@ namespace Nz return *this; } + Skeleton& Skeleton::operator=(Skeleton&&) noexcept = default; + void Skeleton::InvalidateJoints() { m_impl->aabbUpdated = false; @@ -385,26 +234,13 @@ namespace Nz void Skeleton::InvalidateJointMap() { - #ifdef NAZARA_DEBUG - if (!m_impl) - { - NazaraError("Invalid skeleton"); - return; - } - #endif - + NazaraAssert(m_impl, "skeleton must have been created"); m_impl->jointMapUpdated = false; } void Skeleton::UpdateJointMap() const { - #ifdef NAZARA_DEBUG - if (!m_impl) - { - NazaraError("Invalid skeleton"); - return; - } - #endif + NazaraAssert(m_impl, "skeleton must have been created"); m_impl->jointMap.clear(); for (std::size_t i = 0; i < m_impl->joints.size(); ++i) @@ -420,22 +256,4 @@ namespace Nz m_impl->jointMapUpdated = true; } - - bool Skeleton::Initialize() - { - if (!SkeletonLibrary::Initialize()) - { - NazaraError("Failed to initialise library"); - return false; - } - - return true; - } - - void Skeleton::Uninitialize() - { - SkeletonLibrary::Uninitialize(); - } - - SkeletonLibrary::LibraryMap Skeleton::s_library; } diff --git a/src/Nazara/Utility/SoftwareBuffer.cpp b/src/Nazara/Utility/SoftwareBuffer.cpp index d5c9b1010..d2ecad060 100644 --- a/src/Nazara/Utility/SoftwareBuffer.cpp +++ b/src/Nazara/Utility/SoftwareBuffer.cpp @@ -52,7 +52,7 @@ namespace Nz DataStorage SoftwareBuffer::GetStorage() const { - return DataStorage_Software; + return DataStorage::Software; } void* SoftwareBuffer::Map(BufferAccess /*access*/, UInt64 offset, UInt64 /*size*/) diff --git a/src/Nazara/Utility/StaticMesh.cpp b/src/Nazara/Utility/StaticMesh.cpp index 3d17f3638..b8ac35661 100644 --- a/src/Nazara/Utility/StaticMesh.cpp +++ b/src/Nazara/Utility/StaticMesh.cpp @@ -10,32 +10,20 @@ namespace Nz { - StaticMesh::StaticMesh(VertexBuffer* vertexBuffer, const IndexBuffer* indexBuffer) : + StaticMesh::StaticMesh(std::shared_ptr vertexBuffer, std::shared_ptr indexBuffer) : m_aabb(Nz::Boxf::Zero()), - m_indexBuffer(indexBuffer), - m_vertexBuffer(vertexBuffer) + m_indexBuffer(std::move(indexBuffer)), + m_vertexBuffer(std::move(vertexBuffer)) { NazaraAssert(m_vertexBuffer, "Invalid vertex buffer"); } - StaticMesh::StaticMesh(const Mesh* /*parent*/) : - m_aabb(Nz::Boxf::Zero()) - { - } - - StaticMesh::~StaticMesh() - { - OnStaticMeshRelease(this); - - Destroy(); - } - void StaticMesh::Center() { Vector3f offset(m_aabb.x + m_aabb.width/2.f, m_aabb.y + m_aabb.height/2.f, m_aabb.z + m_aabb.depth/2.f); - VertexMapper mapper(m_vertexBuffer); - SparsePtr position = mapper.GetComponentPtr(VertexComponent_Position); + VertexMapper mapper(*m_vertexBuffer); + SparsePtr position = mapper.GetComponentPtr(VertexComponent::Position); unsigned int vertexCount = m_vertexBuffer->GetVertexCount(); for (unsigned int i = 0; i < vertexCount; ++i) @@ -46,38 +34,11 @@ namespace Nz m_aabb.z -= offset.z; } - bool StaticMesh::Create(VertexBuffer* vertexBuffer) - { - Destroy(); - - #if NAZARA_UTILITY_SAFE - if (!vertexBuffer) - { - NazaraError("Invalid vertex buffer"); - return false; - } - #endif - - m_vertexBuffer = vertexBuffer; - return true; - } - - void StaticMesh::Destroy() - { - if (m_vertexBuffer) - { - OnStaticMeshDestroy(this); - - m_indexBuffer.Reset(); - m_vertexBuffer.Reset(); - } - } - bool StaticMesh::GenerateAABB() { // On lock le buffer pour itérer sur toutes les positions et composer notre AABB - VertexMapper mapper(m_vertexBuffer, BufferAccess_ReadOnly); - SetAABB(ComputeAABB(mapper.GetComponentPtr(VertexComponent_Position), m_vertexBuffer->GetVertexCount())); + VertexMapper mapper(*m_vertexBuffer, BufferAccess::ReadOnly); + SetAABB(ComputeAABB(mapper.GetComponentPtr(VertexComponent::Position), m_vertexBuffer->GetVertexCount())); return true; } @@ -89,20 +50,15 @@ namespace Nz AnimationType StaticMesh::GetAnimationType() const { - return AnimationType_Static; + return AnimationType::Static; } - const IndexBuffer* StaticMesh::GetIndexBuffer() const + const std::shared_ptr& StaticMesh::GetIndexBuffer() const { return m_indexBuffer; } - VertexBuffer* StaticMesh::GetVertexBuffer() - { - return m_vertexBuffer; - } - - const VertexBuffer* StaticMesh::GetVertexBuffer() const + const std::shared_ptr& StaticMesh::GetVertexBuffer() const { return m_vertexBuffer; } @@ -129,8 +85,8 @@ namespace Nz OnSubMeshInvalidateAABB(this); } - void StaticMesh::SetIndexBuffer(const IndexBuffer* indexBuffer) + void StaticMesh::SetIndexBuffer(std::shared_ptr indexBuffer) { - m_indexBuffer = indexBuffer; + m_indexBuffer = std::move(indexBuffer); } } diff --git a/src/Nazara/Utility/SubMesh.cpp b/src/Nazara/Utility/SubMesh.cpp index 375fdebb2..c53489888 100644 --- a/src/Nazara/Utility/SubMesh.cpp +++ b/src/Nazara/Utility/SubMesh.cpp @@ -12,36 +12,27 @@ namespace Nz { SubMesh::SubMesh() : - RefCounted(false), // wut - m_primitiveMode(PrimitiveMode_TriangleList), + m_primitiveMode(PrimitiveMode::TriangleList), m_matIndex(0) { } - SubMesh::SubMesh(const Mesh* /*parent*/) : - SubMesh() - { - } - - SubMesh::~SubMesh() - { - OnSubMeshRelease(this); - } + SubMesh::~SubMesh() = default; void SubMesh::GenerateNormals() { - VertexMapper mapper(this); + VertexMapper mapper(*this); std::size_t vertexCount = mapper.GetVertexCount(); - SparsePtr normals = mapper.GetComponentPtr(VertexComponent_Normal); - SparsePtr positions = mapper.GetComponentPtr(VertexComponent_Position); + SparsePtr normals = mapper.GetComponentPtr(VertexComponent::Normal); + SparsePtr positions = mapper.GetComponentPtr(VertexComponent::Position); if (!normals || !positions) return; for (std::size_t i = 0; i < vertexCount; ++i) normals[i].MakeZero(); - TriangleIterator iterator(this); + TriangleIterator iterator(*this); do { Vector3f pos0 = positions[iterator[0]]; @@ -63,13 +54,13 @@ namespace Nz void SubMesh::GenerateNormalsAndTangents() { - VertexMapper mapper(this); + VertexMapper mapper(*this); std::size_t vertexCount = mapper.GetVertexCount(); - SparsePtr normals = mapper.GetComponentPtr(VertexComponent_Normal); - SparsePtr positions = mapper.GetComponentPtr(VertexComponent_Position); - SparsePtr tangents = mapper.GetComponentPtr(VertexComponent_Tangent); - SparsePtr texCoords = mapper.GetComponentPtr(VertexComponent_TexCoord); + SparsePtr normals = mapper.GetComponentPtr(VertexComponent::Normal); + SparsePtr positions = mapper.GetComponentPtr(VertexComponent::Position); + SparsePtr tangents = mapper.GetComponentPtr(VertexComponent::Tangent); + SparsePtr texCoords = mapper.GetComponentPtr(VertexComponent::TexCoord); if (!normals || !positions || !tangents || !texCoords) return; @@ -79,7 +70,7 @@ namespace Nz tangents[i].MakeZero(); } - TriangleIterator iterator(this); + TriangleIterator iterator(*this); do { Vector3f pos0 = positions[iterator[0]]; @@ -121,16 +112,16 @@ namespace Nz void SubMesh::GenerateTangents() { - VertexMapper mapper(this); + VertexMapper mapper(*this); - SparsePtr normals = mapper.GetComponentPtr(VertexComponent_Normal); - SparsePtr positions = mapper.GetComponentPtr(VertexComponent_Position); - SparsePtr tangents = mapper.GetComponentPtr(VertexComponent_Tangent); - SparsePtr texCoords = mapper.GetComponentPtr(VertexComponent_TexCoord); + SparsePtr normals = mapper.GetComponentPtr(VertexComponent::Normal); + SparsePtr positions = mapper.GetComponentPtr(VertexComponent::Position); + SparsePtr tangents = mapper.GetComponentPtr(VertexComponent::Tangent); + SparsePtr texCoords = mapper.GetComponentPtr(VertexComponent::TexCoord); if (!normals || !positions || !tangents || !texCoords) return; - TriangleIterator iterator(this); + TriangleIterator iterator(*this); do { Vector3f pos0 = positions[iterator[0]]; @@ -170,7 +161,7 @@ namespace Nz std::size_t SubMesh::GetTriangleCount() const { - const IndexBuffer* indexBuffer = GetIndexBuffer(); + const std::shared_ptr& indexBuffer = GetIndexBuffer(); std::size_t indexCount; if (indexBuffer) indexCount = indexBuffer->GetIndexCount(); @@ -179,22 +170,22 @@ namespace Nz switch (m_primitiveMode) { - case PrimitiveMode_LineList: - case PrimitiveMode_LineStrip: - case PrimitiveMode_PointList: + case PrimitiveMode::LineList: + case PrimitiveMode::LineStrip: + case PrimitiveMode::PointList: return 0; - case PrimitiveMode_TriangleFan: + case PrimitiveMode::TriangleFan: return (indexCount - 1) / 2; - case PrimitiveMode_TriangleList: + case PrimitiveMode::TriangleList: return indexCount / 3; - case PrimitiveMode_TriangleStrip: + case PrimitiveMode::TriangleStrip: return indexCount - 2; } - NazaraError("Primitive mode not handled (0x" + NumberToString(m_primitiveMode, 16) + ')'); + NazaraError("Primitive mode not handled (0x" + NumberToString(UnderlyingCast(m_primitiveMode), 16) + ')'); return 0; } diff --git a/src/Nazara/Utility/TriangleIterator.cpp b/src/Nazara/Utility/TriangleIterator.cpp index 66b085ac2..a5ce21e2d 100644 --- a/src/Nazara/Utility/TriangleIterator.cpp +++ b/src/Nazara/Utility/TriangleIterator.cpp @@ -8,9 +8,9 @@ namespace Nz { - TriangleIterator::TriangleIterator(PrimitiveMode primitiveMode, const IndexBuffer* indexBuffer) : + TriangleIterator::TriangleIterator(PrimitiveMode primitiveMode, const IndexBuffer& indexBuffer) : m_primitiveMode(primitiveMode), - m_indexMapper(indexBuffer, BufferAccess_ReadOnly) + m_indexMapper(indexBuffer, BufferAccess::ReadOnly) { m_currentIndex = 3; m_triangleIndices[0] = m_indexMapper.Get(0); @@ -20,9 +20,9 @@ namespace Nz m_indexCount = m_indexMapper.GetIndexCount(); } - TriangleIterator::TriangleIterator(const SubMesh* subMesh) : - m_primitiveMode(subMesh->GetPrimitiveMode()), - m_indexMapper(subMesh, BufferAccess_ReadOnly) + TriangleIterator::TriangleIterator(const SubMesh& subMesh) : + m_primitiveMode(subMesh.GetPrimitiveMode()), + m_indexMapper(subMesh, BufferAccess::ReadOnly) { m_currentIndex = 3; m_triangleIndices[0] = m_indexMapper.Get(0); @@ -42,18 +42,18 @@ namespace Nz switch (m_primitiveMode) { - case PrimitiveMode_TriangleFan: + case PrimitiveMode::TriangleFan: m_triangleIndices[1] = m_indexMapper.Get(m_currentIndex++); m_triangleIndices[2] = m_indexMapper.Get(m_currentIndex++); break; - case PrimitiveMode_TriangleList: + case PrimitiveMode::TriangleList: m_triangleIndices[0] = m_indexMapper.Get(m_currentIndex++); m_triangleIndices[1] = m_indexMapper.Get(m_currentIndex++); m_triangleIndices[2] = m_indexMapper.Get(m_currentIndex++); break; - case PrimitiveMode_TriangleStrip: + case PrimitiveMode::TriangleStrip: m_triangleIndices[2] = m_indexMapper.Get(m_currentIndex++); m_triangleIndices[0] = m_triangleIndices[1]; m_triangleIndices[1] = m_triangleIndices[2]; diff --git a/src/Nazara/Utility/UniformBuffer.cpp b/src/Nazara/Utility/UniformBuffer.cpp index 4e0d83f15..6fe544f4e 100644 --- a/src/Nazara/Utility/UniformBuffer.cpp +++ b/src/Nazara/Utility/UniformBuffer.cpp @@ -10,37 +10,24 @@ namespace Nz { - UniformBuffer::UniformBuffer(BufferRef buffer) + UniformBuffer::UniformBuffer(std::shared_ptr buffer) { - ErrorFlags(ErrorFlag_ThrowException, true); + ErrorFlags(ErrorMode::ThrowException, true); Reset(std::move(buffer)); } - UniformBuffer::UniformBuffer(BufferRef buffer, UInt32 offset, UInt32 size) + UniformBuffer::UniformBuffer(std::shared_ptr buffer, UInt32 offset, UInt32 size) { - ErrorFlags(ErrorFlag_ThrowException, true); + ErrorFlags(ErrorMode::ThrowException, true); Reset(std::move(buffer), offset, size); } UniformBuffer::UniformBuffer(UInt32 length, DataStorage storage, BufferUsageFlags usage) { - ErrorFlags(ErrorFlag_ThrowException, true); + ErrorFlags(ErrorMode::ThrowException, true); Reset(length, storage, usage); } - UniformBuffer::UniformBuffer(const UniformBuffer& uniformBuffer) : - RefCounted(), - m_buffer(uniformBuffer.m_buffer), - m_endOffset(uniformBuffer.m_endOffset), - m_startOffset(uniformBuffer.m_startOffset) - { - } - - UniformBuffer::~UniformBuffer() - { - OnUniformBufferRelease(this); - } - bool UniformBuffer::Fill(const void* data, UInt32 offset, UInt32 size) { NazaraAssert(m_buffer && m_buffer->IsValid(), "Invalid buffer"); @@ -67,20 +54,20 @@ namespace Nz void UniformBuffer::Reset() { - m_buffer.Reset(); + m_buffer.reset(); } - void UniformBuffer::Reset(BufferRef buffer) + void UniformBuffer::Reset(std::shared_ptr buffer) { NazaraAssert(buffer && buffer->IsValid(), "Invalid buffer"); Reset(buffer, 0, buffer->GetSize()); } - void UniformBuffer::Reset(BufferRef buffer, UInt32 offset, UInt32 size) + void UniformBuffer::Reset(std::shared_ptr buffer, UInt32 offset, UInt32 size) { NazaraAssert(buffer && buffer->IsValid(), "Invalid buffer"); - NazaraAssert(buffer->GetType() == BufferType_Uniform, "Buffer must be an uniform buffer"); + NazaraAssert(buffer->GetType() == BufferType::Uniform, "Buffer must be an uniform buffer"); NazaraAssert(size > 0, "Invalid size"); NazaraAssert(offset + size > buffer->GetSize(), "Virtual buffer exceed buffer bounds"); @@ -94,7 +81,7 @@ namespace Nz m_endOffset = size; m_startOffset = 0; - m_buffer = Buffer::New(BufferType_Uniform, m_endOffset, storage, usage); + m_buffer = std::make_shared(BufferType::Uniform, m_endOffset, storage, usage); } void UniformBuffer::Reset(const UniformBuffer& uniformBuffer) @@ -108,11 +95,4 @@ namespace Nz { m_buffer->Unmap(); } - - UniformBuffer& UniformBuffer::operator=(const UniformBuffer& uniformBuffer) - { - Reset(uniformBuffer); - - return *this; - } } diff --git a/src/Nazara/Utility/Utility.cpp b/src/Nazara/Utility/Utility.cpp index f07f27fe5..b1ca74d80 100644 --- a/src/Nazara/Utility/Utility.cpp +++ b/src/Nazara/Utility/Utility.cpp @@ -39,27 +39,15 @@ namespace Nz Utility::Utility(Config /*config*/) : ModuleBase("Utility", this) { - if (!Animation::Initialize()) - throw std::runtime_error("failed to initialize animations"); - if (!Buffer::Initialize()) throw std::runtime_error("failed to initialize buffers"); if (!Font::Initialize()) throw std::runtime_error("failed to initialize fonts"); - if (!Image::Initialize()) - throw std::runtime_error("failed to initialize images"); - - if (!Mesh::Initialize()) - throw std::runtime_error("failed to initialize meshes"); - if (!PixelFormatInfo::Initialize()) throw std::runtime_error("failed to initialize pixel formats"); - if (!Skeleton::Initialize()) - throw std::runtime_error("failed to initialize skeletons"); - if (!VertexDeclaration::Initialize()) throw std::runtime_error("failed to initialize vertex declarations"); @@ -68,50 +56,99 @@ namespace Nz /// Loaders génériques // Font - Loaders::RegisterFreeType(); + if (Loaders::InitializeFreeType()) + m_fontLoader.RegisterLoader(Loaders::GetFontLoader_FreeType()); // Image - Loaders::RegisterDDSLoader(); // DDS Loader (DirectX format) - Loaders::RegisterSTBLoader(); // Generic loader (STB) - Loaders::RegisterSTBSaver(); // Generic saver (STB) + m_imageLoader.RegisterLoader(Loaders::GetImageLoader_STB()); // Generic loader (STB) + m_imageSaver.RegisterSaver(Loaders::GetImageSaver_STB()); // Generic saver (STB) /// Loaders spécialisés // Animation - Loaders::RegisterMD5Anim(); // Loader de fichiers .md5anim (v10) + m_animationLoader.RegisterLoader(Loaders::GetAnimationLoader_MD5Anim()); // Loader de fichiers .md5anim (v10) // Mesh (text) - Loaders::RegisterOBJLoader(); - Loaders::RegisterOBJSaver(); + m_meshLoader.RegisterLoader(Loaders::GetMeshLoader_OBJ()); + m_meshSaver.RegisterSaver(Loaders::GetMeshSaver_OBJ()); // Mesh - Loaders::RegisterMD2(); // Loader de fichiers .md2 (v8) - Loaders::RegisterMD5Mesh(); // Loader de fichiers .md5mesh (v10) - Loaders::RegisterOBJLoader(); // Loader de fichiers .md5mesh (v10) + m_meshLoader.RegisterLoader(Loaders::GetMeshLoader_MD2()); // .md2 (v8) + m_meshLoader.RegisterLoader(Loaders::GetMeshLoader_MD5Mesh()); // .md5mesh (v10) + m_meshLoader.RegisterLoader(Loaders::GetMeshLoader_OBJ()); // .obj // Image - Loaders::RegisterPCX(); // Loader de fichiers .pcx (1, 4, 8, 24 bits) + m_imageLoader.RegisterLoader(Loaders::GetImageLoader_DDS()); // DDS Loader (DirectX format) + m_imageLoader.RegisterLoader(Loaders::GetImageLoader_PCX()); // .pcx loader (1, 4, 8, 24 bits) } Utility::~Utility() { - Loaders::UnregisterFreeType(); - Loaders::UnregisterMD2(); - Loaders::UnregisterMD5Anim(); - Loaders::UnregisterMD5Mesh(); - Loaders::UnregisterOBJLoader(); - Loaders::UnregisterOBJSaver(); - Loaders::UnregisterPCX(); - Loaders::UnregisterSTBLoader(); - Loaders::UnregisterSTBSaver(); + Loaders::UninitializeFreeType(); VertexDeclaration::Uninitialize(); - Skeleton::Uninitialize(); PixelFormatInfo::Uninitialize(); - Mesh::Uninitialize(); - Image::Uninitialize(); Font::Uninitialize(); Buffer::Uninitialize(); - Animation::Uninitialize(); + } + + AnimationLoader& Utility::GetAnimationLoader() + { + return m_animationLoader; + } + + const AnimationLoader& Utility::GetAnimationLoader() const + { + return m_animationLoader; + } + + FontLoader& Utility::GetFontLoader() + { + return m_fontLoader; + } + + const FontLoader& Utility::GetFontLoader() const + { + return m_fontLoader; + } + + ImageLoader& Utility::GetImageLoader() + { + return m_imageLoader; + } + + const ImageLoader& Utility::GetImageLoader() const + { + return m_imageLoader; + } + + ImageSaver& Utility::GetImageSaver() + { + return m_imageSaver; + } + + const ImageSaver& Utility::GetImageSaver() const + { + return m_imageSaver; + } + + MeshLoader& Utility::GetMeshLoader() + { + return m_meshLoader; + } + + const MeshLoader& Utility::GetMeshLoader() const + { + return m_meshLoader; + } + + MeshSaver& Utility::GetMeshSaver() + { + return m_meshSaver; + } + + const MeshSaver& Utility::GetMeshSaver() const + { + return m_meshSaver; } Utility* Utility::s_instance = nullptr; diff --git a/src/Nazara/Utility/VertexBuffer.cpp b/src/Nazara/Utility/VertexBuffer.cpp index c4fff82fb..edff32a2c 100644 --- a/src/Nazara/Utility/VertexBuffer.cpp +++ b/src/Nazara/Utility/VertexBuffer.cpp @@ -9,39 +9,24 @@ namespace Nz { - VertexBuffer::VertexBuffer(VertexDeclarationConstRef vertexDeclaration, BufferRef buffer) + VertexBuffer::VertexBuffer(std::shared_ptr vertexDeclaration, std::shared_ptr buffer) { - ErrorFlags(ErrorFlag_ThrowException, true); + ErrorFlags(ErrorMode::ThrowException, true); Reset(std::move(vertexDeclaration), std::move(buffer)); } - VertexBuffer::VertexBuffer(VertexDeclarationConstRef vertexDeclaration, BufferRef buffer, std::size_t offset, std::size_t size) + VertexBuffer::VertexBuffer(std::shared_ptr vertexDeclaration, std::shared_ptr buffer, std::size_t offset, std::size_t size) { - ErrorFlags(ErrorFlag_ThrowException, true); + ErrorFlags(ErrorMode::ThrowException, true); Reset(std::move(vertexDeclaration), std::move(buffer), offset, size); } - VertexBuffer::VertexBuffer(VertexDeclarationConstRef vertexDeclaration, std::size_t length, DataStorage storage, BufferUsageFlags usage) + VertexBuffer::VertexBuffer(std::shared_ptr vertexDeclaration, std::size_t length, DataStorage storage, BufferUsageFlags usage) { - ErrorFlags(ErrorFlag_ThrowException, true); + ErrorFlags(ErrorMode::ThrowException, true); Reset(std::move(vertexDeclaration), length, storage, usage); } - VertexBuffer::VertexBuffer(const VertexBuffer& vertexBuffer) : - RefCounted(), - m_buffer(vertexBuffer.m_buffer), - m_endOffset(vertexBuffer.m_endOffset), - m_startOffset(vertexBuffer.m_startOffset), - m_vertexCount(vertexBuffer.m_vertexCount), - m_vertexDeclaration(vertexBuffer.m_vertexDeclaration) - { - } - - VertexBuffer::~VertexBuffer() - { - OnVertexBufferRelease(this); - } - bool VertexBuffer::Fill(const void* data, std::size_t startVertex, std::size_t length) { std::size_t stride = static_cast(m_vertexDeclaration->GetStride()); @@ -91,20 +76,20 @@ namespace Nz void VertexBuffer::Reset() { - m_buffer.Reset(); - m_vertexDeclaration.Reset(); + m_buffer.reset(); + m_vertexDeclaration.reset(); } - void VertexBuffer::Reset(VertexDeclarationConstRef vertexDeclaration, BufferRef buffer) + void VertexBuffer::Reset(std::shared_ptr vertexDeclaration, std::shared_ptr buffer) { NazaraAssert(buffer && buffer->IsValid(), "Invalid buffer"); - NazaraAssert(buffer->GetType() == BufferType_Vertex, "Buffer must be a vertex buffer"); + NazaraAssert(buffer->GetType() == BufferType::Vertex, "Buffer must be a vertex buffer"); std::size_t size = buffer->GetSize(); Reset(std::move(vertexDeclaration), std::move(buffer), 0, size); } - void VertexBuffer::Reset(VertexDeclarationConstRef vertexDeclaration, BufferRef buffer, std::size_t offset, std::size_t size) + void VertexBuffer::Reset(std::shared_ptr vertexDeclaration, std::shared_ptr buffer, std::size_t offset, std::size_t size) { NazaraAssert(buffer && buffer->IsValid(), "Invalid buffer"); NazaraAssert(size > 0, "Invalid size"); @@ -117,14 +102,14 @@ namespace Nz m_vertexDeclaration = vertexDeclaration; } - void VertexBuffer::Reset(VertexDeclarationConstRef vertexDeclaration, std::size_t length, DataStorage storage, BufferUsageFlags usage) + void VertexBuffer::Reset(std::shared_ptr vertexDeclaration, std::size_t length, DataStorage storage, BufferUsageFlags usage) { m_endOffset = length * ((vertexDeclaration) ? static_cast(vertexDeclaration->GetStride()) : 1); m_startOffset = 0; m_vertexCount = length; m_vertexDeclaration = std::move(vertexDeclaration); - m_buffer = Buffer::New(BufferType_Vertex, m_endOffset, storage, usage); + m_buffer = std::make_shared(BufferType::Vertex, m_endOffset, storage, usage); } void VertexBuffer::Reset(const VertexBuffer& vertexBuffer) @@ -136,7 +121,7 @@ namespace Nz m_vertexDeclaration = vertexBuffer.m_vertexDeclaration; } - void VertexBuffer::SetVertexDeclaration(VertexDeclarationConstRef vertexDeclaration) + void VertexBuffer::SetVertexDeclaration(std::shared_ptr vertexDeclaration) { NazaraAssert(vertexDeclaration, "Invalid vertex declaration"); @@ -148,11 +133,4 @@ namespace Nz { m_buffer->Unmap(); } - - VertexBuffer& VertexBuffer::operator=(const VertexBuffer& vertexBuffer) - { - Reset(vertexBuffer); - - return *this; - } } diff --git a/src/Nazara/Utility/VertexDeclaration.cpp b/src/Nazara/Utility/VertexDeclaration.cpp index 8fc49661b..9a2a3e837 100644 --- a/src/Nazara/Utility/VertexDeclaration.cpp +++ b/src/Nazara/Utility/VertexDeclaration.cpp @@ -16,37 +16,37 @@ namespace Nz { namespace { - std::size_t s_componentStride[ComponentType_Max + 1] = + std::size_t s_componentStride[ComponentTypeCount] = { - 4 * sizeof(UInt8), // ComponentType_Color - 1 * sizeof(double), // ComponentType_Double1 - 2 * sizeof(double), // ComponentType_Double2 - 3 * sizeof(double), // ComponentType_Double3 - 4 * sizeof(double), // ComponentType_Double4 - 1 * sizeof(float), // ComponentType_Float1 - 2 * sizeof(float), // ComponentType_Float2 - 3 * sizeof(float), // ComponentType_Float3 - 4 * sizeof(float), // ComponentType_Float4 - 1 * sizeof(UInt32), // ComponentType_Int1 - 2 * sizeof(UInt32), // ComponentType_Int2 - 3 * sizeof(UInt32), // ComponentType_Int3 - 4 * sizeof(UInt32), // ComponentType_Int4 - 4 * sizeof(float) // ComponentType_Quaternion + 4 * sizeof(UInt8), // ComponentType::Color + 1 * sizeof(double), // ComponentType::Double1 + 2 * sizeof(double), // ComponentType::Double2 + 3 * sizeof(double), // ComponentType::Double3 + 4 * sizeof(double), // ComponentType::Double4 + 1 * sizeof(float), // ComponentType::Float1 + 2 * sizeof(float), // ComponentType::Float2 + 3 * sizeof(float), // ComponentType::Float3 + 4 * sizeof(float), // ComponentType::Float4 + 1 * sizeof(UInt32), // ComponentType::Int1 + 2 * sizeof(UInt32), // ComponentType::Int2 + 3 * sizeof(UInt32), // ComponentType::Int3 + 4 * sizeof(UInt32), // ComponentType::Int4 + 4 * sizeof(float) // ComponentType::Quaternion }; } VertexDeclaration::VertexDeclaration(VertexInputRate inputRate, std::initializer_list components) : m_inputRate(inputRate) { - ErrorFlags errFlags(ErrorFlag_ThrowException); + ErrorFlags errFlags(ErrorMode::ThrowException); std::size_t offset = 0; m_components.reserve(components.size()); for (const ComponentEntry& entry : components) { - NazaraAssert(IsTypeSupported(entry.type), "Component type 0x" + NumberToString(entry.type, 16) + " is not supported by vertex declarations"); - NazaraAssert(entry.componentIndex == 0 || entry.component == VertexComponent_Userdata, "Only userdata components can have non-zero component indexes"); + NazaraAssert(IsTypeSupported(entry.type), "Component type 0x" + NumberToString(UnderlyingCast(entry.type), 16) + " is not supported by vertex declarations"); + NazaraAssert(entry.componentIndex == 0 || entry.component == VertexComponent::Userdata, "Only userdata components can have non-zero component indexes"); - if (entry.component != VertexComponent_Unused) + if (entry.component != VertexComponent::Unused) { // Check for duplicates for (const Component& component : m_components) @@ -62,7 +62,7 @@ namespace Nz component.offset = offset; component.type = entry.type; - offset += s_componentStride[component.type]; + offset += s_componentStride[UnderlyingCast(component.type)]; } m_stride = offset; @@ -72,281 +72,275 @@ namespace Nz { switch (type) { - case ComponentType_Color: - case ComponentType_Double1: - case ComponentType_Double2: - case ComponentType_Double3: - case ComponentType_Double4: - case ComponentType_Float1: - case ComponentType_Float2: - case ComponentType_Float3: - case ComponentType_Float4: - case ComponentType_Int1: - case ComponentType_Int2: - case ComponentType_Int3: - case ComponentType_Int4: + case ComponentType::Color: + case ComponentType::Double1: + case ComponentType::Double2: + case ComponentType::Double3: + case ComponentType::Double4: + case ComponentType::Float1: + case ComponentType::Float2: + case ComponentType::Float3: + case ComponentType::Float4: + case ComponentType::Int1: + case ComponentType::Int2: + case ComponentType::Int3: + case ComponentType::Int4: return true; - case ComponentType_Quaternion: + case ComponentType::Quaternion: return false; } - NazaraError("Component type not handled (0x" + NumberToString(type, 16) + ')'); + NazaraError("Component type not handled (0x" + NumberToString(UnderlyingCast(type), 16) + ')'); return false; } bool VertexDeclaration::Initialize() { - if (!VertexDeclarationLibrary::Initialize()) - { - NazaraError("Failed to initialise library"); - return false; - } - try { - ErrorFlags flags(ErrorFlag_Silent | ErrorFlag_ThrowException); + ErrorFlags flags(ErrorMode::Silent | ErrorMode::ThrowException); auto NewDeclaration = [](VertexInputRate inputRate, std::initializer_list components) { - return New(inputRate, std::move(components)); + return std::make_shared(inputRate, std::move(components)); }; - // VertexLayout_XY : VertexStruct_XY - s_declarations[VertexLayout_XY] = NewDeclaration(VertexInputRate::Vertex, { + // VertexLayout::XY : VertexStruct_XY + s_declarations[UnderlyingCast(VertexLayout::XY)] = NewDeclaration(VertexInputRate::Vertex, { { - VertexComponent_Position, - ComponentType_Float2, + VertexComponent::Position, + ComponentType::Float2, 0 } }); - NazaraAssert(s_declarations[VertexLayout_XY]->GetStride() == sizeof(VertexStruct_XY), "Invalid stride for declaration VertexLayout_XY"); + NazaraAssert(s_declarations[UnderlyingCast(VertexLayout::XY)]->GetStride() == sizeof(VertexStruct_XY), "Invalid stride for declaration VertexLayout::XY"); - s_declarations[VertexLayout_XY_Color] = NewDeclaration(VertexInputRate::Vertex, { + s_declarations[UnderlyingCast(VertexLayout::XY_Color)] = NewDeclaration(VertexInputRate::Vertex, { { - VertexComponent_Position, - ComponentType_Float2, + VertexComponent::Position, + ComponentType::Float2, 0 }, { - VertexComponent_Color, - ComponentType_Color, + VertexComponent::Color, + ComponentType::Color, 0 }, }); - NazaraAssert(s_declarations[VertexLayout_XY_Color]->GetStride() == sizeof(VertexStruct_XY_Color), "Invalid stride for declaration VertexLayout_XY_Color"); + NazaraAssert(s_declarations[UnderlyingCast(VertexLayout::XY_Color)]->GetStride() == sizeof(VertexStruct_XY_Color), "Invalid stride for declaration VertexLayout::XY_Color"); - // VertexLayout_XY_UV : VertexStruct_XY_UV - s_declarations[VertexLayout_XY_UV] = NewDeclaration(VertexInputRate::Vertex, { + // VertexLayout::XY_UV : VertexStruct_XY_UV + s_declarations[UnderlyingCast(VertexLayout::XY_UV)] = NewDeclaration(VertexInputRate::Vertex, { { - VertexComponent_Position, - ComponentType_Float2, + VertexComponent::Position, + ComponentType::Float2, 0 }, { - VertexComponent_TexCoord, - ComponentType_Float2, + VertexComponent::TexCoord, + ComponentType::Float2, 0 }, }); - NazaraAssert(s_declarations[VertexLayout_XY_UV]->GetStride() == sizeof(VertexStruct_XY_UV), "Invalid stride for declaration VertexLayout_XY_UV"); + NazaraAssert(s_declarations[UnderlyingCast(VertexLayout::XY_UV)]->GetStride() == sizeof(VertexStruct_XY_UV), "Invalid stride for declaration VertexLayout::XY_UV"); - // VertexLayout_XYZ : VertexStruct_XYZ - s_declarations[VertexLayout_XYZ] = NewDeclaration(VertexInputRate::Vertex, { + // VertexLayout::XYZ : VertexStruct_XYZ + s_declarations[UnderlyingCast(VertexLayout::XYZ)] = NewDeclaration(VertexInputRate::Vertex, { { - VertexComponent_Position, - ComponentType_Float3, + VertexComponent::Position, + ComponentType::Float3, 0 }, }); - NazaraAssert(s_declarations[VertexLayout_XYZ]->GetStride() == sizeof(VertexStruct_XYZ), "Invalid stride for declaration VertexLayout_XYZ"); + NazaraAssert(s_declarations[UnderlyingCast(VertexLayout::XYZ)]->GetStride() == sizeof(VertexStruct_XYZ), "Invalid stride for declaration VertexLayout::XYZ"); - // VertexLayout_XYZ_Color : VertexStruct_XYZ_Color - s_declarations[VertexLayout_XYZ_Color] = NewDeclaration(VertexInputRate::Vertex, { + // VertexLayout::XYZ_Color : VertexStruct_XYZ_Color + s_declarations[UnderlyingCast(VertexLayout::XYZ_Color)] = NewDeclaration(VertexInputRate::Vertex, { { - VertexComponent_Position, - ComponentType_Float3, + VertexComponent::Position, + ComponentType::Float3, 0 }, { - VertexComponent_Color, - ComponentType_Color, + VertexComponent::Color, + ComponentType::Color, 0 } }); - NazaraAssert(s_declarations[VertexLayout_XYZ_Color]->GetStride() == sizeof(VertexStruct_XYZ_Color), "Invalid stride for declaration VertexLayout_XYZ_Color"); + NazaraAssert(s_declarations[UnderlyingCast(VertexLayout::XYZ_Color)]->GetStride() == sizeof(VertexStruct_XYZ_Color), "Invalid stride for declaration VertexLayout::XYZ_Color"); - // VertexLayout_XYZ_Color_UV : VertexStruct_XYZ_Color_UV - s_declarations[VertexLayout_XYZ_Color_UV] = NewDeclaration(VertexInputRate::Vertex, { + // VertexLayout::XYZ_Color_UV : VertexStruct_XYZ_Color_UV + s_declarations[UnderlyingCast(VertexLayout::XYZ_Color_UV)] = NewDeclaration(VertexInputRate::Vertex, { { - VertexComponent_Position, - ComponentType_Float3, + VertexComponent::Position, + ComponentType::Float3, 0 }, { - VertexComponent_Color, - ComponentType_Color, + VertexComponent::Color, + ComponentType::Color, 0 }, { - VertexComponent_TexCoord, - ComponentType_Float2, + VertexComponent::TexCoord, + ComponentType::Float2, 0 }, }); - NazaraAssert(s_declarations[VertexLayout_XYZ_Color_UV]->GetStride() == sizeof(VertexStruct_XYZ_Color_UV), "Invalid stride for declaration VertexLayout_XYZ_Color_UV"); + NazaraAssert(s_declarations[UnderlyingCast(VertexLayout::XYZ_Color_UV)]->GetStride() == sizeof(VertexStruct_XYZ_Color_UV), "Invalid stride for declaration VertexLayout::XYZ_Color_UV"); - // VertexLayout_XYZ_Normal : VertexStruct_XYZ_Normal - s_declarations[VertexLayout_XYZ_Normal] = NewDeclaration(VertexInputRate::Vertex, { + // VertexLayout::XYZ_Normal : VertexStruct_XYZ_Normal + s_declarations[UnderlyingCast(VertexLayout::XYZ_Normal)] = NewDeclaration(VertexInputRate::Vertex, { { - VertexComponent_Position, - ComponentType_Float3, + VertexComponent::Position, + ComponentType::Float3, 0 }, { - VertexComponent_Normal, - ComponentType_Float3, + VertexComponent::Normal, + ComponentType::Float3, 0 } }); - NazaraAssert(s_declarations[VertexLayout_XYZ_Normal]->GetStride() == sizeof(VertexStruct_XYZ_Normal), "Invalid stride for declaration VertexLayout_XYZ_Normal"); + NazaraAssert(s_declarations[UnderlyingCast(VertexLayout::XYZ_Normal)]->GetStride() == sizeof(VertexStruct_XYZ_Normal), "Invalid stride for declaration VertexLayout::XYZ_Normal"); - // VertexLayout_XYZ_Normal_UV : VertexStruct_XYZ_Normal_UV - s_declarations[VertexLayout_XYZ_Normal_UV] = NewDeclaration(VertexInputRate::Vertex, { + // VertexLayout::XYZ_Normal_UV : VertexStruct_XYZ_Normal_UV + s_declarations[UnderlyingCast(VertexLayout::XYZ_Normal_UV)] = NewDeclaration(VertexInputRate::Vertex, { { - VertexComponent_Position, - ComponentType_Float3, + VertexComponent::Position, + ComponentType::Float3, 0 }, { - VertexComponent_Normal, - ComponentType_Float3, + VertexComponent::Normal, + ComponentType::Float3, 0 }, { - VertexComponent_TexCoord, - ComponentType_Float2, + VertexComponent::TexCoord, + ComponentType::Float2, 0 } }); - NazaraAssert(s_declarations[VertexLayout_XYZ_Normal_UV]->GetStride() == sizeof(VertexStruct_XYZ_Normal_UV), "Invalid stride for declaration VertexLayout_XYZ_Normal_UV"); + NazaraAssert(s_declarations[UnderlyingCast(VertexLayout::XYZ_Normal_UV)]->GetStride() == sizeof(VertexStruct_XYZ_Normal_UV), "Invalid stride for declaration VertexLayout::XYZ_Normal_UV"); - // VertexLayout_XYZ_Normal_UV_Tangent : VertexStruct_XYZ_Normal_UV_Tangent - s_declarations[VertexLayout_XYZ_Normal_UV_Tangent] = NewDeclaration(VertexInputRate::Vertex, { + // VertexLayout::XYZ_Normal_UV_Tangent : VertexStruct_XYZ_Normal_UV_Tangent + s_declarations[UnderlyingCast(VertexLayout::XYZ_Normal_UV_Tangent)] = NewDeclaration(VertexInputRate::Vertex, { { - VertexComponent_Position, - ComponentType_Float3, + VertexComponent::Position, + ComponentType::Float3, 0 }, { - VertexComponent_Normal, - ComponentType_Float3, + VertexComponent::Normal, + ComponentType::Float3, 0 }, { - VertexComponent_TexCoord, - ComponentType_Float2, + VertexComponent::TexCoord, + ComponentType::Float2, 0 }, { - VertexComponent_Tangent, - ComponentType_Float3, + VertexComponent::Tangent, + ComponentType::Float3, 0 } }); - NazaraAssert(s_declarations[VertexLayout_XYZ_Normal_UV_Tangent]->GetStride() == sizeof(VertexStruct_XYZ_Normal_UV_Tangent), "Invalid stride for declaration VertexLayout_XYZ_Normal_UV_Tangent"); + NazaraAssert(s_declarations[UnderlyingCast(VertexLayout::XYZ_Normal_UV_Tangent)]->GetStride() == sizeof(VertexStruct_XYZ_Normal_UV_Tangent), "Invalid stride for declaration VertexLayout::XYZ_Normal_UV_Tangent"); - // VertexLayout_XYZ_Normal_UV_Tangent_Skinning : VertexStruct_XYZ_Normal_UV_Tangent_Skinning - s_declarations[VertexLayout_XYZ_Normal_UV_Tangent_Skinning] = NewDeclaration(VertexInputRate::Vertex, { + // VertexLayout::XYZ_Normal_UV_Tangent_Skinning : VertexStruct_XYZ_Normal_UV_Tangent_Skinning + s_declarations[UnderlyingCast(VertexLayout::XYZ_Normal_UV_Tangent_Skinning)] = NewDeclaration(VertexInputRate::Vertex, { { - VertexComponent_Position, - ComponentType_Float3, + VertexComponent::Position, + ComponentType::Float3, 0 }, { - VertexComponent_Normal, - ComponentType_Float3, + VertexComponent::Normal, + ComponentType::Float3, 0 }, { - VertexComponent_TexCoord, - ComponentType_Float2, + VertexComponent::TexCoord, + ComponentType::Float2, 0 }, { - VertexComponent_Tangent, - ComponentType_Float3, + VertexComponent::Tangent, + ComponentType::Float3, 0 }, { - VertexComponent_Userdata, - ComponentType_Int1, + VertexComponent::Userdata, + ComponentType::Int1, 0 // Weight count }, { - VertexComponent_Userdata, - ComponentType_Float4, + VertexComponent::Userdata, + ComponentType::Float4, 1 // Weights }, { - VertexComponent_Userdata, - ComponentType_Int4, + VertexComponent::Userdata, + ComponentType::Int4, 2 // Joint indexes }, }); - NazaraAssert(s_declarations[VertexLayout_XYZ_Normal_UV_Tangent_Skinning]->GetStride() == sizeof(VertexStruct_XYZ_Normal_UV_Tangent_Skinning), "Invalid stride for declaration VertexLayout_XYZ_Normal_UV_Tangent_Skinning"); + NazaraAssert(s_declarations[UnderlyingCast(VertexLayout::XYZ_Normal_UV_Tangent_Skinning)]->GetStride() == sizeof(VertexStruct_XYZ_Normal_UV_Tangent_Skinning), "Invalid stride for declaration VertexLayout::XYZ_Normal_UV_Tangent_Skinning"); - // VertexLayout_XYZ_UV : VertexStruct_XYZ_UV - s_declarations[VertexLayout_XYZ_UV] = NewDeclaration(VertexInputRate::Vertex, { + // VertexLayout::XYZ_UV : VertexStruct_XYZ_UV + s_declarations[UnderlyingCast(VertexLayout::XYZ_UV)] = NewDeclaration(VertexInputRate::Vertex, { { - VertexComponent_Position, - ComponentType_Float3, + VertexComponent::Position, + ComponentType::Float3, 0 }, { - VertexComponent_TexCoord, - ComponentType_Float2, + VertexComponent::TexCoord, + ComponentType::Float2, 0 } }); - NazaraAssert(s_declarations[VertexLayout_XYZ_UV]->GetStride() == sizeof(VertexStruct_XYZ_UV), "Invalid stride for declaration VertexLayout_XYZ_UV"); + NazaraAssert(s_declarations[UnderlyingCast(VertexLayout::XYZ_UV)]->GetStride() == sizeof(VertexStruct_XYZ_UV), "Invalid stride for declaration VertexLayout::XYZ_UV"); - // VertexLayout_Matrix4 : Matrix4f - s_declarations[VertexLayout_Matrix4] = NewDeclaration(VertexInputRate::Vertex, { + // VertexLayout::Matrix4 : Matrix4f + s_declarations[UnderlyingCast(VertexLayout::Matrix4)] = NewDeclaration(VertexInputRate::Vertex, { { - VertexComponent_Userdata, - ComponentType_Float4, + VertexComponent::Userdata, + ComponentType::Float4, 0 }, { - VertexComponent_Userdata, - ComponentType_Float4, + VertexComponent::Userdata, + ComponentType::Float4, 1 }, { - VertexComponent_Userdata, - ComponentType_Float4, + VertexComponent::Userdata, + ComponentType::Float4, 2 }, { - VertexComponent_Userdata, - ComponentType_Float4, + VertexComponent::Userdata, + ComponentType::Float4, 3 } }); - NazaraAssert(s_declarations[VertexLayout_Matrix4]->GetStride() == sizeof(Matrix4f), "Invalid stride for declaration VertexLayout_Matrix4"); + NazaraAssert(s_declarations[UnderlyingCast(VertexLayout::Matrix4)]->GetStride() == sizeof(Matrix4f), "Invalid stride for declaration VertexLayout::Matrix4"); } catch (const std::exception& e) { @@ -359,11 +353,8 @@ namespace Nz void VertexDeclaration::Uninitialize() { - VertexDeclarationLibrary::Uninitialize(); - s_declarations.fill(nullptr); } - std::array VertexDeclaration::s_declarations; - VertexDeclarationLibrary::LibraryMap VertexDeclaration::s_library; + std::array, VertexLayoutCount> VertexDeclaration::s_declarations; } diff --git a/src/Nazara/Utility/VertexMapper.cpp b/src/Nazara/Utility/VertexMapper.cpp index 97bf6cbda..a863ae8fa 100644 --- a/src/Nazara/Utility/VertexMapper.cpp +++ b/src/Nazara/Utility/VertexMapper.cpp @@ -12,75 +12,75 @@ namespace Nz { - VertexMapper::VertexMapper(SubMesh* subMesh, BufferAccess access) + VertexMapper::VertexMapper(SubMesh& subMesh, BufferAccess access) { - ErrorFlags flags(ErrorFlag_ThrowException, true); + ErrorFlags flags(ErrorMode::ThrowException, true); - VertexBuffer* buffer = nullptr; - switch (subMesh->GetAnimationType()) + std::shared_ptr buffer = nullptr; + switch (subMesh.GetAnimationType()) { - case AnimationType_Skeletal: + case AnimationType::Skeletal: { - SkeletalMesh* skeletalMesh = static_cast(subMesh); - buffer = skeletalMesh->GetVertexBuffer(); + SkeletalMesh& skeletalMesh = static_cast(subMesh); + buffer = skeletalMesh.GetVertexBuffer(); break; } - case AnimationType_Static: + case AnimationType::Static: { - StaticMesh* staticMesh = static_cast(subMesh); - buffer = staticMesh->GetVertexBuffer(); + StaticMesh& staticMesh = static_cast(subMesh); + buffer = staticMesh.GetVertexBuffer(); break; } } if (!buffer) { - NazaraInternalError("Animation type not handled (0x" + NumberToString(subMesh->GetAnimationType(), 16) + ')'); + NazaraInternalError("Animation type not handled (0x" + NumberToString(UnderlyingCast(subMesh.GetAnimationType()), 16) + ')'); } - m_mapper.Map(buffer, access); + m_mapper.Map(*buffer, access); } - VertexMapper::VertexMapper(VertexBuffer* vertexBuffer, BufferAccess access) + VertexMapper::VertexMapper(VertexBuffer& vertexBuffer, BufferAccess access) { - ErrorFlags flags(ErrorFlag_ThrowException, true); + ErrorFlags flags(ErrorMode::ThrowException, true); m_mapper.Map(vertexBuffer, access); } - VertexMapper::VertexMapper(const SubMesh* subMesh, BufferAccess access) + VertexMapper::VertexMapper(const SubMesh& subMesh, BufferAccess access) { - ErrorFlags flags(ErrorFlag_ThrowException, true); + ErrorFlags flags(ErrorMode::ThrowException, true); - const VertexBuffer* buffer = nullptr; - switch (subMesh->GetAnimationType()) + std::shared_ptr buffer = nullptr; + switch (subMesh.GetAnimationType()) { - case AnimationType_Skeletal: + case AnimationType::Skeletal: { - const SkeletalMesh* skeletalMesh = static_cast(subMesh); - buffer = skeletalMesh->GetVertexBuffer(); + const SkeletalMesh& skeletalMesh = static_cast(subMesh); + buffer = skeletalMesh.GetVertexBuffer(); break; } - case AnimationType_Static: + case AnimationType::Static: { - const StaticMesh* staticMesh = static_cast(subMesh); - buffer = staticMesh->GetVertexBuffer(); + const StaticMesh& staticMesh = static_cast(subMesh); + buffer = staticMesh.GetVertexBuffer(); break; } } if (!buffer) { - NazaraInternalError("Animation type not handled (0x" + NumberToString(subMesh->GetAnimationType(), 16) + ')'); + NazaraInternalError("Animation type not handled (0x" + NumberToString(UnderlyingCast(subMesh.GetAnimationType()), 16) + ')'); } - m_mapper.Map(buffer, access); + m_mapper.Map(*buffer, access); } - VertexMapper::VertexMapper(const VertexBuffer* vertexBuffer, BufferAccess access) + VertexMapper::VertexMapper(const VertexBuffer& vertexBuffer, BufferAccess access) { - ErrorFlags flags(ErrorFlag_ThrowException, true); + ErrorFlags flags(ErrorMode::ThrowException, true); m_mapper.Map(vertexBuffer, access); } diff --git a/src/Nazara/VulkanRenderer/VkRenderWindow.cpp b/src/Nazara/VulkanRenderer/VkRenderWindow.cpp index 111ed0840..b4b609958 100644 --- a/src/Nazara/VulkanRenderer/VkRenderWindow.cpp +++ b/src/Nazara/VulkanRenderer/VkRenderWindow.cpp @@ -22,7 +22,6 @@ namespace Nz VkRenderWindow::VkRenderWindow(RenderWindow& owner) : m_currentFrame(0), m_owner(owner), - m_depthStencilFormat(VK_FORMAT_MAX_ENUM), m_shouldRecreateSwapchain(false) { } @@ -58,7 +57,7 @@ namespace Nz invalidateFramebuffer = true; } - VulkanRenderImage& currentFrame = m_concurrentImageData[m_currentFrame]; + VulkanRenderImage& currentFrame = *m_concurrentImageData[m_currentFrame]; Vk::Fence& inFlightFence = currentFrame.GetInFlightFence(); // Wait until previous rendering to this image has been done @@ -90,7 +89,7 @@ namespace Nz case VK_ERROR_SURFACE_LOST_KHR: //< TODO: Handle it by recreating the surface? case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT: default: - throw std::runtime_error("Failed to acquire next image: " + TranslateVulkanError(m_swapchain.GetLastErrorCode())); + throw std::runtime_error("failed to acquire next image: " + TranslateVulkanError(m_swapchain.GetLastErrorCode())); } if (m_inflightFences[imageIndex]) @@ -106,14 +105,16 @@ namespace Nz bool VkRenderWindow::Create(RendererImpl* /*renderer*/, RenderSurface* surface, const RenderWindowParameters& parameters) { - const auto& deviceInfo = Vulkan::GetPhysicalDevices()[0]; + VulkanDevice& referenceDevice = static_cast(*m_owner.GetRenderDevice()); + + const auto& physDeviceInfo = referenceDevice.GetPhysicalDeviceInfo(); Vk::Surface& vulkanSurface = static_cast(surface)->GetSurface(); UInt32 graphicsFamilyQueueIndex; UInt32 presentableFamilyQueueIndex; UInt32 transferFamilyQueueIndex; - m_device = Vulkan::SelectDevice(deviceInfo, vulkanSurface, &graphicsFamilyQueueIndex, &presentableFamilyQueueIndex, &transferFamilyQueueIndex); + m_device = Vulkan::SelectDevice(physDeviceInfo, vulkanSurface, &graphicsFamilyQueueIndex, &presentableFamilyQueueIndex, &transferFamilyQueueIndex); if (!m_device) { NazaraError("Failed to get compatible Vulkan device"); @@ -125,7 +126,7 @@ namespace Nz m_transferQueue = m_device->GetQueue(transferFamilyQueueIndex, 0); std::vector surfaceFormats; - if (!vulkanSurface.GetFormats(deviceInfo.physDevice, &surfaceFormats)) + if (!vulkanSurface.GetFormats(physDeviceInfo.physDevice, &surfaceFormats)) { NazaraError("Failed to query supported surface formats"); return false; @@ -151,39 +152,47 @@ namespace Nz } }(); + m_depthStencilFormat = VK_FORMAT_MAX_ENUM; if (!parameters.depthFormats.empty()) { for (PixelFormat format : parameters.depthFormats) { switch (format) { - case PixelFormat_Depth16: + case PixelFormat::Depth16: m_depthStencilFormat = VK_FORMAT_D16_UNORM; break; - case PixelFormat_Depth24: - case PixelFormat_Depth24Stencil8: + case PixelFormat::Depth16Stencil8: + m_depthStencilFormat = VK_FORMAT_D16_UNORM_S8_UINT; + break; + + case PixelFormat::Depth24: + case PixelFormat::Depth24Stencil8: m_depthStencilFormat = VK_FORMAT_D24_UNORM_S8_UINT; break; - case PixelFormat_Depth32: + case PixelFormat::Depth32F: m_depthStencilFormat = VK_FORMAT_D32_SFLOAT; break; - case PixelFormat_Stencil1: - case PixelFormat_Stencil4: - case PixelFormat_Stencil8: + case PixelFormat::Depth32FStencil8: + m_depthStencilFormat = VK_FORMAT_D32_SFLOAT_S8_UINT; + break; + + case PixelFormat::Stencil1: + case PixelFormat::Stencil4: + case PixelFormat::Stencil8: m_depthStencilFormat = VK_FORMAT_S8_UINT; break; - case PixelFormat_Stencil16: - m_depthStencilFormat = VK_FORMAT_MAX_ENUM; - break; + case PixelFormat::Stencil16: + continue; default: { PixelFormatContent formatContent = PixelFormatInfo::GetContent(format); - if (formatContent != PixelFormatContent_DepthStencil && formatContent != PixelFormatContent_Stencil) + if (formatContent != PixelFormatContent::DepthStencil && formatContent != PixelFormatContent::Stencil) NazaraWarning("Invalid format " + PixelFormatInfo::GetName(format) + " for depth-stencil attachment"); m_depthStencilFormat = VK_FORMAT_MAX_ENUM; @@ -193,7 +202,7 @@ namespace Nz if (m_depthStencilFormat != VK_FORMAT_MAX_ENUM) { - VkFormatProperties formatProperties = m_device->GetInstance().GetPhysicalDeviceFormatProperties(deviceInfo.physDevice, m_depthStencilFormat); + VkFormatProperties formatProperties = m_device->GetInstance().GetPhysicalDeviceFormatProperties(physDeviceInfo.physDevice, m_depthStencilFormat); if (formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) break; //< Found it @@ -335,6 +344,14 @@ namespace Nz return false; } + PixelFormat format = FromVulkan(m_depthStencilFormat).value(); + + VkImageAspectFlags aspectMask; + if (PixelFormatInfo::GetContent(format) == PixelFormatContent::DepthStencil) + aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + else + aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + VkImageViewCreateInfo imageViewCreateInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType; nullptr, // const void* pNext; @@ -349,7 +366,7 @@ namespace Nz VK_COMPONENT_SWIZZLE_A // VkComponentSwizzle .a; }, { // VkImageSubresourceRange subresourceRange; - VK_IMAGE_ASPECT_DEPTH_BIT, // VkImageAspectFlags .aspectMask; + aspectMask, // VkImageAspectFlags .aspectMask; 0, // uint32_t .baseMipLevel; 1, // uint32_t .levelCount; 0, // uint32_t .baseArrayLayer; @@ -400,98 +417,30 @@ namespace Nz bool VkRenderWindow::SetupRenderPass() { - std::array attachments = { - { - { - 0, // VkAttachmentDescriptionFlags flags; - m_surfaceFormat.format, // VkFormat format; - VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; - VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp; - VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp; - VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; - VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; - VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR // VkImageLayout finalLayout; - }, - { - 0, // VkAttachmentDescriptionFlags flags; - m_depthStencilFormat, // VkFormat format; - VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; - VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp; - VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp storeOp; - VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; - VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; - VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout; - }, - } - }; - - VkAttachmentReference colorReference = { - 0, // uint32_t attachment; - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout; - }; - - VkAttachmentReference depthReference = { - 1, // uint32_t attachment; - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL // VkImageLayout layout; - }; - - VkSubpassDescription subpass = { - 0, // VkSubpassDescriptionFlags flags; - VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint; - 0U, // uint32_t inputAttachmentCount; - nullptr, // const VkAttachmentReference* pInputAttachments; - 1U, // uint32_t colorAttachmentCount; - &colorReference, // const VkAttachmentReference* pColorAttachments; - nullptr, // const VkAttachmentReference* pResolveAttachments; - (m_depthStencilFormat != VK_FORMAT_MAX_ENUM) ? &depthReference : nullptr, // const VkAttachmentReference* pDepthStencilAttachment; - 0U, // uint32_t preserveAttachmentCount; - nullptr // const uint32_t* pPreserveAttachments; - }; - - std::array dependencies; - // First dependency at the start of the render pass - // Does the transition from final to initial layout - dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; // Producer of the dependency - dependencies[0].dstSubpass = 0; // Consumer is our single subpass that will wait for the execution dependency - dependencies[0].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependencies[0].srcAccessMask = 0; - dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; - - // Second dependency at the end the render pass - // Does the transition from the initial to the final layout - dependencies[1].srcSubpass = 0; // Producer of the dependency is our single subpass - dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL; // Consumer are all commands outside of the render pass - dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; - dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; - - VkRenderPassCreateInfo createInfo = { - VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType; - nullptr, // const void* pNext; - 0, // VkRenderPassCreateFlags flags; - (m_depthStencilFormat != VK_FORMAT_MAX_ENUM) ? 2U : 1U, // uint32_t attachmentCount; - attachments.data(), // const VkAttachmentDescription* pAttachments; - 1U, // uint32_t subpassCount; - &subpass, // const VkSubpassDescription* pSubpasses; - UInt32(dependencies.size()), // uint32_t dependencyCount; - dependencies.data() // const VkSubpassDependency* pDependencies; - }; - - Vk::RenderPass renderPass; - if (!renderPass.Create(*m_device, createInfo)) + std::optional colorFormat = FromVulkan(m_surfaceFormat.format); + if (!colorFormat) { - NazaraError("Failed to create render pass: " + TranslateVulkanError(renderPass.GetLastErrorCode())); + NazaraError("unhandled vulkan pixel format (0x" + NumberToString(m_surfaceFormat.format, 16) + ")"); return false; } - std::initializer_list fixmeplease = { PixelFormat::PixelFormat_RGB8, PixelFormat::PixelFormat_Depth24Stencil8 }; - m_renderPass.emplace(std::move(renderPass), fixmeplease); + std::optional depthStencilFormat; + if (m_depthStencilFormat != VK_FORMAT_MAX_ENUM) + { + depthStencilFormat = FromVulkan(m_depthStencilFormat); + if (!depthStencilFormat) + { + NazaraError("unhandled vulkan pixel format (0x" + NumberToString(m_depthStencilFormat, 16) + ")"); + return false; + } + } + + std::vector attachments; + std::vector subpassDescriptions; + std::vector subpassDependencies; + + BuildRenderPass(*colorFormat, depthStencilFormat.value_or(PixelFormat::Undefined), attachments, subpassDescriptions, subpassDependencies); + m_renderPass.emplace(*m_device, std::move(attachments), std::move(subpassDescriptions), std::move(subpassDependencies)); return true; } @@ -537,6 +486,9 @@ namespace Nz swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; } + // Ensure all operations on the device have been finished before recreating the swapchain (this can be avoided but is more complicated) + m_device->WaitForIdle(); + VkSwapchainCreateInfoKHR swapchainInfo = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, nullptr, @@ -578,7 +530,7 @@ namespace Nz m_concurrentImageData.reserve(imageCount); for (std::size_t i = 0; i < imageCount; ++i) - m_concurrentImageData.emplace_back(*this); + m_concurrentImageData.emplace_back(std::make_unique(*this)); } return true; diff --git a/src/Nazara/VulkanRenderer/Vulkan.cpp b/src/Nazara/VulkanRenderer/Vulkan.cpp index 4daa698f4..cc4150d0c 100644 --- a/src/Nazara/VulkanRenderer/Vulkan.cpp +++ b/src/Nazara/VulkanRenderer/Vulkan.cpp @@ -16,6 +16,74 @@ namespace Nz { + namespace + { + struct AvailableLayer + { + VkLayerProperties layerProperties; + std::unordered_map extensionByName; + std::vector extensionList; + }; + + void EnumerateLayers(std::vector& availableLayers, std::unordered_map& layerByName) + { + std::vector layerList; + if (Vk::Loader::EnumerateInstanceLayerProperties(&layerList)) + { + for (VkLayerProperties& layerProperties : layerList) + { + std::size_t layerIndex = availableLayers.size(); + auto& layerData = availableLayers.emplace_back(); + layerData.layerProperties = layerProperties; + + if (Vk::Loader::EnumerateInstanceExtensionProperties(&layerData.extensionList, layerProperties.layerName)) + { + for (VkExtensionProperties& extProperty : layerData.extensionList) + layerData.extensionByName.emplace(extProperty.extensionName, layerData.extensionByName.size()); + } + + layerByName.emplace(layerProperties.layerName, layerIndex); + } + } + } + } + + RenderDeviceInfo Vulkan::BuildRenderDeviceInfo(const Vk::PhysicalDevice& physDevice) + { + RenderDeviceInfo deviceInfo; + deviceInfo.name = physDevice.properties.deviceName; + + deviceInfo.limits.minUniformBufferOffsetAlignment = physDevice.properties.limits.minUniformBufferOffsetAlignment; + + switch (physDevice.properties.deviceType) + { + case VK_PHYSICAL_DEVICE_TYPE_CPU: + deviceInfo.type = RenderDeviceType::Software; + break; + + case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: + deviceInfo.type = RenderDeviceType::Dedicated; + break; + + case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: + deviceInfo.type = RenderDeviceType::Integrated; + break; + + case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: + deviceInfo.type = RenderDeviceType::Virtual; + break; + + default: + NazaraWarning("Device " + deviceInfo.name + " has handled device type (0x" + NumberToString(physDevice.properties.deviceType, 16) + ')'); + // fallthrough + case VK_PHYSICAL_DEVICE_TYPE_OTHER: + deviceInfo.type = RenderDeviceType::Unknown; + break; + } + + return deviceInfo; + } + Vk::Instance& Vulkan::GetInstance() { return s_instance; @@ -103,14 +171,9 @@ namespace Nz std::vector enabledLayers; - // Get supported layer list - std::unordered_set availableLayers; - std::vector layerList; - if (Vk::Loader::EnumerateInstanceLayerProperties(&layerList)) - { - for (VkLayerProperties& extProperty : layerList) - availableLayers.insert(extProperty.layerName); - } + std::vector availableLayers; + std::unordered_map availableLayerByName; + EnumerateLayers(availableLayers, availableLayerByName); if (!parameters.GetBooleanParameter("VkInstanceInfo_OverrideEnabledLayers", &bParam) || !bParam) { @@ -118,9 +181,9 @@ namespace Nz #ifdef NAZARA_DEBUG // Enable Vulkan validation if available in debug mode - if (availableLayers.count("VK_LAYER_KHRONOS_validation")) + if (availableLayerByName.count("VK_LAYER_KHRONOS_validation")) enabledLayers.push_back("VK_LAYER_KHRONOS_validation"); - else if (availableLayers.count("VK_LAYER_LUNARG_standard_validation")) + else if (availableLayerByName.count("VK_LAYER_LUNARG_standard_validation")) enabledLayers.push_back("VK_LAYER_LUNARG_standard_validation"); #endif } @@ -202,17 +265,51 @@ namespace Nz } } - VkInstanceCreateInfo instanceInfo = { - VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, - nullptr, - createFlags, - &appInfo, - UInt32(enabledLayers.size()), - enabledLayers.data(), - UInt32(enabledExtensions.size()), - enabledExtensions.data() + VkInstanceCreateInfo instanceInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO }; + +#ifdef NAZARA_DEBUG + // Handle VK_LAYER_KHRONOS_validation extended features + + VkValidationFeaturesEXT features = { VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT }; + + std::vector enabledFeatures = { + //VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT, + //VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT, + VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT }; + auto validationIt = std::find_if(enabledLayers.begin(), enabledLayers.end(), [&](const char* layerName) + { + return std::strcmp(layerName, "VK_LAYER_KHRONOS_validation") == 0; + }); + if (validationIt != enabledLayers.end()) + { + auto layerIt = availableLayerByName.find("VK_LAYER_KHRONOS_validation"); + assert(layerIt != availableLayerByName.end()); + + auto& validationLayer = availableLayers[layerIt->second]; + if (validationLayer.extensionByName.find(VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME) != validationLayer.extensionByName.end()) + { + enabledExtensions.push_back(VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME); + + features.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT; + features.enabledValidationFeatureCount = UInt32(enabledFeatures.size()); + features.pEnabledValidationFeatures = enabledFeatures.data(); + + instanceInfo.pNext = &features; + } + } +#endif + + instanceInfo.flags = createFlags; + instanceInfo.pApplicationInfo = &appInfo; + + instanceInfo.enabledExtensionCount = UInt32(enabledExtensions.size()); + instanceInfo.ppEnabledExtensionNames = enabledExtensions.data(); + + instanceInfo.enabledLayerCount = UInt32(enabledLayers.size()); + instanceInfo.ppEnabledLayerNames = enabledLayers.data(); + if (!s_instance.Create(instanceInfo)) { NazaraError("Failed to create instance: " + TranslateVulkanError(s_instance.GetLastErrorCode())); @@ -275,7 +372,7 @@ namespace Nz std::shared_ptr Vulkan::CreateDevice(const Vk::PhysicalDevice& deviceInfo) { - Nz::ErrorFlags errFlags(ErrorFlag_ThrowException, true); + Nz::ErrorFlags errFlags(ErrorMode::ThrowException, true); // Find a queue that supports graphics operations UInt32 graphicsQueueNodeIndex = UINT32_MAX; @@ -312,7 +409,7 @@ namespace Nz std::shared_ptr Vulkan::CreateDevice(const Vk::PhysicalDevice& deviceInfo, const Vk::Surface& surface, UInt32* graphicsFamilyIndex, UInt32* presentableFamilyIndex, UInt32* transferFamilyIndex) { - Nz::ErrorFlags errFlags(ErrorFlag_ThrowException, true); + Nz::ErrorFlags errFlags(ErrorMode::ThrowException, true); // Find a queue that supports graphics operations UInt32 graphicsQueueNodeIndex = UINT32_MAX; @@ -487,7 +584,7 @@ namespace Nz nullptr }; - std::shared_ptr device = std::make_shared(s_instance); + std::shared_ptr device = std::make_shared(s_instance, BuildRenderDeviceInfo(deviceInfo)); if (!device->Create(deviceInfo, createInfo)) { NazaraError("Failed to create Vulkan Device: " + TranslateVulkanError(device->GetLastErrorCode())); diff --git a/src/Nazara/VulkanRenderer/VulkanBuffer.cpp b/src/Nazara/VulkanRenderer/VulkanBuffer.cpp index e3c90c8ac..430c40812 100644 --- a/src/Nazara/VulkanRenderer/VulkanBuffer.cpp +++ b/src/Nazara/VulkanRenderer/VulkanBuffer.cpp @@ -18,7 +18,7 @@ namespace Nz bool VulkanBuffer::Fill(const void* data, UInt64 offset, UInt64 size) { - void* ptr = Map(BufferAccess_WriteOnly, offset, size); + void* ptr = Map(BufferAccess::WriteOnly, offset, size); if (!ptr) return false; @@ -36,7 +36,7 @@ namespace Nz VkBufferUsageFlags bufferUsage = ToVulkan(m_type); - if ((usage & BufferUsage_DirectMapping) == 0) + if ((usage & BufferUsage::DirectMapping) == 0) bufferUsage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; VkBufferCreateInfo createInfo = {}; @@ -45,9 +45,9 @@ namespace Nz createInfo.usage = bufferUsage; VmaAllocationCreateInfo allocInfo = {}; - if (usage & BufferUsage_DeviceLocal) + if (usage & BufferUsage::DeviceLocal) { - if (usage & BufferUsage_DirectMapping) + if (usage & BufferUsage::DirectMapping) allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU; else allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; @@ -55,7 +55,7 @@ namespace Nz else allocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY; - if (usage & BufferUsage_PersistentMapping) + if (usage & BufferUsage::PersistentMapping) allocInfo.flags |= VMA_ALLOCATION_CREATE_MAPPED_BIT; VkResult result = vmaCreateBuffer(m_device.GetMemoryAllocator(), &createInfo, &allocInfo, &m_buffer, &m_allocation, nullptr); @@ -75,12 +75,12 @@ namespace Nz DataStorage VulkanBuffer::GetStorage() const { - return DataStorage_Hardware; + return DataStorage::Hardware; } void* VulkanBuffer::Map(BufferAccess /*access*/, UInt64 offset, UInt64 size) { - if (m_usage & BufferUsage_DirectMapping) + if (m_usage & BufferUsage::DirectMapping) { void* mappedPtr; VkResult result = vmaMapMemory(m_device.GetMemoryAllocator(), m_allocation, &mappedPtr); @@ -118,7 +118,7 @@ namespace Nz bool VulkanBuffer::Unmap() { - if (m_usage & BufferUsage_DirectMapping) + if (m_usage & BufferUsage::DirectMapping) { vmaUnmapMemory(m_device.GetMemoryAllocator(), m_allocation); return true; diff --git a/src/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.cpp b/src/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.cpp index 8e027e923..96e1ca51a 100644 --- a/src/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.cpp +++ b/src/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -26,7 +27,7 @@ namespace Nz m_commandBuffer.BeginDebugRegion(regionNameEOS.data(), color); } - void VulkanCommandBufferBuilder::BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect, std::initializer_list clearValues) + void VulkanCommandBufferBuilder::BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect, const ClearValues* clearValues, std::size_t clearValueCount) { const VulkanRenderPass& vkRenderPass = static_cast(renderPass); @@ -49,14 +50,15 @@ namespace Nz throw std::runtime_error("Unhandled framebuffer type " + std::to_string(UnderlyingCast(vkFramebuffer.GetType()))); }(); - StackArray vkClearValues = NazaraStackArray(VkClearValue, clearValues.size()); + std::size_t attachmentCount = vkRenderPass.GetAttachmentCount(); - std::size_t index = 0; - for (const ClearValues& values : clearValues) + StackArray vkClearValues = NazaraStackArray(VkClearValue, attachmentCount); + for (std::size_t i = 0; i < attachmentCount; ++i) { - auto& vkValues = vkClearValues[index]; + const auto& values = (i < clearValueCount) ? clearValues[i] : CommandBufferBuilder::ClearValues{}; + auto& vkValues = vkClearValues[i]; - if (PixelFormatInfo::GetContent(vkRenderPass.GetAttachmentFormat(index)) == PixelFormatContent_ColorRGBA) + if (PixelFormatInfo::GetContent(vkRenderPass.GetAttachment(i).format) == PixelFormatContent::ColorRGBA) { vkValues.color.float32[0] = values.color.r / 255.f; vkValues.color.float32[1] = values.color.g / 255.f; @@ -68,8 +70,6 @@ namespace Nz vkValues.depthStencil.depth = values.depth; vkValues.depthStencil.stencil = values.stencil; } - - index++; } VkRenderPassBeginInfo beginInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO }; @@ -79,12 +79,13 @@ namespace Nz beginInfo.renderArea.offset.y = renderRect.y; beginInfo.renderArea.extent.width = renderRect.width; beginInfo.renderArea.extent.height = renderRect.height; - beginInfo.clearValueCount = vkClearValues.size(); + beginInfo.clearValueCount = UInt32(vkClearValues.size()); beginInfo.pClearValues = vkClearValues.data(); m_commandBuffer.BeginRenderPass(beginInfo); m_currentRenderPass = &vkRenderPass; + m_currentSubpassIndex = 0; } void VulkanCommandBufferBuilder::BindIndexBuffer(Nz::AbstractBuffer* indexBuffer, UInt64 offset) @@ -101,7 +102,7 @@ namespace Nz const VulkanRenderPipeline& vkBinding = static_cast(pipeline); - m_commandBuffer.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, vkBinding.Get(m_currentRenderPass->GetRenderPass())); + m_commandBuffer.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, vkBinding.Get(*m_currentRenderPass, m_currentSubpassIndex)); } void VulkanCommandBufferBuilder::BindShaderBinding(const ShaderBinding& binding) @@ -157,6 +158,12 @@ namespace Nz m_currentRenderPass = nullptr; } + void VulkanCommandBufferBuilder::NextSubpass() + { + m_commandBuffer.NextSubpass(); + m_currentSubpassIndex++; + } + void VulkanCommandBufferBuilder::PreTransferBarrier() { m_commandBuffer.MemoryBarrier(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0U, VK_ACCESS_TRANSFER_READ_BIT); @@ -176,4 +183,11 @@ namespace Nz { m_commandBuffer.SetViewport(Nz::Rectf(viewportRegion), 0.f, 1.f); } + + void VulkanCommandBufferBuilder::TextureBarrier(PipelineStageFlags srcStageMask, PipelineStageFlags dstStageMask, MemoryAccessFlags srcAccessMask, MemoryAccessFlags dstAccessMask, TextureLayout oldLayout, TextureLayout newLayout, const Texture& texture) + { + const VulkanTexture& vkTexture = static_cast(texture); + + m_commandBuffer.ImageBarrier(ToVulkan(srcStageMask), ToVulkan(dstStageMask), VkDependencyFlags(0), ToVulkan(srcAccessMask), ToVulkan(dstAccessMask), ToVulkan(oldLayout), ToVulkan(newLayout), vkTexture.GetImage(), VK_IMAGE_ASPECT_COLOR_BIT); + } } diff --git a/src/Nazara/VulkanRenderer/VulkanCommandPool.cpp b/src/Nazara/VulkanRenderer/VulkanCommandPool.cpp index a654c45b6..5076946b4 100644 --- a/src/Nazara/VulkanRenderer/VulkanCommandPool.cpp +++ b/src/Nazara/VulkanRenderer/VulkanCommandPool.cpp @@ -18,7 +18,7 @@ namespace Nz { Vk::AutoCommandBuffer& commandBuffer = commandBuffers.emplace_back(m_commandPool.AllocateCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY)); - if (!commandBuffer->Begin()) + if (!commandBuffer->Begin(VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) throw std::runtime_error("failed to begin command buffer: " + TranslateVulkanError(commandBuffer->GetLastErrorCode())); VulkanCommandBufferBuilder builder(commandBuffer.Get(), imageIndex); diff --git a/src/Nazara/VulkanRenderer/VulkanDevice.cpp b/src/Nazara/VulkanRenderer/VulkanDevice.cpp index adc23c0b8..8d8527e93 100644 --- a/src/Nazara/VulkanRenderer/VulkanDevice.cpp +++ b/src/Nazara/VulkanRenderer/VulkanDevice.cpp @@ -4,9 +4,11 @@ #include #include +#include #include #include -#include +#include +#include #include #include #include @@ -15,6 +17,11 @@ namespace Nz { VulkanDevice::~VulkanDevice() = default; + const RenderDeviceInfo& VulkanDevice::GetDeviceInfo() const + { + return m_renderDeviceInfo; + } + std::shared_ptr VulkanDevice::InstantiateBuffer(BufferType type) { return std::make_shared(*this, type); @@ -25,6 +32,16 @@ namespace Nz return std::make_shared(*this, queueType); } + std::shared_ptr VulkanDevice::InstantiateFramebuffer(unsigned int width, unsigned int height, const std::shared_ptr& renderPass, const std::vector>& attachments) + { + return std::make_shared(*this, width, height, renderPass, attachments); + } + + std::shared_ptr VulkanDevice::InstantiateRenderPass(std::vector attachments, std::vector subpassDescriptions, std::vector subpassDependencies) + { + return std::make_shared(*this, std::move(attachments), std::move(subpassDescriptions), std::move(subpassDependencies)); + } + std::shared_ptr VulkanDevice::InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) { return std::make_shared(*this, std::move(pipelineInfo)); @@ -34,16 +51,25 @@ namespace Nz { auto pipelineLayout = std::make_shared(); if (!pipelineLayout->Create(*this, std::move(pipelineLayoutInfo))) - return {}; + throw std::runtime_error("failed to instanciate vulkan render pipeline layout"); return pipelineLayout; } - std::shared_ptr VulkanDevice::InstantiateShaderStage(ShaderStageType type, ShaderLanguage lang, const void* source, std::size_t sourceSize) + std::shared_ptr VulkanDevice::InstantiateShaderModule(ShaderStageTypeFlags stages, ShaderAst::StatementPtr& shaderAst, const ShaderWriter::States& states) { - auto stage = std::make_shared(); - if (!stage->Create(*this, type, lang, source, sourceSize)) - return {}; + auto stage = std::make_shared(); + if (!stage->Create(*this, stages, shaderAst, states)) + throw std::runtime_error("failed to instanciate vulkan shader module"); + + return stage; + } + + std::shared_ptr VulkanDevice::InstantiateShaderModule(ShaderStageTypeFlags stages, ShaderLanguage lang, const void* source, std::size_t sourceSize, const ShaderWriter::States& states) + { + auto stage = std::make_shared(); + if (!stage->Create(*this, stages, lang, source, sourceSize, states)) + throw std::runtime_error("failed to instanciate vulkan shader module"); return stage; } @@ -57,4 +83,35 @@ namespace Nz { return std::make_shared(*this, params); } + + bool VulkanDevice::IsTextureFormatSupported(PixelFormat format, TextureUsage usage) const + { + VkFormatFeatureFlags flags = 0; + switch (usage) + { + case TextureUsage::ColorAttachment: + flags = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT; + break; + + case TextureUsage::DepthStencilAttachment: + flags = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT; + break; + + case TextureUsage::InputAttachment: + case TextureUsage::ShaderSampling: + flags = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT; + break; + + case TextureUsage::TransferSource: + flags = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT; + break; + + case TextureUsage::TransferDestination: + flags = VK_FORMAT_FEATURE_TRANSFER_DST_BIT; + break; + } + + VkFormatProperties formatProperties = GetInstance().GetPhysicalDeviceFormatProperties(GetPhysicalDevice(), ToVulkan(format)); + return formatProperties.optimalTilingFeatures & flags; //< Assume optimal tiling + } } diff --git a/src/Nazara/VulkanRenderer/VulkanRenderImage.cpp b/src/Nazara/VulkanRenderer/VulkanRenderImage.cpp index a1e8c2db3..2c01d4b1a 100644 --- a/src/Nazara/VulkanRenderer/VulkanRenderImage.cpp +++ b/src/Nazara/VulkanRenderer/VulkanRenderImage.cpp @@ -63,6 +63,15 @@ namespace Nz return m_uploadPool; } + void VulkanRenderImage::Present() + { + Vk::QueueHandle& graphicsQueue = m_owner.GetGraphicsQueue(); + if (!graphicsQueue.Submit(UInt32(m_graphicalCommandsBuffers.size()), m_graphicalCommandsBuffers.data(), m_imageAvailableSemaphore, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, m_renderFinishedSemaphore, m_inFlightFence)) + throw std::runtime_error("Failed to submit command buffers: " + TranslateVulkanError(graphicsQueue.GetLastErrorCode())); + + m_owner.Present(m_imageIndex, m_renderFinishedSemaphore); + } + void VulkanRenderImage::SubmitCommandBuffer(CommandBuffer* commandBuffer, QueueTypeFlags queueTypeFlags) { VulkanCommandBuffer& vkCommandBuffer = *static_cast(commandBuffer); @@ -81,13 +90,4 @@ namespace Nz throw std::runtime_error("Failed to submit command buffer: " + TranslateVulkanError(graphicsQueue.GetLastErrorCode())); } } - - void VulkanRenderImage::Present() - { - Vk::QueueHandle& graphicsQueue = m_owner.GetGraphicsQueue(); - if (!graphicsQueue.Submit(UInt32(m_graphicalCommandsBuffers.size()), m_graphicalCommandsBuffers.data(), m_imageAvailableSemaphore, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, m_renderFinishedSemaphore, m_inFlightFence)) - throw std::runtime_error("Failed to submit command buffers: " + TranslateVulkanError(graphicsQueue.GetLastErrorCode())); - - m_owner.Present(m_imageIndex, m_renderFinishedSemaphore); - } } diff --git a/src/Nazara/VulkanRenderer/VulkanRenderPass.cpp b/src/Nazara/VulkanRenderer/VulkanRenderPass.cpp index e9c406cfc..88da30cef 100644 --- a/src/Nazara/VulkanRenderer/VulkanRenderPass.cpp +++ b/src/Nazara/VulkanRenderer/VulkanRenderPass.cpp @@ -3,8 +3,129 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include +#include +#include #include namespace Nz { + inline VulkanRenderPass::VulkanRenderPass(Vk::Device& device, std::vector attachments, std::vector subpassDescriptions, std::vector subpassDependencies) : + RenderPass(std::move(attachments), std::move(subpassDescriptions), std::move(subpassDependencies)) + { + std::size_t totalAttachmentReference = 0; + for (const SubpassDescription& subpassInfo : m_subpassDescriptions) + { + totalAttachmentReference += subpassInfo.colorAttachment.size(); + totalAttachmentReference += subpassInfo.inputAttachments.size(); + + if (subpassInfo.depthStencilAttachment) + totalAttachmentReference++; + } + + StackVector vkAttachments = NazaraStackVector(VkAttachmentDescription, m_attachments.size()); + for (const Attachment& attachmentInfo : m_attachments) + { + vkAttachments.push_back({ + 0, + ToVulkan(attachmentInfo.format), + VK_SAMPLE_COUNT_1_BIT, + ToVulkan(attachmentInfo.loadOp), + ToVulkan(attachmentInfo.storeOp), + ToVulkan(attachmentInfo.stencilLoadOp), + ToVulkan(attachmentInfo.stencilStoreOp), + ToVulkan(attachmentInfo.initialLayout), + ToVulkan(attachmentInfo.finalLayout) + }); + } + + StackVector vkAttachmentReferences = NazaraStackVector(VkAttachmentReference, totalAttachmentReference); + StackVector vkPreserveAttachments = NazaraStackVector(UInt32, attachments.size()); + + StackVector vkSubpassDescs = NazaraStackVector(VkSubpassDescription, m_subpassDescriptions.size()); + for (const SubpassDescription& subpassInfo : m_subpassDescriptions) + { + std::size_t colorAttachmentIndex = vkAttachmentReferences.size(); + for (const AttachmentReference& attachmentRef : subpassInfo.colorAttachment) + { + vkAttachmentReferences.push_back({ + UInt32(attachmentRef.attachmentIndex), + ToVulkan(attachmentRef.attachmentLayout) + }); + } + + std::size_t inputAttachmentIndex = vkAttachmentReferences.size(); + for (const AttachmentReference& attachmentRef : subpassInfo.inputAttachments) + { + vkAttachmentReferences.push_back({ + UInt32(attachmentRef.attachmentIndex), + ToVulkan(attachmentRef.attachmentLayout) + }); + } + + std::size_t depthStencilAttachmentIndex = vkAttachmentReferences.size(); + if (subpassInfo.depthStencilAttachment) + { + auto& depthStencilRef = *subpassInfo.depthStencilAttachment; + vkAttachmentReferences.push_back({ + UInt32(depthStencilRef.attachmentIndex), + ToVulkan(depthStencilRef.attachmentLayout) + }); + } + + assert(subpassInfo.preserveAttachments.size() <= vkPreserveAttachments.size()); + for (std::size_t attachmentIndex : subpassInfo.preserveAttachments) + vkPreserveAttachments.push_back(UInt32(attachmentIndex)); + + vkSubpassDescs.push_back({ + VkSubpassDescriptionFlags(0), + VK_PIPELINE_BIND_POINT_GRAPHICS, + UInt32(subpassInfo.inputAttachments.size()), + (!subpassInfo.inputAttachments.empty()) ? &vkAttachmentReferences[inputAttachmentIndex] : nullptr, + UInt32(subpassInfo.colorAttachment.size()), + (!subpassInfo.colorAttachment.empty()) ? &vkAttachmentReferences[colorAttachmentIndex] : nullptr, + nullptr, + (subpassInfo.depthStencilAttachment) ? &vkAttachmentReferences[depthStencilAttachmentIndex] : nullptr, + UInt32(vkPreserveAttachments.size()), + (!vkPreserveAttachments.empty()) ? &vkPreserveAttachments[0] : nullptr + }); + } + + StackVector vkSubpassDeps = NazaraStackVector(VkSubpassDependency, m_subpassDependencies.size()); + for (const SubpassDependency& subpassDependency : m_subpassDependencies) + { + auto ToSubPassIndex = [](std::size_t subpassIndex) -> UInt32 + { + if (subpassIndex == ExternalSubpassIndex) + return VK_SUBPASS_EXTERNAL; + + return UInt32(subpassIndex); + }; + + vkSubpassDeps.push_back({ + ToSubPassIndex(subpassDependency.fromSubpassIndex), + ToSubPassIndex(subpassDependency.toSubpassIndex), + ToVulkan(subpassDependency.fromStages), + ToVulkan(subpassDependency.toStages), + ToVulkan(subpassDependency.fromAccessFlags), + ToVulkan(subpassDependency.toAccessFlags), + VkDependencyFlags((subpassDependency.tilable) ? VK_DEPENDENCY_BY_REGION_BIT : 0) + }); + } + + VkRenderPassCreateInfo renderPassInfo = { + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // sType + nullptr, // pNext + 0, // flags + UInt32(vkAttachments.size()), // attachmentCount + vkAttachments.data(), // pAttachments + UInt32(vkSubpassDescs.size()), // subpassCount + vkSubpassDescs.data(), // pSubpasses + UInt32(vkSubpassDeps.size()), // dependencyCount + vkSubpassDeps.data() // pDependencies + }; + + if (!m_renderPass.Create(device, renderPassInfo)) + throw std::runtime_error("failed to instantiate Vulkan render pass: " + TranslateVulkanError(m_renderPass.GetLastErrorCode())); + } } diff --git a/src/Nazara/VulkanRenderer/VulkanRenderPipeline.cpp b/src/Nazara/VulkanRenderer/VulkanRenderPipeline.cpp index 72430f5b5..39ee2c154 100644 --- a/src/Nazara/VulkanRenderer/VulkanRenderPipeline.cpp +++ b/src/Nazara/VulkanRenderer/VulkanRenderPipeline.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include @@ -19,20 +19,31 @@ namespace Nz m_pipelineCreateInfo = BuildCreateInfo(m_pipelineInfo); } - VkPipeline VulkanRenderPipeline::Get(const Vk::RenderPass& renderPass) const + VkPipeline VulkanRenderPipeline::Get(const VulkanRenderPass& renderPass, std::size_t subpassIndex) const { - if (auto it = m_pipelines.find(renderPass); it != m_pipelines.end()) + const Vk::RenderPass& renderPassHandle = renderPass.GetRenderPass(); + + // Use color attachment count as a key + const auto& subpasses = renderPass.GetSubpassDescriptions(); + assert(subpassIndex < subpasses.size()); + + std::size_t colorAttachmentCount = subpasses[subpassIndex].colorAttachment.size(); + + std::pair key = { renderPassHandle, colorAttachmentCount }; + + if (auto it = m_pipelines.find(key); it != m_pipelines.end()) return it->second; - // Copy create info to make Get re-entrant + UpdateCreateInfo(colorAttachmentCount); + VkGraphicsPipelineCreateInfo pipelineCreateInfo = m_pipelineCreateInfo.pipelineInfo; - pipelineCreateInfo.renderPass = renderPass; + pipelineCreateInfo.renderPass = renderPassHandle; Vk::Pipeline newPipeline; if (!newPipeline.CreateGraphics(*m_device, pipelineCreateInfo)) return VK_NULL_HANDLE; - auto it = m_pipelines.emplace(renderPass, std::move(newPipeline)).first; + auto it = m_pipelines.emplace(key, std::move(newPipeline)).first; return it->second; } @@ -42,15 +53,19 @@ namespace Nz VkPipelineColorBlendAttachmentState& colorBlendState = colorBlendStates.emplace_back(); colorBlendState.blendEnable = pipelineInfo.blending; - colorBlendState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; //< TODO + if (pipelineInfo.colorWrite) + colorBlendState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; //< TODO + else + colorBlendState.colorWriteMask = 0; if (pipelineInfo.blending) { - //TODO - /*switch (pipelineInfo.dstBlend) - { - blendState.dstAlphaBlendFactor - }*/ + colorBlendState.srcColorBlendFactor = ToVulkan(pipelineInfo.blend.srcColor); + colorBlendState.dstColorBlendFactor = ToVulkan(pipelineInfo.blend.dstColor); + colorBlendState.colorBlendOp = ToVulkan(pipelineInfo.blend.modeColor); + colorBlendState.srcAlphaBlendFactor = ToVulkan(pipelineInfo.blend.srcAlpha); + colorBlendState.dstAlphaBlendFactor = ToVulkan(pipelineInfo.blend.dstAlpha); + colorBlendState.alphaBlendOp = ToVulkan(pipelineInfo.blend.modeAlpha); } else { @@ -65,7 +80,7 @@ namespace Nz return colorBlendStates; } - VkPipelineColorBlendStateCreateInfo VulkanRenderPipeline::BuildColorBlendInfo(const RenderPipelineInfo& pipelineInfo, const std::vector& attachmentState) + VkPipelineColorBlendStateCreateInfo VulkanRenderPipeline::BuildColorBlendInfo(const RenderPipelineInfo& /*pipelineInfo*/, const std::vector& attachmentState) { VkPipelineColorBlendStateCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; @@ -89,7 +104,7 @@ namespace Nz return createInfo; } - VkPipelineDynamicStateCreateInfo VulkanRenderPipeline::BuildDynamicStateInfo(const RenderPipelineInfo& pipelineInfo, const std::vector& dynamicStates) + VkPipelineDynamicStateCreateInfo VulkanRenderPipeline::BuildDynamicStateInfo(const RenderPipelineInfo& /*pipelineInfo*/, const std::vector& dynamicStates) { VkPipelineDynamicStateCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; @@ -99,7 +114,7 @@ namespace Nz return createInfo; } - std::vector VulkanRenderPipeline::BuildDynamicStateList(const RenderPipelineInfo& pipelineInfo) + std::vector VulkanRenderPipeline::BuildDynamicStateList(const RenderPipelineInfo& /*pipelineInfo*/) { return { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; } @@ -113,7 +128,7 @@ namespace Nz return createInfo; } - VkPipelineMultisampleStateCreateInfo VulkanRenderPipeline::BuildMultisampleInfo(const RenderPipelineInfo& pipelineInfo) + VkPipelineMultisampleStateCreateInfo VulkanRenderPipeline::BuildMultisampleInfo(const RenderPipelineInfo& /*pipelineInfo*/) { VkPipelineMultisampleStateCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; @@ -128,14 +143,14 @@ namespace Nz VkPipelineRasterizationStateCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; createInfo.polygonMode = ToVulkan(pipelineInfo.faceFilling); - createInfo.cullMode = ToVulkan(pipelineInfo.cullingSide); - createInfo.frontFace = VK_FRONT_FACE_CLOCKWISE; //< TODO + createInfo.cullMode = (pipelineInfo.faceCulling) ? ToVulkan(pipelineInfo.cullingSide) : VK_CULL_MODE_NONE; + createInfo.frontFace = ToVulkan(pipelineInfo.frontFace); createInfo.lineWidth = pipelineInfo.lineWidth; return createInfo; } - VkPipelineViewportStateCreateInfo VulkanRenderPipeline::BuildViewportInfo(const RenderPipelineInfo& pipelineInfo) + VkPipelineViewportStateCreateInfo VulkanRenderPipeline::BuildViewportInfo(const RenderPipelineInfo& /*pipelineInfo*/) { VkPipelineViewportStateCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; @@ -164,15 +179,19 @@ namespace Nz { std::vector shaderStageCreateInfos; - for (auto&& stagePtr : pipelineInfo.shaderStages) + for (auto&& stagePtr : pipelineInfo.shaderModules) { - Nz::VulkanShaderStage& vulkanStage = *static_cast(stagePtr.get()); + assert(stagePtr); - VkPipelineShaderStageCreateInfo& createInfo = shaderStageCreateInfos.emplace_back(); - createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - createInfo.module = vulkanStage.GetHandle(); - createInfo.pName = "main"; - createInfo.stage = ToVulkan(vulkanStage.GetStageType()); + Nz::VulkanShaderModule& vulkanModule = *static_cast(stagePtr.get()); + for (auto& stage : vulkanModule.GetStages()) + { + VkPipelineShaderStageCreateInfo& createInfo = shaderStageCreateInfos.emplace_back(); + createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + createInfo.module = vulkanModule.GetHandle(); + createInfo.pName = stage.name.data(); + createInfo.stage = ToVulkan(stage.stage); + } } return shaderStageCreateInfos; @@ -216,7 +235,7 @@ namespace Nz return vertexBindings; } - VkPipelineVertexInputStateCreateInfo VulkanRenderPipeline::BuildVertexInputInfo(const RenderPipelineInfo& pipelineInfo, const std::vector& vertexAttributes, const std::vector& bindingDescriptions) + VkPipelineVertexInputStateCreateInfo VulkanRenderPipeline::BuildVertexInputInfo(const RenderPipelineInfo& /*pipelineInfo*/, const std::vector& vertexAttributes, const std::vector& bindingDescriptions) { VkPipelineVertexInputStateCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; @@ -267,4 +286,20 @@ namespace Nz return createInfo; } + + void VulkanRenderPipeline::UpdateCreateInfo(std::size_t colorBufferCount) const + { + // TODO: Add support for independent blend + std::size_t previousSize = m_pipelineCreateInfo.colorBlendAttachmentState.size(); + if (previousSize < colorBufferCount) + { + assert(!m_pipelineCreateInfo.colorBlendAttachmentState.empty()); + + m_pipelineCreateInfo.colorBlendAttachmentState.resize(colorBufferCount); + for (std::size_t i = previousSize; i < colorBufferCount; ++i) + m_pipelineCreateInfo.colorBlendAttachmentState[i] = m_pipelineCreateInfo.colorBlendAttachmentState.front(); + } + + m_pipelineCreateInfo.stateData->colorBlendState = BuildColorBlendInfo(m_pipelineInfo, m_pipelineCreateInfo.colorBlendAttachmentState); + } } diff --git a/src/Nazara/VulkanRenderer/VulkanRenderPipelineLayout.cpp b/src/Nazara/VulkanRenderer/VulkanRenderPipelineLayout.cpp index ad76aa5b9..7d7a9c333 100644 --- a/src/Nazara/VulkanRenderer/VulkanRenderPipelineLayout.cpp +++ b/src/Nazara/VulkanRenderer/VulkanRenderPipelineLayout.cpp @@ -83,8 +83,10 @@ namespace Nz } DescriptorPool pool; - if (!pool.descriptorPool.Create(*m_device, MaxSet, UInt32(poolSizes.size()), poolSizes.data(), VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT)) - throw std::runtime_error("Failed to allocate new descriptor pool: " + TranslateVulkanError(pool.descriptorPool.GetLastErrorCode())); + pool.descriptorPool = std::make_unique(); + + if (!pool.descriptorPool->Create(*m_device, MaxSet, UInt32(poolSizes.size()), poolSizes.data(), VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT)) + throw std::runtime_error("failed to allocate new descriptor pool: " + TranslateVulkanError(pool.descriptorPool->GetLastErrorCode())); pool.freeBindings.Resize(MaxSet, true); pool.storage = std::make_unique(MaxSet); @@ -100,10 +102,10 @@ namespace Nz if (freeBindingId == pool.freeBindings.npos) return {}; //< No free binding in this pool - Vk::DescriptorSet descriptorSet = pool.descriptorPool.AllocateDescriptorSet(m_descriptorSetLayout); + Vk::DescriptorSet descriptorSet = pool.descriptorPool->AllocateDescriptorSet(m_descriptorSetLayout); if (!descriptorSet) { - NazaraWarning("Failed to allocate descriptor set: " + TranslateVulkanError(pool.descriptorPool.GetLastErrorCode())); + NazaraWarning("Failed to allocate descriptor set: " + TranslateVulkanError(pool.descriptorPool->GetLastErrorCode())); return {}; } diff --git a/src/Nazara/VulkanRenderer/VulkanRenderer.cpp b/src/Nazara/VulkanRenderer/VulkanRenderer.cpp index 6f1213a34..ab9db0069 100644 --- a/src/Nazara/VulkanRenderer/VulkanRenderer.cpp +++ b/src/Nazara/VulkanRenderer/VulkanRenderer.cpp @@ -32,13 +32,24 @@ namespace Nz std::shared_ptr VulkanRenderer::InstanciateRenderDevice(std::size_t deviceIndex) { - assert(deviceIndex < m_physDevices.size()); - return Vulkan::SelectDevice(m_physDevices[deviceIndex]); + const auto& physDevices = Vulkan::GetPhysicalDevices(); + + assert(deviceIndex < physDevices.size()); + return Vulkan::SelectDevice(physDevices[deviceIndex]); } bool VulkanRenderer::Prepare(const ParameterList& parameters) { - return Vulkan::Initialize(APIVersion, parameters); + if (!Vulkan::Initialize(APIVersion, parameters)) + return false; + + const auto& physDevices = Vulkan::GetPhysicalDevices(); + + m_deviceInfos.reserve(physDevices.size()); + for (const Vk::PhysicalDevice& physDevice : physDevices) + m_deviceInfos.push_back(Vulkan::BuildRenderDeviceInfo(physDevice)); + + return true; } RenderAPI VulkanRenderer::QueryAPI() const @@ -59,43 +70,8 @@ namespace Nz return APIVersion; } - std::vector VulkanRenderer::QueryRenderDevices() const + const std::vector& VulkanRenderer::QueryRenderDevices() const { - std::vector devices; - devices.reserve(m_physDevices.size()); - - for (const Vk::PhysicalDevice& physDevice : m_physDevices) - { - RenderDeviceInfo& device = devices.emplace_back(); - device.name = physDevice.properties.deviceName; - - switch (physDevice.properties.deviceType) - { - case VK_PHYSICAL_DEVICE_TYPE_CPU: - device.type = RenderDeviceType::Software; - break; - - case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: - device.type = RenderDeviceType::Dedicated; - break; - - case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: - device.type = RenderDeviceType::Integrated; - break; - - case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: - device.type = RenderDeviceType::Virtual; - break; - - default: - NazaraWarning("Device " + device.name + " has handled device type (0x" + NumberToString(physDevice.properties.deviceType, 16) + ')'); - // fallthrough - case VK_PHYSICAL_DEVICE_TYPE_OTHER: - device.type = RenderDeviceType::Unknown; - break; - } - } - - return devices; + return m_deviceInfos; } } diff --git a/src/Nazara/VulkanRenderer/VulkanShaderBinding.cpp b/src/Nazara/VulkanRenderer/VulkanShaderBinding.cpp index 58f9731ac..abec596e4 100644 --- a/src/Nazara/VulkanRenderer/VulkanShaderBinding.cpp +++ b/src/Nazara/VulkanRenderer/VulkanShaderBinding.cpp @@ -13,14 +13,16 @@ namespace Nz { - void VulkanShaderBinding::Update(std::initializer_list bindings) + void VulkanShaderBinding::Update(const Binding* bindings, std::size_t bindingCount) { - StackVector bufferBinding = NazaraStackVector(VkDescriptorBufferInfo, bindings.size()); - StackVector imageBinding = NazaraStackVector(VkDescriptorImageInfo, bindings.size()); - StackVector writeOps = NazaraStackVector(VkWriteDescriptorSet, bindings.size()); + StackVector bufferBinding = NazaraStackVector(VkDescriptorBufferInfo, bindingCount); + StackVector imageBinding = NazaraStackVector(VkDescriptorImageInfo, bindingCount); + StackVector writeOps = NazaraStackVector(VkWriteDescriptorSet, bindingCount); - for (const Binding& binding : bindings) + for (std::size_t i = 0; i < bindingCount; ++i) { + const Binding& binding = bindings[i]; + VkWriteDescriptorSet& writeOp = writeOps.emplace_back(); writeOp.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writeOp.dstSet = m_descriptorSet; @@ -32,31 +34,29 @@ namespace Nz if constexpr (std::is_same_v) { - VulkanTexture& vkTexture = *static_cast(arg.texture); - VulkanTextureSampler& vkSampler = *static_cast(arg.sampler); + VulkanTexture* vkTexture = static_cast(arg.texture); + VulkanTextureSampler* vkSampler = static_cast(arg.sampler); VkDescriptorImageInfo& imageInfo = imageBinding.emplace_back(); imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageInfo.imageView = vkTexture.GetImageView(); - imageInfo.sampler = vkSampler.GetSampler(); + imageInfo.imageView = (vkTexture) ? vkTexture->GetImageView() : VK_NULL_HANDLE; + imageInfo.sampler = (vkSampler) ? vkSampler->GetSampler() : VK_NULL_HANDLE; writeOp.descriptorCount = 1; writeOp.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - writeOp.pImageInfo = &imageInfo; } else if constexpr (std::is_same_v) { - VulkanBuffer& vkBuffer = *static_cast(arg.buffer); + VulkanBuffer* vkBuffer = static_cast(arg.buffer); VkDescriptorBufferInfo& bufferInfo = bufferBinding.emplace_back(); - bufferInfo.buffer = vkBuffer.GetBuffer(); + bufferInfo.buffer = (vkBuffer) ? vkBuffer->GetBuffer() : VK_NULL_HANDLE; bufferInfo.offset = arg.offset; bufferInfo.range = arg.range; writeOp.descriptorCount = 1; writeOp.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - writeOp.pBufferInfo = &bufferInfo; } else diff --git a/src/Nazara/VulkanRenderer/VulkanShaderModule.cpp b/src/Nazara/VulkanRenderer/VulkanShaderModule.cpp new file mode 100644 index 000000000..a414d4551 --- /dev/null +++ b/src/Nazara/VulkanRenderer/VulkanShaderModule.cpp @@ -0,0 +1,148 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Vulkan Renderer" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + namespace + { + struct SpirvEntryPointExtractor : SpirvDecoder + { + struct EntryPoint + { + SpirvExecutionModel executionModel; + std::string name; + }; + + std::vector entryPoints; + + bool HandleOpcode(const SpirvInstruction& instruction, UInt32 /*wordCount*/) override + { + switch (instruction.op) + { + // All instructions that can appear before OpEntryPoint + case SpirvOp::OpCapability: + case SpirvOp::OpExtension: + case SpirvOp::OpExtInstImport: + case SpirvOp::OpMemoryModel: + return true; + + case SpirvOp::OpEntryPoint: + { + SpirvExecutionModel executionModel = static_cast(ReadWord()); + ReadWord(); // func id + std::string name = ReadString(); + + entryPoints.push_back({ + executionModel, + std::move(name) + }); + + return true; + } + + // Return false for other instructions (which means OpEntryPoint will no longer appear from here) + default: + return false; + } + } + }; + } + + bool VulkanShaderModule::Create(Vk::Device& device, ShaderStageTypeFlags shaderStages, ShaderAst::StatementPtr& shaderAst, const ShaderWriter::States& states) + { + SpirvWriter::Environment env; + + SpirvWriter writer; + writer.SetEnv(env); + + std::vector code = writer.Generate(shaderAst, states); + return Create(device, shaderStages, ShaderLanguage::SpirV, code.data(), code.size() * sizeof(UInt32), {}); + } + + bool VulkanShaderModule::Create(Vk::Device& device, ShaderStageTypeFlags shaderStages, ShaderLanguage lang, const void* source, std::size_t sourceSize, const ShaderWriter::States& states) + { + switch (lang) + { + case ShaderLanguage::GLSL: + case ShaderLanguage::HLSL: + case ShaderLanguage::MSL: + break; + + case ShaderLanguage::NazaraBinary: + { + auto shader = ShaderAst::UnserializeShader(source, sourceSize); + return Create(device, shaderStages, shader, {}); + } + + case ShaderLanguage::NazaraShader: + { + std::vector tokens = Nz::ShaderLang::Tokenize(std::string_view(static_cast(source), sourceSize)); + + Nz::ShaderLang::Parser parser; + Nz::ShaderAst::StatementPtr shaderAst = parser.Parse(tokens); + return Create(device, shaderStages, shaderAst, states); + } + + case ShaderLanguage::SpirV: + { + SpirvEntryPointExtractor extractor; + extractor.Decode(reinterpret_cast(source), sourceSize / sizeof(UInt32)); + + ShaderStageTypeFlags remainingStages = shaderStages; + for (auto& entryPoint : extractor.entryPoints) + { + ShaderStageType stageType; + switch (entryPoint.executionModel) + { + case SpirvExecutionModel::Fragment: + stageType = ShaderStageType::Fragment; + break; + + case SpirvExecutionModel::Vertex: + stageType = ShaderStageType::Vertex; + break; + + default: + continue; //< Ignore + } + + if (!remainingStages.Test(stageType)) + continue; + + m_stages.push_back({ + stageType, + std::move(entryPoint.name) + }); + + remainingStages.Clear(stageType); + } + + if (remainingStages != 0) + { + NazaraError("Vulkan shader module does not handle all requested stage types"); + return false; + } + + if (!m_shaderModule.Create(device, reinterpret_cast(source), sourceSize)) + { + NazaraError("failed to create shader module"); + return false; + } + + return true; + } + } + + NazaraError("this language is not supported"); + return false; + } +} diff --git a/src/Nazara/VulkanRenderer/VulkanShaderStage.cpp b/src/Nazara/VulkanRenderer/VulkanShaderStage.cpp deleted file mode 100644 index 9459ccfe3..000000000 --- a/src/Nazara/VulkanRenderer/VulkanShaderStage.cpp +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Vulkan Renderer" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include -#include -#include -#include - -namespace Nz -{ - bool VulkanShaderStage::Create(Vk::Device& device, ShaderStageType type, ShaderLanguage lang, const void* source, std::size_t sourceSize) - { - m_stage = type; - - switch (lang) - { - case ShaderLanguage::NazaraBinary: - { - ByteStream byteStream(source, sourceSize); - auto shader = Nz::UnserializeShader(byteStream); - - if (shader.GetStage() != type) - throw std::runtime_error("incompatible shader stage"); - - SpirvWriter::Environment env; - - SpirvWriter writer; - writer.SetEnv(env); - - std::vector code = writer.Generate(shader); - - if (!m_shaderModule.Create(device, code.data(), code.size() * sizeof(UInt32))) - { - NazaraError("Failed to create shader module"); - return false; - } - - break; - } - - case ShaderLanguage::SpirV: - { - if (!m_shaderModule.Create(device, reinterpret_cast(source), sourceSize)) - { - NazaraError("Failed to create shader module"); - return false; - } - - break; - } - - default: - { - NazaraError("this language is not supported"); - return false; - } - } - - return true; - } -} diff --git a/src/Nazara/VulkanRenderer/VulkanSingleFramebuffer.cpp b/src/Nazara/VulkanRenderer/VulkanSingleFramebuffer.cpp index a8ecb74ad..e445e2a5f 100644 --- a/src/Nazara/VulkanRenderer/VulkanSingleFramebuffer.cpp +++ b/src/Nazara/VulkanRenderer/VulkanSingleFramebuffer.cpp @@ -3,8 +3,42 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include +#include +#include +#include #include namespace Nz { + VulkanSingleFramebuffer::VulkanSingleFramebuffer(Vk::Device& device, unsigned int width, unsigned int height, const std::shared_ptr& renderPass, const std::vector>& attachments) : + VulkanFramebuffer(Type::Single) + { + assert(renderPass); + const VulkanRenderPass& vkRenderPass = static_cast(*renderPass); + + StackArray imageViews = NazaraStackArrayNoInit(VkImageView, attachments.size()); + for (std::size_t i = 0; i < attachments.size(); ++i) + { + assert(attachments[i]); + + const VulkanTexture& vkTexture = static_cast(*attachments[i]); + imageViews[i] = vkTexture.GetImageView(); + } + + VkFramebufferCreateInfo createInfo = { + VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + nullptr, + 0, + vkRenderPass.GetRenderPass(), + UInt32(imageViews.size()), + imageViews.data(), + UInt32(width), + UInt32(height), + 1 + }; + + if (!m_framebuffer.Create(device, createInfo)) + throw std::runtime_error("failed to instantiate Vulkan framebuffer: " + TranslateVulkanError(m_framebuffer.GetLastErrorCode())); + } } diff --git a/src/Nazara/VulkanRenderer/VulkanSurface.cpp b/src/Nazara/VulkanRenderer/VulkanSurface.cpp index 279231880..9b9707774 100644 --- a/src/Nazara/VulkanRenderer/VulkanSurface.cpp +++ b/src/Nazara/VulkanRenderer/VulkanSurface.cpp @@ -4,6 +4,7 @@ #include #include +#include #include namespace Nz diff --git a/src/Nazara/VulkanRenderer/VulkanTexture.cpp b/src/Nazara/VulkanRenderer/VulkanTexture.cpp index 20900d81f..c0e775764 100644 --- a/src/Nazara/VulkanRenderer/VulkanTexture.cpp +++ b/src/Nazara/VulkanRenderer/VulkanTexture.cpp @@ -24,7 +24,7 @@ namespace Nz createInfo.mipLevels = params.mipmapLevel; createInfo.samples = VK_SAMPLE_COUNT_1_BIT; createInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - createInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + createInfo.usage = ToVulkan(params.usageFlags); VkImageViewCreateInfo createInfoView = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; createInfoView.subresourceRange = { @@ -39,7 +39,7 @@ namespace Nz switch (params.type) { - case ImageType_1D: + case ImageType::E1D: NazaraAssert(params.width > 0, "Width must be over zero"); createInfoView.viewType = VK_IMAGE_VIEW_TYPE_1D; @@ -51,7 +51,7 @@ namespace Nz createInfo.arrayLayers = 1; break; - case ImageType_1D_Array: + case ImageType::E1D_Array: NazaraAssert(params.width > 0, "Width must be over zero"); NazaraAssert(params.height > 0, "Height must be over zero"); @@ -64,7 +64,7 @@ namespace Nz createInfo.arrayLayers = params.height; break; - case ImageType_2D: + case ImageType::E2D: NazaraAssert(params.width > 0, "Width must be over zero"); NazaraAssert(params.height > 0, "Height must be over zero"); @@ -77,7 +77,7 @@ namespace Nz createInfo.arrayLayers = 1; break; - case ImageType_2D_Array: + case ImageType::E2D_Array: NazaraAssert(params.width > 0, "Width must be over zero"); NazaraAssert(params.height > 0, "Height must be over zero"); NazaraAssert(params.depth > 0, "Depth must be over zero"); @@ -91,7 +91,7 @@ namespace Nz createInfo.arrayLayers = params.depth; break; - case ImageType_3D: + case ImageType::E3D: NazaraAssert(params.width > 0, "Width must be over zero"); NazaraAssert(params.height > 0, "Height must be over zero"); NazaraAssert(params.depth > 0, "Depth must be over zero"); @@ -105,11 +105,12 @@ namespace Nz createInfo.arrayLayers = 1; break; - case ImageType_Cubemap: + case ImageType::Cubemap: NazaraAssert(params.width > 0, "Width must be over zero"); NazaraAssert(params.height > 0, "Height must be over zero"); createInfoView.viewType = VK_IMAGE_VIEW_TYPE_CUBE; + createInfoView.subresourceRange.layerCount = 6; createInfo.imageType = VK_IMAGE_TYPE_2D; createInfo.extent.width = params.width; @@ -168,6 +169,8 @@ namespace Nz bool VulkanTexture::Update(const void* ptr) { std::size_t textureSize = m_params.width * m_params.height * m_params.depth * PixelFormatInfo::GetBytesPerPixel(m_params.pixelFormat); + if (m_params.type == ImageType::Cubemap) + textureSize *= 6; VkBufferCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; @@ -200,11 +203,26 @@ namespace Nz if (!copyCommandBuffer->Begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT)) return false; - copyCommandBuffer->SetImageLayout(m_image, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + VkImageSubresourceLayers subresourceLayers = { //< FIXME + VK_IMAGE_ASPECT_COLOR_BIT, + 0, //< mipLevel + 0, //< baseArrayLayer + (m_params.type == ImageType::Cubemap) ? 6 : 1 //< layerCount + }; - copyCommandBuffer->CopyBufferToImage(stagingBuffer, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, m_params.width, m_params.height, m_params.depth); + VkImageSubresourceRange subresourceRange = { //< FIXME + VK_IMAGE_ASPECT_COLOR_BIT, + 0, //< baseMipLevel + 1, //< levelCount + subresourceLayers.baseArrayLayer, //< baseArrayLayer + subresourceLayers.layerCount //< layerCount + }; - copyCommandBuffer->SetImageLayout(m_image, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + copyCommandBuffer->SetImageLayout(m_image, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, subresourceRange); + + copyCommandBuffer->CopyBufferToImage(stagingBuffer, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, subresourceLayers, m_params.width, m_params.height, m_params.depth); + + copyCommandBuffer->SetImageLayout(m_image, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, subresourceRange); if (!copyCommandBuffer->End()) return false; @@ -227,11 +245,67 @@ namespace Nz VK_COMPONENT_SWIZZLE_A }; + // TODO: Fill this switch switch (pixelFormat) { - case PixelFormat_L8: + case PixelFormat::BGR8: + case PixelFormat::BGR8_SRGB: + case PixelFormat::BGRA8: + case PixelFormat::BGRA8_SRGB: + case PixelFormat::RGB8: + case PixelFormat::RGB8_SRGB: + case PixelFormat::RGBA8: + case PixelFormat::RGBA8_SRGB: + case PixelFormat::RGBA32F: { - createImage.format = VK_FORMAT_R8_SRGB; + createImage.format = ToVulkan(pixelFormat); + createImageView.format = createImage.format; + break; + } + + case PixelFormat::Depth16: + { + createImage.format = VK_FORMAT_D16_UNORM; + createImageView.format = createImage.format; + createImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + break; + } + + case PixelFormat::Depth16Stencil8: + { + createImage.format = VK_FORMAT_D16_UNORM_S8_UINT; + createImageView.format = createImage.format; + createImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + break; + } + + case PixelFormat::Depth24Stencil8: + { + createImage.format = VK_FORMAT_D24_UNORM_S8_UINT; + createImageView.format = createImage.format; + createImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + break; + } + + case PixelFormat::Depth32F: + { + createImage.format = VK_FORMAT_D32_SFLOAT; + createImageView.format = createImage.format; + createImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + break; + } + + case PixelFormat::Depth32FStencil8: + { + createImage.format = VK_FORMAT_D32_SFLOAT_S8_UINT; + createImageView.format = createImage.format; + createImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + break; + } + + case PixelFormat::L8: + { + createImage.format = VK_FORMAT_R8_UNORM; createImageView.format = createImage.format; createImageView.components = { VK_COMPONENT_SWIZZLE_R, @@ -242,9 +316,9 @@ namespace Nz break; } - case PixelFormat_LA8: + case PixelFormat::LA8: { - createImage.format = VK_FORMAT_R8G8_SRGB; + createImage.format = VK_FORMAT_R8G8_UNORM; createImageView.format = createImage.format; createImageView.components = { VK_COMPONENT_SWIZZLE_R, @@ -255,20 +329,6 @@ namespace Nz break; } - case PixelFormat_RGB8: - { - createImage.format = VK_FORMAT_R8G8B8_SRGB; - createImageView.format = createImage.format; - break; - } - - case PixelFormat_RGBA8: - { - createImage.format = VK_FORMAT_R8G8B8A8_SRGB; - createImageView.format = createImage.format; - break; - } - default: throw std::runtime_error("Unsupported pixel format " + PixelFormatInfo::GetName(pixelFormat)); } diff --git a/src/Nazara/VulkanRenderer/VulkanUploadPool.cpp b/src/Nazara/VulkanRenderer/VulkanUploadPool.cpp index 3d0027332..5897d09b7 100644 --- a/src/Nazara/VulkanRenderer/VulkanUploadPool.cpp +++ b/src/Nazara/VulkanRenderer/VulkanUploadPool.cpp @@ -19,8 +19,6 @@ namespace Nz auto VulkanUploadPool::Allocate(UInt64 size, UInt64 alignment) -> VulkanAllocation& { - assert(size <= m_blockSize); - // Try to minimize lost space struct { @@ -32,7 +30,7 @@ namespace Nz for (Block& block : m_blocks) { UInt64 alignedOffset = AlignPow2(block.freeOffset, alignment); - if (alignedOffset + size > m_blockSize) + if (alignedOffset + size > block.size) continue; //< Not enough space UInt64 lostSpace = alignedOffset - block.freeOffset; @@ -48,32 +46,52 @@ namespace Nz // No block found, allocate a new one if (!bestBlock.block) { + // Handle really big allocations (TODO: Handle them separately as they shouldn't be common and can consume a lot of memory) + UInt64 blockSize = std::max(m_blockSize, size); + Block newBlock; - if (!newBlock.buffer.Create(m_device, 0U, m_blockSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT)) - throw std::runtime_error("Failed to create block buffer: " + TranslateVulkanError(newBlock.buffer.GetLastErrorCode())); + newBlock.size = blockSize; + + if (!newBlock.buffer.Create(m_device, 0U, blockSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT)) + throw std::runtime_error("failed to create block buffer: " + TranslateVulkanError(newBlock.buffer.GetLastErrorCode())); VkMemoryRequirements requirement = newBlock.buffer.GetMemoryRequirements(); if (!newBlock.blockMemory.Create(m_device, requirement.size, requirement.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) - throw std::runtime_error("Failed to allocate block memory: " + TranslateVulkanError(newBlock.blockMemory.GetLastErrorCode())); + throw std::runtime_error("failed to allocate block memory: " + TranslateVulkanError(newBlock.blockMemory.GetLastErrorCode())); if (!newBlock.buffer.BindBufferMemory(newBlock.blockMemory)) - throw std::runtime_error("Failed to bind buffer memory: " + TranslateVulkanError(newBlock.buffer.GetLastErrorCode())); + throw std::runtime_error("failed to bind buffer memory: " + TranslateVulkanError(newBlock.buffer.GetLastErrorCode())); if (!newBlock.blockMemory.Map()) - throw std::runtime_error("Failed to map buffer memory: " + TranslateVulkanError(newBlock.buffer.GetLastErrorCode())); + throw std::runtime_error("failed to map buffer memory: " + TranslateVulkanError(newBlock.buffer.GetLastErrorCode())); bestBlock.block = &m_blocks.emplace_back(std::move(newBlock)); bestBlock.alignedOffset = 0; bestBlock.lostSpace = 0; } - VulkanAllocation& allocationData = m_allocations.emplace_back(); + // Now find the proper allocation buffer + std::size_t allocationBlockIndex = m_nextAllocationIndex / AllocationPerBlock; + std::size_t allocationIndex = m_nextAllocationIndex % AllocationPerBlock; + + if (allocationBlockIndex >= m_allocationBlocks.size()) + { + assert(allocationBlockIndex == m_allocationBlocks.size()); + m_allocationBlocks.emplace_back(std::make_unique()); + } + + auto& allocationBlock = *m_allocationBlocks[allocationBlockIndex]; + + VulkanAllocation& allocationData = allocationBlock[allocationIndex]; allocationData.buffer = bestBlock.block->buffer; allocationData.mappedPtr = static_cast(bestBlock.block->blockMemory.GetMappedPointer()) + bestBlock.alignedOffset; allocationData.offset = bestBlock.alignedOffset; allocationData.size = size; + bestBlock.block->freeOffset += size; + m_nextAllocationIndex++; + return allocationData; } @@ -82,6 +100,6 @@ namespace Nz for (Block& block : m_blocks) block.freeOffset = 0; - m_allocations.clear(); + m_nextAllocationIndex = 0; } } diff --git a/src/Nazara/VulkanRenderer/Wrapper/Device.cpp b/src/Nazara/VulkanRenderer/Wrapper/Device.cpp index 5877ef9c9..bdc9c7e20 100644 --- a/src/Nazara/VulkanRenderer/Wrapper/Device.cpp +++ b/src/Nazara/VulkanRenderer/Wrapper/Device.cpp @@ -75,7 +75,7 @@ namespace Nz // Load all device-related functions try { - ErrorFlags flags(ErrorFlag_ThrowException, true); + ErrorFlags flags(ErrorMode::ThrowException, true); UInt32 deviceVersion = deviceInfo.properties.apiVersion; diff --git a/src/Nazara/VulkanRenderer/Wrapper/Instance.cpp b/src/Nazara/VulkanRenderer/Wrapper/Instance.cpp index e15812528..56332e0fd 100644 --- a/src/Nazara/VulkanRenderer/Wrapper/Instance.cpp +++ b/src/Nazara/VulkanRenderer/Wrapper/Instance.cpp @@ -49,7 +49,11 @@ namespace Nz ss << "[Validation]"; - ss << "[" << pCallbackData->messageIdNumber << ":" << pCallbackData->pMessageIdName << "]: " << pCallbackData->pMessage; + ss << "[" << pCallbackData->messageIdNumber; + if (pCallbackData->pMessageIdName) + ss << ":" << pCallbackData->pMessageIdName; + + ss << "]: " << pCallbackData->pMessage; if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) NazaraError(ss.str()); @@ -105,7 +109,7 @@ namespace Nz // And now load everything try { - ErrorFlags flags(ErrorFlag_ThrowException, true); + ErrorFlags flags(ErrorMode::ThrowException, true); #define NAZARA_VULKANRENDERER_INSTANCE_EXT_BEGIN(ext) if (IsExtensionLoaded(#ext)) { #define NAZARA_VULKANRENDERER_INSTANCE_EXT_END() } @@ -131,7 +135,7 @@ namespace Nz return true; } - bool Instance::EnumeratePhysicalDevices(std::vector* devices) + bool Instance::EnumeratePhysicalDevices(std::vector* devices) const { NazaraAssert(devices, "Invalid device vector"); @@ -156,7 +160,7 @@ namespace Nz return true; } - bool Instance::GetPhysicalDeviceExtensions(VkPhysicalDevice device, std::vector* extensionProperties) + bool Instance::GetPhysicalDeviceExtensions(VkPhysicalDevice device, std::vector* extensionProperties) const { NazaraAssert(extensionProperties, "Invalid extension properties vector"); @@ -184,7 +188,7 @@ namespace Nz return true; } - bool Instance::GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice device, std::vector* queueFamilyProperties) + bool Instance::GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice device, std::vector* queueFamilyProperties) const { NazaraAssert(queueFamilyProperties, "Invalid family properties vector"); @@ -215,7 +219,7 @@ namespace Nz } VkDebugUtilsMessengerCreateInfoEXT callbackCreateInfo = { VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT }; - callbackCreateInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT; + callbackCreateInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; callbackCreateInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; callbackCreateInfo.pfnUserCallback = &DebugCallback; diff --git a/src/Nazara/VulkanRenderer/Wrapper/Loader.cpp b/src/Nazara/VulkanRenderer/Wrapper/Loader.cpp index e0937675a..c41ca52c5 100644 --- a/src/Nazara/VulkanRenderer/Wrapper/Loader.cpp +++ b/src/Nazara/VulkanRenderer/Wrapper/Loader.cpp @@ -99,7 +99,7 @@ namespace Nz #define NAZARA_VULKANRENDERER_LOAD_GLOBAL(func) func = reinterpret_cast(GetProcAddr(#func)) try { - ErrorFlags flags(ErrorFlag_ThrowException, true); + ErrorFlags flags(ErrorMode::ThrowException, true); #define NAZARA_VULKANRENDERER_GLOBAL_FUNCTION(func) func = reinterpret_cast(GetProcAddr(#func, false)); #define NAZARA_VULKANRENDERER_GLOBAL_FUNCTION_OPT(func) func = reinterpret_cast(GetProcAddr(#func, true)); diff --git a/src/NazaraSDK/Application.cpp b/src/NazaraSDK/Application.cpp index 148987070..b85059f16 100644 --- a/src/NazaraSDK/Application.cpp +++ b/src/NazaraSDK/Application.cpp @@ -7,11 +7,6 @@ #include #include -#ifndef NDK_SERVER -#include -#include -#endif - namespace Ndk { /*! @@ -33,6 +28,32 @@ namespace Ndk */ Application::Application(int argc, char* argv[]) : Application() + { + ParseCommandline(argc, argv); + } + + /*! + * \brief Runs the application by updating worlds, taking care about windows, ... + */ + bool Application::Run() + { + if (m_shouldQuit) + return false; + + m_updateTime = m_updateClock.Restart() / 1'000'000.f; + + for (World& world : m_worlds) + world.Update(m_updateTime); + + return true; + } + + void Application::ClearWorlds() + { + m_worlds.clear(); + } + + void Application::ParseCommandline(int argc, char* argv[]) { std::regex optionRegex(R"(-(\w+))"); std::regex valueRegex(R"(-(\w+)\s*=\s*(.+))"); @@ -62,46 +83,5 @@ namespace Ndk } } - /*! - * \brief Runs the application by updating worlds, taking care about windows, ... - */ - bool Application::Run() - { - #ifndef NDK_SERVER - bool hasAtLeastOneActiveWindow = false; - - auto it = m_windows.begin(); - while (it != m_windows.end()) - { - Nz::Window& window = *it->window; - - window.ProcessEvents(); - - if (!window.IsOpen(true)) - { - it = m_windows.erase(it); - continue; - } - - hasAtLeastOneActiveWindow = true; - - ++it; - } - - if (m_exitOnClosedWindows && !hasAtLeastOneActiveWindow) - return false; - #endif - - if (m_shouldQuit) - return false; - - m_updateTime = m_updateClock.Restart() / 1'000'000.f; - - for (World& world : m_worlds) - world.Update(m_updateTime); - - return true; - } - Application* Application::s_application = nullptr; } diff --git a/src/NazaraSDK/ClientApplication.cpp b/src/NazaraSDK/ClientApplication.cpp new file mode 100644 index 000000000..fd0f7a3b4 --- /dev/null +++ b/src/NazaraSDK/ClientApplication.cpp @@ -0,0 +1,69 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Development Kit" +// For conditions of distribution and use, see copyright notice in Prerequisites.hpp + +#include +#include +#include + +namespace Ndk +{ + /*! + * \ingroup NDK + * \class Ndk::ClientApplication + * \brief NDK class that represents a client-side application, it offers a set of tools to ease the development + */ + + /*! + * \brief Constructs an ClientApplication object with command-line arguments + * + * Pass the argc and argv arguments from the main function. + * + * Command-line arguments can be retrieved by application methods + * + * This calls Sdk::Initialize() + * + * \remark Only one Application instance can exist at a time + */ + ClientApplication::ClientApplication(int argc, char* argv[]) : + ClientApplication() + { + ParseCommandline(argc, argv); + } + + /*! + * \brief Runs the application by updating worlds, taking care about windows, ... + */ + bool ClientApplication::Run() + { + if (!Application::Run()) + return false; + + bool hasAtLeastOneActiveWindow = false; + + auto it = m_windows.begin(); + while (it != m_windows.end()) + { + Nz::Window& window = *it->window; + + window.ProcessEvents(); + + if (!window.IsOpen(true)) + { + it = m_windows.erase(it); + continue; + } + + hasAtLeastOneActiveWindow = true; + + ++it; + } + + if (m_exitOnClosedWindows && !hasAtLeastOneActiveWindow) + return false; + + return true; + } + + ClientApplication* ClientApplication::s_clientApplication = nullptr; +} diff --git a/src/NazaraSDK/ClientSdk.cpp b/src/NazaraSDK/ClientSdk.cpp new file mode 100644 index 000000000..f9791d9c2 --- /dev/null +++ b/src/NazaraSDK/ClientSdk.cpp @@ -0,0 +1,56 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Development Kit" +// For conditions of distribution and use, see copyright notice in Prerequisites.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Ndk +{ + /*! + * \ingroup NDK + * \class Ndk::Sdk + * \brief NDK class that represents the software development kit, a set of tools made to ease the conception of application + */ + + /*! + * \brief Initializes the Sdk module + * \return true if initialization is successful + * + * \remark Produces a NazaraNotice + */ + ClientSdk::ClientSdk(Config /*config*/) : + ModuleBase("ClientSDK", this) + { + Nz::ErrorFlags errFlags(Nz::ErrorMode::ThrowException, true); + + // Client components + InitializeComponent("NdkList"); + + // Systems + + // Client systems + InitializeSystem(); + } + + /*! + * \brief Uninitializes the Sdk module + * + * \remark Produces a NazaraNotice + */ + ClientSdk::~ClientSdk() = default; + + ClientSdk* ClientSdk::s_instance = nullptr; +} diff --git a/src/NazaraSDK/Components/CollisionComponent2D.cpp b/src/NazaraSDK/Components/CollisionComponent2D.cpp index ced3d8053..a2bbb95e7 100644 --- a/src/NazaraSDK/Components/CollisionComponent2D.cpp +++ b/src/NazaraSDK/Components/CollisionComponent2D.cpp @@ -53,7 +53,7 @@ namespace Ndk * * \param geom Geometry used for collisions */ - void CollisionComponent2D::SetGeom(Nz::Collider2DRef geom, bool recomputeMoment, bool recomputeMassCenter) + void CollisionComponent2D::SetGeom(std::shared_ptr geom, bool recomputeMoment, bool recomputeMassCenter) { m_geom = std::move(geom); diff --git a/src/NazaraSDK/Components/CollisionComponent3D.cpp b/src/NazaraSDK/Components/CollisionComponent3D.cpp index 4983a8af1..e7ec5ebbf 100644 --- a/src/NazaraSDK/Components/CollisionComponent3D.cpp +++ b/src/NazaraSDK/Components/CollisionComponent3D.cpp @@ -24,7 +24,7 @@ namespace Ndk * \remark Produces a NazaraAssert if the entity has no physics component and has no static body */ - void CollisionComponent3D::SetGeom(Nz::Collider3DRef geom) + void CollisionComponent3D::SetGeom(std::shared_ptr geom) { m_geom = std::move(geom); diff --git a/src/NazaraSDK/Components/PhysicsComponent2D.cpp b/src/NazaraSDK/Components/PhysicsComponent2D.cpp index 91d610eb4..ce33e8ce0 100644 --- a/src/NazaraSDK/Components/PhysicsComponent2D.cpp +++ b/src/NazaraSDK/Components/PhysicsComponent2D.cpp @@ -33,7 +33,7 @@ namespace Ndk Nz::Vector2f positionOffset; - Nz::Collider2DRef geom; + std::shared_ptr geom; if (m_entity->HasComponent()) { const CollisionComponent2D& entityCollision = m_entity->GetComponent(); @@ -94,7 +94,7 @@ namespace Ndk if (IsComponent(component)) { NazaraAssert(m_object, "Invalid object"); - m_object->SetGeom(Nz::NullCollider2D::New(), false, false); + m_object->SetGeom(std::make_shared(), false, false); } } diff --git a/src/NazaraSDK/Components/PhysicsComponent3D.cpp b/src/NazaraSDK/Components/PhysicsComponent3D.cpp index c830960a2..718b7fc7d 100644 --- a/src/NazaraSDK/Components/PhysicsComponent3D.cpp +++ b/src/NazaraSDK/Components/PhysicsComponent3D.cpp @@ -30,7 +30,7 @@ namespace Ndk Nz::PhysWorld3D& world = entityWorld->GetSystem().GetWorld(); - Nz::Collider3DRef geom; + std::shared_ptr geom; if (m_entity->HasComponent()) geom = m_entity->GetComponent().GetGeom(); @@ -81,7 +81,7 @@ namespace Ndk { NazaraAssert(m_object, "Invalid object"); - m_object->SetGeom(Nz::NullCollider3D::New()); + m_object->SetGeom(std::make_shared()); } } diff --git a/src/NazaraSDK/EntityList.cpp b/src/NazaraSDK/EntityList.cpp index a6a9d1140..9f15ad0a7 100644 --- a/src/NazaraSDK/EntityList.cpp +++ b/src/NazaraSDK/EntityList.cpp @@ -7,6 +7,149 @@ namespace Ndk { + /*! + * \brief Construct a new entity list by copying another one + */ + EntityList::EntityList(const EntityList& entityList) : + m_entityBits(entityList.m_entityBits), + m_world(entityList.m_world) + { + for (const Ndk::EntityHandle& entity : *this) + entity->RegisterEntityList(this); + + if (m_world) + m_world->RegisterEntityList(this); + } + + /*! + * \brief Construct a new entity list by moving a list into this one + */ + EntityList::EntityList(EntityList&& entityList) noexcept : + m_entityBits(std::move(entityList.m_entityBits)), + m_world(entityList.m_world) + { + for (const Ndk::EntityHandle& entity : *this) + { + entity->UnregisterEntityList(&entityList); + entity->RegisterEntityList(this); + } + + if (m_world) + { + m_world->UnregisterEntityList(&entityList); + m_world->RegisterEntityList(this); + + entityList.m_world = nullptr; + } + } + + EntityList::~EntityList() + { + for (const Ndk::EntityHandle& entity : *this) + entity->UnregisterEntityList(this); + + if (m_world) + m_world->UnregisterEntityList(this); + } + + + /*! + * \brief Clears the set from every entities + * + * \remark This resets the implicit world member, allowing you to insert entities from a different world than previously + */ + void EntityList::Clear() + { + for (const Ndk::EntityHandle& entity : *this) + entity->UnregisterEntityList(this); + + m_entityBits.Clear(); + + if (m_world) + { + m_world->UnregisterEntityList(this); + m_world = nullptr; + } + } + + /*! + * \brief Inserts the entity into the set + * + * Marks an entity as present in this entity list, it must belongs to the same world as others entities contained in this list. + * + * \param entity Valid pointer to an entity + * + * \remark If entity is already contained, no action is performed + * \remark If any entity has been inserted since construction (or last Clear call), the entity must belong to the same world as the previously inserted entities + */ + void EntityList::Insert(Entity* entity) + { + NazaraAssert(entity, "Invalid entity"); + + if (!Has(entity)) + { + entity->RegisterEntityList(this); + + m_entityBits.UnboundedSet(entity->GetId(), true); + if (!m_world) + { + m_world = entity->GetWorld(); + m_world->RegisterEntityList(this); + } + } + } + + EntityList& EntityList::operator=(const EntityList& entityList) + { + if (m_world) + m_world->UnregisterEntityList(this); + + for (const Ndk::EntityHandle& entity : *this) + entity->UnregisterEntityList(this); + + m_entityBits = entityList.m_entityBits; + m_world = entityList.m_world; + + for (const Ndk::EntityHandle& entity : *this) + entity->RegisterEntityList(this); + + if (m_world) + m_world->RegisterEntityList(this); + + return *this; + } + + EntityList& EntityList::operator=(EntityList&& entityList) noexcept + { + if (this == &entityList) + return *this; + + if (m_world) + m_world->UnregisterEntityList(this); + + for (const Ndk::EntityHandle& entity : *this) + entity->UnregisterEntityList(this); + + m_entityBits = std::move(entityList.m_entityBits); + m_world = entityList.m_world; + + if (m_world) + { + m_world->UnregisterEntityList(&entityList); + m_world->RegisterEntityList(this); + + entityList.m_world = nullptr; + } + + for (const Ndk::EntityHandle& entity : *this) + { + entity->UnregisterEntityList(&entityList); + entity->RegisterEntityList(this); + } + + return *this; + } + const EntityHandle& EntityList::iterator::operator*() const { return m_list->GetWorld()->GetEntity(static_cast(m_nextEntityId)); diff --git a/src/NazaraSDK/Sdk.cpp b/src/NazaraSDK/Sdk.cpp index 5c44bf3c8..c548da94f 100644 --- a/src/NazaraSDK/Sdk.cpp +++ b/src/NazaraSDK/Sdk.cpp @@ -19,11 +19,6 @@ #include #include -#ifndef NDK_SERVER -#include -#include -#endif - namespace Ndk { /*! @@ -35,7 +30,7 @@ namespace Ndk Sdk::Sdk(Config /*config*/) : ModuleBase("SDK", this) { - Nz::ErrorFlags errFlags(Nz::ErrorFlag_ThrowException, true); + Nz::ErrorFlags errFlags(Nz::ErrorMode::ThrowException, true); // SDK Initialization @@ -52,11 +47,6 @@ namespace Ndk InitializeComponent("NdkVeloc"); InitializeComponent("NdkCons2"); - #ifndef NDK_SERVER - // Client components - InitializeComponent("NdkList"); - #endif - // Systems BaseSystem::Initialize(); @@ -66,11 +56,6 @@ namespace Ndk InitializeSystem(); InitializeSystem(); InitializeSystem(); - - #ifndef NDK_SERVER - // Client systems - InitializeSystem(); - #endif } Sdk::~Sdk() diff --git a/src/NazaraSDK/Systems/ListenerSystem.cpp b/src/NazaraSDK/Systems/ListenerSystem.cpp index 9fdb2147e..39a488220 100644 --- a/src/NazaraSDK/Systems/ListenerSystem.cpp +++ b/src/NazaraSDK/Systems/ListenerSystem.cpp @@ -52,10 +52,10 @@ namespace Ndk // We get the position and the rotation to affect these to the listener const NodeComponent& node = entity->GetComponent(); - Nz::Vector3f newPos = node.GetPosition(Nz::CoordSys_Global); + Nz::Vector3f newPos = node.GetPosition(Nz::CoordSys::Global); audio->SetListenerPosition(newPos); - audio->SetListenerRotation(node.GetRotation(Nz::CoordSys_Global)); + audio->SetListenerRotation(node.GetRotation(Nz::CoordSys::Global)); // Compute listener velocity based on their old/new position Nz::Vector3f velocity = (newPos - oldPos) / elapsedTime; diff --git a/src/NazaraSDK/Systems/PhysicsSystem2D.cpp b/src/NazaraSDK/Systems/PhysicsSystem2D.cpp index 60ff8e437..fab5be272 100644 --- a/src/NazaraSDK/Systems/PhysicsSystem2D.cpp +++ b/src/NazaraSDK/Systems/PhysicsSystem2D.cpp @@ -196,7 +196,7 @@ namespace Ndk auto& node = entity->GetComponent(); Nz::RigidBody2D* physObj = collision.GetStaticBody(); - physObj->SetPosition(Nz::Vector2f(node.GetPosition(Nz::CoordSys_Global))); + physObj->SetPosition(Nz::Vector2f(node.GetPosition(Nz::CoordSys::Global))); //physObj->SetRotation(node.GetRotation()); } } @@ -224,8 +224,8 @@ namespace Ndk PhysicsComponent2D& phys = entity->GetComponent(); Nz::RigidBody2D* body = phys.GetRigidBody(); - node.SetRotation(body->GetRotation(), Nz::CoordSys_Global); - node.SetPosition(Nz::Vector3f(body->GetPosition(), node.GetPosition(Nz::CoordSys_Global).z), Nz::CoordSys_Global); + node.SetRotation(body->GetRotation(), Nz::CoordSys::Global); + node.SetPosition(Nz::Vector3f(body->GetPosition(), node.GetPosition(Nz::CoordSys::Global).z), Nz::CoordSys::Global); } float invElapsedTime = 1.f / elapsedTime; @@ -237,7 +237,7 @@ namespace Ndk Nz::RigidBody2D* body = collision.GetStaticBody(); Nz::Vector2f oldPosition = body->GetPosition(); - Nz::Vector2f newPosition = Nz::Vector2f(node.GetPosition(Nz::CoordSys_Global)); + Nz::Vector2f newPosition = Nz::Vector2f(node.GetPosition(Nz::CoordSys::Global)); // To move static objects and ensure their collisions, we have to specify them a velocity // (/!\: the physical engine does not apply the speed on static objects) @@ -250,7 +250,7 @@ namespace Ndk body->SetVelocity(Nz::Vector2f::Zero()); Nz::RadianAnglef oldRotation = body->GetRotation(); - Nz::RadianAnglef newRotation = node.GetRotation(Nz::CoordSys_Global).To2DAngle(); + Nz::RadianAnglef newRotation = node.GetRotation(Nz::CoordSys::Global).To2DAngle(); if (newRotation != oldRotation) { diff --git a/src/NazaraSDK/Systems/PhysicsSystem3D.cpp b/src/NazaraSDK/Systems/PhysicsSystem3D.cpp index c83103048..ccc45b7a8 100644 --- a/src/NazaraSDK/Systems/PhysicsSystem3D.cpp +++ b/src/NazaraSDK/Systems/PhysicsSystem3D.cpp @@ -69,8 +69,8 @@ namespace Ndk auto& node = entity->GetComponent(); Nz::RigidBody3D* physObj = collision.GetStaticBody(); - physObj->SetPosition(node.GetPosition(Nz::CoordSys_Global)); - physObj->SetRotation(node.GetRotation(Nz::CoordSys_Global)); + physObj->SetPosition(node.GetPosition(Nz::CoordSys::Global)); + physObj->SetRotation(node.GetRotation(Nz::CoordSys::Global)); } } @@ -97,8 +97,8 @@ namespace Ndk PhysicsComponent3D& phys = entity->GetComponent(); Nz::RigidBody3D* physObj = phys.GetRigidBody(); - node.SetRotation(physObj->GetRotation(), Nz::CoordSys_Global); - node.SetPosition(physObj->GetPosition(), Nz::CoordSys_Global); + node.SetRotation(physObj->GetRotation(), Nz::CoordSys::Global); + node.SetPosition(physObj->GetPosition(), Nz::CoordSys::Global); } float invElapsedTime = 1.f / elapsedTime; @@ -111,8 +111,8 @@ namespace Ndk Nz::Quaternionf oldRotation = physObj->GetRotation(); Nz::Vector3f oldPosition = physObj->GetPosition(); - Nz::Quaternionf newRotation = node.GetRotation(Nz::CoordSys_Global); - Nz::Vector3f newPosition = node.GetPosition(Nz::CoordSys_Global); + Nz::Quaternionf newRotation = node.GetRotation(Nz::CoordSys::Global); + Nz::Vector3f newPosition = node.GetPosition(Nz::CoordSys::Global); // To move static objects and ensure their collisions, we have to specify them a velocity // (/!\: the physical motor does not apply the speed on static objects) @@ -128,9 +128,7 @@ namespace Ndk { Nz::Quaternionf transition = newRotation * oldRotation.GetConjugate(); Nz::EulerAnglesf angles = transition.ToEulerAngles(); - Nz::Vector3f angularVelocity(Nz::ToRadians(angles.pitch * invElapsedTime), - Nz::ToRadians(angles.yaw * invElapsedTime), - Nz::ToRadians(angles.roll * invElapsedTime)); + Nz::Vector3f angularVelocity((angles.pitch * invElapsedTime).ToRadians(), (angles.yaw * invElapsedTime).ToRadians(), (angles.roll * invElapsedTime).ToRadians()); physObj->SetRotation(oldRotation); physObj->SetAngularVelocity(angularVelocity); diff --git a/src/NazaraSDK/World.cpp b/src/NazaraSDK/World.cpp index 42650b169..cdd67873d 100644 --- a/src/NazaraSDK/World.cpp +++ b/src/NazaraSDK/World.cpp @@ -11,10 +11,6 @@ #include #include -#ifndef NDK_SERVER -#include -#endif - namespace Ndk { /*! @@ -35,22 +31,6 @@ namespace Ndk Clear(); } - /*! - * \brief Adds default systems to the world - */ - - void World::AddDefaultSystems() - { - AddSystem(); - AddSystem(); - AddSystem(); - AddSystem(); - - #ifndef NDK_SERVER - AddSystem(); - #endif - } - /*! * \brief Creates an entity in the world * \return The entity created @@ -125,6 +105,11 @@ namespace Ndk } m_entityBlocks.clear(); + // Reset world for entity lists + for (EntityList* list : m_referencedByLists) + list->SetWorld(nullptr); + m_referencedByLists.clear(); + m_entities.clear(); m_waitingEntities.clear(); diff --git a/src/ShaderNode/DataModels/BinOp.hpp b/src/ShaderNode/DataModels/BinOp.hpp new file mode 100644 index 000000000..e8dcfd8a1 --- /dev/null +++ b/src/ShaderNode/DataModels/BinOp.hpp @@ -0,0 +1,163 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_BINOP_HPP +#define NAZARA_SHADERNODES_BINOP_HPP + +#include +#include +#include + +template +class BinOp : public ShaderNode +{ + public: + BinOp(ShaderGraph& graph); + ~BinOp() = default; + + Nz::ShaderAst::NodePtr BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const override; + + virtual QString GetOperationString() const = 0; + + unsigned int nPorts(QtNodes::PortType portType) const override; + + QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + std::shared_ptr outData(QtNodes::PortIndex port) override; + + QString portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + bool portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + void setInData(std::shared_ptr value, int index) override; + + QtNodes::NodeValidationState validationState() const override; + QString validationMessage() const override; + + private: + virtual void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) = 0; + + bool ComputePreview(QPixmap& pixmap) override; + void UpdateOutput(); + + std::shared_ptr m_lhs; + std::shared_ptr m_rhs; + std::shared_ptr m_output; +}; + + +template +class BinAdd : public BinOp +{ + public: + using BinOp::BinOp; + + void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) override; + QString GetOperationString() const final; +}; + +template +class BinMul : public BinOp +{ + public: + using BinOp::BinOp; + + void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) override; + QString GetOperationString() const final; +}; + +template +class BinSub : public BinOp +{ + public: + using BinOp::BinOp; + + void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) override; + QString GetOperationString() const final; +}; + +template +class BinDiv : public BinOp +{ + public: + using BinOp::BinOp; + + void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) override; + QString GetOperationString() const final; +}; + + +class FloatAdd : public BinAdd +{ + public: + using BinAdd::BinAdd; + + QString caption() const override { return "Float addition"; } + QString name() const override { return "float_add"; } +}; + +class FloatMul : public BinMul +{ + public: + using BinMul::BinMul; + + QString caption() const override { return "Float multiplication"; } + QString name() const override { return "float_mul"; } +}; + +class FloatSub : public BinMul +{ + public: + using BinMul::BinMul; + + QString caption() const override { return "Float subtraction"; } + QString name() const override { return "float_sub"; } +}; + +class FloatDiv : public BinDiv +{ + public: + using BinDiv::BinDiv; + + QString caption() const override { return "Float division"; } + QString name() const override { return "float_div"; } +}; + + +class VecAdd : public BinAdd +{ + public: + using BinAdd::BinAdd; + + QString caption() const override { return "Vector addition"; } + QString name() const override { return "vec_add"; } +}; + +class VecMul : public BinMul +{ + public: + using BinMul::BinMul; + + QString caption() const override { return "Vector multiplication"; } + QString name() const override { return "vec_mul"; } +}; + +class VecSub : public BinMul +{ + public: + using BinMul::BinMul; + + QString caption() const override { return "Vector subtraction"; } + QString name() const override { return "vec_sub"; } +}; + +class VecDiv : public BinDiv +{ + public: + using BinDiv::BinDiv; + + QString caption() const override { return "Vector division"; } + QString name() const override { return "vec_div"; } +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/BinOp.inl b/src/ShaderNode/DataModels/BinOp.inl new file mode 100644 index 000000000..b91999e18 --- /dev/null +++ b/src/ShaderNode/DataModels/BinOp.inl @@ -0,0 +1,238 @@ +#include +#include + +template +BinOp::BinOp(ShaderGraph& graph) : +ShaderNode(graph) +{ + UpdateOutput(); +} + +template +Nz::ShaderAst::NodePtr BinOp::BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const +{ + assert(count == 2); + assert(outputIndex == 0); + + return Nz::ShaderBuilder::Binary(Op, std::move(expressions[0]), std::move(expressions[1])); +} + +template +QtNodes::NodeDataType BinOp::dataType(QtNodes::PortType /*portType*/, QtNodes::PortIndex portIndex) const +{ + assert(portIndex == 0 || portIndex == 1); + + return DataType::Type(); +} + +template +unsigned int BinOp::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 2; + case QtNodes::PortType::Out: return 1; + default: break; + } + + assert(false); + throw std::runtime_error("invalid port type"); +} + +template +std::shared_ptr BinOp::outData(QtNodes::PortIndex port) +{ + assert(port == 0); + return m_output; +} + +template +QString BinOp::portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + switch (portType) + { + case QtNodes::PortType::In: + { + switch (portIndex) + { + case 0: + return "A"; + + case 1: + return "B"; + + default: + break; + } + } + + case QtNodes::PortType::Out: + { + assert(portIndex == 0); + return "A " + GetOperationString() + " B"; + } + + default: + break; + } + + return QString{}; +} + +template +bool BinOp::portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + assert(portIndex == 0 || portIndex == 1); + return portType == QtNodes::PortType::In || portType == QtNodes::PortType::Out; +} + +template +void BinOp::setInData(std::shared_ptr value, int index) +{ + assert(index == 0 || index == 1); + + std::shared_ptr castedValue; + if (value && value->type().id == DataType::Type().id) + castedValue = std::static_pointer_cast(value); + + if (index == 0) + m_lhs = std::move(castedValue); + else + m_rhs = std::move(castedValue); + + UpdateOutput(); +} + +template +QtNodes::NodeValidationState BinOp::validationState() const +{ + if (!m_lhs || !m_rhs) + return QtNodes::NodeValidationState::Error; + + if constexpr (std::is_same_v) + { + if (m_lhs->componentCount != m_rhs->componentCount) + return QtNodes::NodeValidationState::Error; + } + + return QtNodes::NodeValidationState::Valid; +} + +template +QString BinOp::validationMessage() const +{ + if (!m_lhs || !m_rhs) + return "Missing operands"; + + if constexpr (std::is_same_v) + { + if (m_lhs->componentCount != m_rhs->componentCount) + return "Incompatible components count (left has " + QString::number(m_lhs->componentCount) + ", right has " + QString::number(m_rhs->componentCount) + ")"; + } + + return QString(); +} + +template +bool BinOp::ComputePreview(QPixmap& pixmap) +{ + if (!m_lhs || !m_rhs) + return false; + + pixmap = QPixmap::fromImage(m_output->preview.GenerateImage()); + return true; +} + +template +void BinOp::UpdateOutput() +{ + if (validationState() != QtNodes::NodeValidationState::Valid) + { + if constexpr (std::is_same_v) + m_output = std::make_shared(4); + else + m_output = std::make_shared(); + + m_output->preview = PreviewValues(1, 1); + m_output->preview.Fill(Nz::Vector4f::Zero()); + return; + } + + if constexpr (std::is_same_v) + m_output = std::make_shared(m_lhs->componentCount); + else + m_output = std::make_shared(); + + const PreviewValues& leftPreview = m_lhs->preview; + const PreviewValues& rightPreview = m_rhs->preview; + std::size_t maxWidth = std::max(leftPreview.GetWidth(), rightPreview.GetWidth()); + std::size_t maxHeight = std::max(leftPreview.GetHeight(), rightPreview.GetHeight()); + + // FIXME: Prevent useless copy + PreviewValues leftResized = leftPreview; + if (leftResized.GetWidth() != maxWidth || leftResized.GetHeight() != maxHeight) + leftResized = leftResized.Resized(maxWidth, maxHeight); + + PreviewValues rightResized = rightPreview; + if (rightResized.GetWidth() != maxWidth || rightResized.GetHeight() != maxHeight) + rightResized = rightResized.Resized(maxWidth, maxHeight); + + m_output->preview = PreviewValues(maxWidth, maxHeight); + ApplyOp(leftResized.GetData(), rightResized.GetData(), m_output->preview.GetData(), maxWidth * maxHeight); + + Q_EMIT dataUpdated(0); + + UpdatePreview(); +} + +template +void BinAdd::ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) +{ + for (std::size_t i = 0; i < pixelCount; ++i) + output[i] = left[i] + right[i]; +} + +template +QString BinAdd::GetOperationString() const +{ + return "+"; +} + +template +void BinMul::ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) +{ + for (std::size_t i = 0; i < pixelCount; ++i) + output[i] = left[i] * right[i]; +} + +template +QString BinMul::GetOperationString() const +{ + return "*"; +} + +template +void BinSub::ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) +{ + for (std::size_t i = 0; i < pixelCount; ++i) + output[i] = left[i] - right[i]; +} + +template +QString BinSub::GetOperationString() const +{ + return "-"; +} + +template +void BinDiv::ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) +{ + for (std::size_t i = 0; i < pixelCount; ++i) + output[i] = left[i] / right[i]; +} + +template +QString BinDiv::GetOperationString() const +{ + return "/"; +} diff --git a/src/ShaderNode/DataModels/BoolValue.cpp b/src/ShaderNode/DataModels/BoolValue.cpp new file mode 100644 index 000000000..2e06c627e --- /dev/null +++ b/src/ShaderNode/DataModels/BoolValue.cpp @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include + +BoolValue::BoolValue(ShaderGraph& graph) : +ShaderNode(graph), +m_value(true) +{ + UpdatePreview(); +} + +QString BoolValue::caption() const +{ + static QString caption = "Boolean constant"; + return caption; +} + +QString BoolValue::name() const +{ + static QString name = "bool_constant"; + return name; +} + +QtNodes::NodeDataType BoolValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + assert(portType == QtNodes::PortType::Out); + assert(portIndex == 0); + + return BoolData::Type(); +} + +unsigned int BoolValue::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 0; + case QtNodes::PortType::Out: return 1; + + default: + break; + } + + assert(false); + throw std::runtime_error("Invalid port type"); +} + +std::shared_ptr BoolValue::outData(QtNodes::PortIndex port) +{ + assert(port == 0); + + float c = (m_value) ? 1.f : 0.f; + + auto out = std::make_shared(); + out->preview(0, 0) = Nz::Vector4f(c, c, c, 1.f); + + return out; +} + +QString BoolValue::portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + assert(portIndex == 0); + assert(portType == QtNodes::PortType::Out); + + return (m_value) ? "true" : "false"; +} + +bool BoolValue::portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + assert(portIndex == 0); + return portType == QtNodes::PortType::Out; +} + +void BoolValue::BuildNodeEdition(QFormLayout* layout) +{ + ShaderNode::BuildNodeEdition(layout); + + QCheckBox* checkbox = new QCheckBox; + checkbox->setCheckState((m_value) ? Qt::Checked : Qt::Unchecked); + connect(checkbox, &QCheckBox::stateChanged, [=](int newState) + { + m_value = (newState == Qt::Checked); + Q_EMIT dataUpdated(0); + + UpdatePreview(); + }); + + layout->addRow(tr("Value"), checkbox); +} + +Nz::ShaderAst::NodePtr BoolValue::BuildNode(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count, std::size_t outputIndex) const +{ + assert(count == 0); + assert(outputIndex == 0); + + return Nz::ShaderBuilder::Constant(m_value); +} + +bool BoolValue::ComputePreview(QPixmap& pixmap) +{ + pixmap.fill(ToColor()); + return true; +} + +QColor BoolValue::ToColor() const +{ + float value = (m_value) ? 1.f : 0.f; + + return QColor::fromRgbF(value, value, value, value); +} + +void BoolValue::restore(const QJsonObject& data) +{ + m_value = float(data["value"].toBool(m_value)); + + ShaderNode::restore(data); +} + +QJsonObject BoolValue::save() const +{ + QJsonObject data = ShaderNode::save(); + data["value"] = m_value; + + return data; +} diff --git a/src/ShaderNode/DataModels/BoolValue.hpp b/src/ShaderNode/DataModels/BoolValue.hpp new file mode 100644 index 000000000..8e906e97b --- /dev/null +++ b/src/ShaderNode/DataModels/BoolValue.hpp @@ -0,0 +1,47 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_BOOLVALUE_HPP +#define NAZARA_SHADERNODES_BOOLVALUE_HPP + +#include +#include +#include +#include +#include +#include +#include + +class BoolValue : public ShaderNode +{ + public: + BoolValue(ShaderGraph& graph); + ~BoolValue() = default; + + Nz::ShaderAst::NodePtr BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const override; + void BuildNodeEdition(QFormLayout* layout) override; + + QString caption() const override; + QString name() const override; + + QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + unsigned int nPorts(QtNodes::PortType portType) const override; + + std::shared_ptr outData(QtNodes::PortIndex port) override; + + QString portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + bool portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + private: + bool ComputePreview(QPixmap& pixmap) override; + QColor ToColor() const; + + void restore(const QJsonObject& data) override; + QJsonObject save() const override; + + bool m_value; +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/BoolValue.inl b/src/ShaderNode/DataModels/BoolValue.inl new file mode 100644 index 000000000..428c66ae7 --- /dev/null +++ b/src/ShaderNode/DataModels/BoolValue.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/DataModels/BufferField.cpp b/src/ShaderNode/DataModels/BufferField.cpp index 1c673e8ca..b191aeba4 100644 --- a/src/ShaderNode/DataModels/BufferField.cpp +++ b/src/ShaderNode/DataModels/BufferField.cpp @@ -49,9 +49,10 @@ ShaderNode(graph) UpdatePreview(); } -Nz::ShaderNodes::ExpressionPtr BufferField::GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const +Nz::ShaderAst::NodePtr BufferField::BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const { assert(count == 0); + assert(outputIndex == 0); if (!m_currentBufferIndex) throw std::runtime_error("no buffer"); @@ -61,23 +62,13 @@ Nz::ShaderNodes::ExpressionPtr BufferField::GetExpression(Nz::ShaderNodes::Expre const auto& bufferEntry = graph.GetBuffer(*m_currentBufferIndex); const auto& structEntry = graph.GetStruct(bufferEntry.structIndex); - Nz::ShaderNodes::VariablePtr varPtr; - switch (bufferEntry.type) - { - case BufferType::UniformBufferObject: - varPtr = Nz::ShaderBuilder::Uniform(bufferEntry.name, structEntry.name); - break; - } - - assert(varPtr); - assert(m_currentFieldIndex); const CurrentField& currentField = *m_currentFieldIndex; - Nz::ShaderNodes::ExpressionPtr sourceExpr = Nz::ShaderBuilder::Identifier(varPtr); + Nz::ShaderAst::ExpressionPtr sourceExpr = Nz::ShaderBuilder::Identifier(bufferEntry.name); - std::vector memberIndices; - memberIndices.reserve(currentField.nestedFields.size() + 1); + std::vector memberIdentifiers; + memberIdentifiers.reserve(currentField.nestedFields.size() + 1); const ShaderGraph::StructEntry* sourceStruct = &structEntry; for (std::size_t nestedIndex : currentField.nestedFields) @@ -89,16 +80,17 @@ Nz::ShaderNodes::ExpressionPtr BufferField::GetExpression(Nz::ShaderNodes::Expre std::size_t nestedStructIndex = std::get(memberEntry.type); sourceStruct = &graph.GetStruct(nestedStructIndex); - memberIndices.push_back(nestedIndex); + memberIdentifiers.push_back(memberEntry.name); } - memberIndices.push_back(currentField.finalFieldIndex); - assert(currentField.finalFieldIndex < sourceStruct->members.size()); const auto& memberEntry = sourceStruct->members[currentField.finalFieldIndex]; assert(std::holds_alternative(memberEntry.type)); - return Nz::ShaderBuilder::AccessMember(std::move(sourceExpr), std::move(memberIndices), graph.ToShaderExpressionType(std::get(memberEntry.type))); + memberIdentifiers.push_back(memberEntry.name); + + using namespace Nz; + return ShaderBuilder::AccessMember(std::move(sourceExpr), std::move(memberIdentifiers)); } unsigned int BufferField::nPorts(QtNodes::PortType portType) const diff --git a/src/ShaderNode/DataModels/BufferField.hpp b/src/ShaderNode/DataModels/BufferField.hpp index 8bd232a7a..eed42d9e1 100644 --- a/src/ShaderNode/DataModels/BufferField.hpp +++ b/src/ShaderNode/DataModels/BufferField.hpp @@ -15,10 +15,9 @@ class BufferField : public ShaderNode BufferField(ShaderGraph& graph); ~BufferField() = default; + Nz::ShaderAst::NodePtr BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const override; void BuildNodeEdition(QFormLayout* layout) override; - Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const override; - QString caption() const override { return "BufferField"; } QString name() const override { return "BufferField"; } diff --git a/src/ShaderNode/DataModels/Cast.hpp b/src/ShaderNode/DataModels/Cast.hpp index c30f3eadc..47f954f81 100644 --- a/src/ShaderNode/DataModels/Cast.hpp +++ b/src/ShaderNode/DataModels/Cast.hpp @@ -17,10 +17,9 @@ class CastVec : public ShaderNode CastVec(ShaderGraph& graph); ~CastVec() = default; + Nz::ShaderAst::NodePtr BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const; void BuildNodeEdition(QFormLayout* layout) override; - Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const override; - QString caption() const override; QString name() const override; diff --git a/src/ShaderNode/DataModels/Cast.inl b/src/ShaderNode/DataModels/Cast.inl index 441ede3f5..e6ea83960 100644 --- a/src/ShaderNode/DataModels/Cast.inl +++ b/src/ShaderNode/DataModels/Cast.inl @@ -17,6 +17,42 @@ ShaderNode(graph) m_output = std::make_shared(ToComponentCount); } +template +Nz::ShaderAst::NodePtr CastVec::BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const +{ + assert(m_input); + assert(count == 1); + assert(outputIndex == 0); + + std::size_t fromComponentCount = m_input->componentCount; + + if (ToComponentCount > fromComponentCount) + { + std::size_t overflowComponentCount = ToComponentCount - fromComponentCount; + + std::vector params; + params.emplace_back(std::move(expressions[0])); + for (std::size_t i = 0; i < overflowComponentCount; ++i) + params.emplace_back(Nz::ShaderBuilder::Constant(m_overflowComponents[i])); + + return Nz::ShaderBuilder::Cast(Nz::ShaderAst::VectorType{ ToComponentCount, Nz::ShaderAst::PrimitiveType::Float32 }, std::move(params)); + } + else if (ToComponentCount < fromComponentCount) + { + std::array swizzleComponents; + for (std::size_t i = 0; i < ToComponentCount; ++i) + swizzleComponents[i] = static_cast(static_cast(Nz::ShaderAst::SwizzleComponent::First) + i); + + return std::apply([&](auto... components) + { + std::initializer_list componentList{ components... }; + return Nz::ShaderBuilder::Swizzle(std::move(expressions[0]), componentList); + }, swizzleComponents); + } + else + return std::move(expressions[0]); //< no-op +} + template void CastVec::BuildNodeEdition(QFormLayout* layout) { @@ -49,43 +85,6 @@ void CastVec::BuildNodeEdition(QFormLayout* layout) } } -template -Nz::ShaderNodes::ExpressionPtr CastVec::GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const -{ - assert(m_input); - assert(count == 1); - - std::size_t fromComponentCount = m_input->componentCount; - - if (ToComponentCount > fromComponentCount) - { - std::size_t overflowComponentCount = ToComponentCount - fromComponentCount; - - std::array expr; - expr[0] = expressions[0]; - for (std::size_t i = 0; i < overflowComponentCount; ++i) - expr[i + 1] = Nz::ShaderBuilder::Constant(m_overflowComponents[i]); - - constexpr auto ExpressionType = VecExpressionType; - - return Nz::ShaderBuilder::Cast(expr.data(), 1 + overflowComponentCount); - } - else if (ToComponentCount < fromComponentCount) - { - std::array swizzleComponents; - for (std::size_t i = 0; i < ToComponentCount; ++i) - swizzleComponents[i] = static_cast(static_cast(Nz::ShaderNodes::SwizzleComponent::First) + i); - - return std::apply([&](auto... components) - { - std::initializer_list componentList{ components... }; - return Nz::ShaderBuilder::Swizzle(expressions[0], componentList); - }, swizzleComponents); - } - else - return expressions[0]; //< no-op -} - template QString CastVec::caption() const { @@ -109,6 +108,7 @@ QtNodes::NodeDataType CastVec::dataType(QtNodes::PortType port { case QtNodes::PortType::In: return VecData::Type(); case QtNodes::PortType::Out: return VecData::Type(); + default: break; } assert(false); @@ -142,7 +142,7 @@ template void CastVec::setInData(std::shared_ptr value, int index) { assert(index == 0); - if (value) + if (value && value->type().id == VecData::Type().id) { assert(dynamic_cast(value.get()) != nullptr); m_input = std::static_pointer_cast(value); diff --git a/src/ShaderNode/DataModels/CompOp.hpp b/src/ShaderNode/DataModels/CompOp.hpp new file mode 100644 index 000000000..134fe87ca --- /dev/null +++ b/src/ShaderNode/DataModels/CompOp.hpp @@ -0,0 +1,220 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_COMPOP_HPP +#define NAZARA_SHADERNODES_COMPOP_HPP + +#include +#include +#include +#include + +template +class CompOp : public ShaderNode +{ + public: + CompOp(ShaderGraph& graph); + ~CompOp() = default; + + Nz::ShaderAst::NodePtr BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const override; + + virtual QString GetOperationString() const = 0; + + unsigned int nPorts(QtNodes::PortType portType) const override; + + QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + std::shared_ptr outData(QtNodes::PortIndex port) override; + + QString portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + bool portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + void setInData(std::shared_ptr value, int index) override; + + QtNodes::NodeValidationState validationState() const override; + QString validationMessage() const override; + + private: + virtual void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) = 0; + + bool ComputePreview(QPixmap& pixmap) override; + void UpdateOutput(); + + std::shared_ptr m_output; + std::shared_ptr m_lhs; + std::shared_ptr m_rhs; +}; + + +template +class CompEq : public CompOp +{ + public: + using CompOp::CompOp; + + void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) override; + QString GetOperationString() const final; +}; + +template +class CompGe : public CompOp +{ + public: + using CompOp::CompOp; + + void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) override; + QString GetOperationString() const final; +}; + +template +class CompGt : public CompOp +{ + public: + using CompOp::CompOp; + + void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) override; + QString GetOperationString() const final; +}; + +template +class CompLe : public CompOp +{ + public: + using CompOp::CompOp; + + void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) override; + QString GetOperationString() const final; +}; + +template +class CompLt : public CompOp +{ + public: + using CompOp::CompOp; + + void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) override; + QString GetOperationString() const final; +}; + +template +class CompNe : public CompOp +{ + public: + using CompOp::CompOp; + + void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) override; + QString GetOperationString() const final; +}; + + +class FloatEq : public CompEq +{ + public: + using CompEq::CompEq; + + QString caption() const override { return "Float equality"; } + QString name() const override { return "float_eq"; } +}; + +class FloatGe : public CompGe +{ + public: + using CompGe::CompGe; + + QString caption() const override { return "Float greater than or equal"; } + QString name() const override { return "float_ge"; } +}; + +class FloatGt : public CompGt +{ + public: + using CompGt::CompGt; + + QString caption() const override { return "Float greater than"; } + QString name() const override { return "float_gt"; } +}; + +class FloatLe : public CompLe +{ + public: + using CompLe::CompLe; + + QString caption() const override { return "Float less than or equal"; } + QString name() const override { return "float_le"; } +}; + +class FloatLt : public CompLt +{ + public: + using CompLt::CompLt; + + QString caption() const override { return "Float less than"; } + QString name() const override { return "float_lt"; } +}; + +class FloatNe : public CompNe +{ + public: + using CompNe::CompNe; + + QString caption() const override { return "Float inequality"; } + QString name() const override { return "float_ne"; } +}; + + +class VecEq : public CompEq +{ + public: + using CompEq::CompEq; + + QString caption() const override { return "Vector equality"; } + QString name() const override { return "vec_eq"; } +}; + +class VecGe : public CompGe +{ + public: + using CompGe::CompGe; + + QString caption() const override { return "Vector greater than or equal"; } + QString name() const override { return "vec_ge"; } +}; + +class VecGt : public CompGt +{ + public: + using CompGt::CompGt; + + QString caption() const override { return "Vector greater than"; } + QString name() const override { return "vec_gt"; } +}; + +class VecLe : public CompLe +{ + public: + using CompLe::CompLe; + + QString caption() const override { return "Vector less than or equal"; } + QString name() const override { return "vec_le"; } +}; + +class VecLt : public CompLt +{ + public: + using CompLt::CompLt; + + QString caption() const override { return "Vector less than"; } + QString name() const override { return "vec_lt"; } +}; + +class VecNe : public CompNe +{ + public: + using CompNe::CompNe; + + QString caption() const override { return "Vector inequality"; } + QString name() const override { return "vec_ne"; } +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/CompOp.inl b/src/ShaderNode/DataModels/CompOp.inl new file mode 100644 index 000000000..ba4b55ad8 --- /dev/null +++ b/src/ShaderNode/DataModels/CompOp.inl @@ -0,0 +1,291 @@ +#include +#include + +template +CompOp::CompOp(ShaderGraph& graph) : +ShaderNode(graph) +{ + UpdateOutput(); +} + +template +Nz::ShaderAst::NodePtr CompOp::BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const +{ + assert(count == 2); + assert(outputIndex == 0); + + return Nz::ShaderBuilder::Binary(Op, std::move(expressions[0]), std::move(expressions[1])); +} + +template +QtNodes::NodeDataType CompOp::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + switch (portType) + { + case QtNodes::PortType::In: + { + assert(portIndex == 0 || portIndex == 1); + return DataType::Type(); + } + + case QtNodes::PortType::Out: + { + assert(portIndex == 0); + return BoolData::Type(); + } + + default: break; + } + + assert(false); + throw std::runtime_error("invalid port type"); +} + +template +unsigned int CompOp::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 2; + case QtNodes::PortType::Out: return 1; + default: break; + } + + assert(false); + throw std::runtime_error("invalid port type"); +} + +template +std::shared_ptr CompOp::outData(QtNodes::PortIndex port) +{ + assert(port == 0); + return m_output; +} + +template +QString CompOp::portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + switch (portType) + { + case QtNodes::PortType::In: + { + switch (portIndex) + { + case 0: + return "A"; + + case 1: + return "B"; + + default: + break; + } + } + + case QtNodes::PortType::Out: + { + assert(portIndex == 0); + return "A " + GetOperationString() + " B"; + } + + default: + break; + } + + return QString{}; +} + +template +bool CompOp::portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + assert(portIndex == 0 || portIndex == 1); + return portType == QtNodes::PortType::In || portType == QtNodes::PortType::Out; +} + +template +void CompOp::setInData(std::shared_ptr value, int index) +{ + assert(index == 0 || index == 1); + + std::shared_ptr castedValue; + if (value && value->type().id == DataType::Type().id) + castedValue = std::static_pointer_cast(value); + + if (index == 0) + m_lhs = std::move(castedValue); + else + m_rhs = std::move(castedValue); + + UpdateOutput(); +} + +template +QtNodes::NodeValidationState CompOp::validationState() const +{ + if (!m_lhs || !m_rhs) + return QtNodes::NodeValidationState::Error; + + if constexpr (std::is_same_v) + { + if (m_lhs->componentCount != m_rhs->componentCount) + return QtNodes::NodeValidationState::Error; + } + + return QtNodes::NodeValidationState::Valid; +} + +template +QString CompOp::validationMessage() const +{ + if (!m_lhs || !m_rhs) + return "Missing operands"; + + if constexpr (std::is_same_v) + { + if (m_lhs->componentCount != m_rhs->componentCount) + return "Incompatible components count (left has " + QString::number(m_lhs->componentCount) + ", right has " + QString::number(m_rhs->componentCount) + ")"; + } + + return QString(); +} + +template +bool CompOp::ComputePreview(QPixmap& pixmap) +{ + if (!m_lhs || !m_rhs) + return false; + + pixmap = QPixmap::fromImage(m_output->preview.GenerateImage()); + return true; +} + +template +void CompOp::UpdateOutput() +{ + if (validationState() != QtNodes::NodeValidationState::Valid) + { + m_output = std::make_shared(); + m_output->preview = PreviewValues(1, 1); + m_output->preview.Fill(Nz::Vector4f::Zero()); + return; + } + + m_output = std::make_shared(); + + const PreviewValues& leftPreview = m_lhs->preview; + const PreviewValues& rightPreview = m_rhs->preview; + std::size_t maxWidth = std::max(leftPreview.GetWidth(), rightPreview.GetWidth()); + std::size_t maxHeight = std::max(leftPreview.GetHeight(), rightPreview.GetHeight()); + + // FIXME: Prevent useless copy + PreviewValues leftResized = leftPreview; + if (leftResized.GetWidth() != maxWidth || leftResized.GetHeight() != maxHeight) + leftResized = leftResized.Resized(maxWidth, maxHeight); + + PreviewValues rightResized = rightPreview; + if (rightResized.GetWidth() != maxWidth || rightResized.GetHeight() != maxHeight) + rightResized = rightResized.Resized(maxWidth, maxHeight); + + m_output->preview = PreviewValues(maxWidth, maxHeight); + ApplyOp(leftResized.GetData(), rightResized.GetData(), m_output->preview.GetData(), maxWidth * maxHeight); + + Q_EMIT dataUpdated(0); + + UpdatePreview(); +} + +template +void CompEq::ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) +{ + for (std::size_t i = 0; i < pixelCount; ++i) + { + float r = (left[i] == right[i]) ? 1.f : 0.f; + output[i] = Nz::Vector4f(r, r, r, r); + } +} + +template +QString CompEq::GetOperationString() const +{ + return "=="; +} + +template +void CompGe::ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) +{ + for (std::size_t i = 0; i < pixelCount; ++i) + { + float r = (left[i] >= right[i]) ? 1.f : 0.f; + output[i] = Nz::Vector4f(r, r, r, r); + } +} + +template +QString CompGe::GetOperationString() const +{ + return ">="; +} + +template +void CompGt::ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) +{ + for (std::size_t i = 0; i < pixelCount; ++i) + { + float r = (left[i] > right[i]) ? 1.f : 0.f; + output[i] = Nz::Vector4f(r, r, r, r); + } +} + +template +QString CompGt::GetOperationString() const +{ + return ">"; +} + +template +void CompLe::ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) +{ + for (std::size_t i = 0; i < pixelCount; ++i) + { + float r = (left[i] >= right[i]) ? 1.f : 0.f; + output[i] = Nz::Vector4f(r, r, r, r); + } +} + +template +QString CompLe::GetOperationString() const +{ + return "<="; +} + +template +void CompLt::ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) +{ + for (std::size_t i = 0; i < pixelCount; ++i) + { + float r = (left[i] > right[i]) ? 1.f : 0.f; + output[i] = Nz::Vector4f(r, r, r, r); + } +} + +template +QString CompLt::GetOperationString() const +{ + return "<"; +} + +template +void CompNe::ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) +{ + for (std::size_t i = 0; i < pixelCount; ++i) + { + float r = (left[i] != right[i]) ? 1.f : 0.f; + output[i] = Nz::Vector4f(r, r, r, r); + } +} + +template +QString CompNe::GetOperationString() const +{ + return "!="; +} diff --git a/src/ShaderNode/DataModels/ConditionalExpression.cpp b/src/ShaderNode/DataModels/ConditionalExpression.cpp new file mode 100644 index 000000000..e73aeb79c --- /dev/null +++ b/src/ShaderNode/DataModels/ConditionalExpression.cpp @@ -0,0 +1,277 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +ConditionalExpression::ConditionalExpression(ShaderGraph& graph) : +ShaderNode(graph) +{ + m_onConditionListUpdateSlot.Connect(GetGraph().OnConditionListUpdate, [&](ShaderGraph*) { OnConditionListUpdate(); }); + m_onConditionUpdateSlot.Connect(GetGraph().OnConditionUpdate, [&](ShaderGraph*, std::size_t conditionIndex) + { + if (m_currentConditionIndex == conditionIndex) + { + UpdatePreview(); + Q_EMIT dataUpdated(0); + } + }); + + if (graph.GetConditionCount() > 0) + { + m_currentConditionIndex = 0; + UpdateConditionText(); + } + + EnablePreview(); + SetPreviewSize({ 128, 128 }); + UpdatePreview(); +} + +Nz::ShaderAst::NodePtr ConditionalExpression::BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const +{ + assert(count == 2); + assert(outputIndex == 0); + + if (!m_currentConditionIndex) + throw std::runtime_error("no condition"); + + const ShaderGraph& graph = GetGraph(); + + const auto& conditionEntry = graph.GetCondition(*m_currentConditionIndex); + return Nz::ShaderBuilder::SelectOption(conditionEntry.name, std::move(expressions[0]), std::move(expressions[1])); +} + +QString ConditionalExpression::caption() const +{ + return "ConditionalExpression (" + QString::fromStdString(m_currentConditionText) + ")"; +} + +QString ConditionalExpression::name() const +{ + return "ConditionalExpression"; +} + +unsigned int ConditionalExpression::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 2; + case QtNodes::PortType::Out: return 1; + } + + return 0; +} + +void ConditionalExpression::BuildNodeEdition(QFormLayout* layout) +{ + ShaderNode::BuildNodeEdition(layout); + + QComboBox* conditionSelection = new QComboBox; + for (const auto& conditionEntry : GetGraph().GetConditions()) + conditionSelection->addItem(QString::fromStdString(conditionEntry.name)); + + if (m_currentConditionIndex) + conditionSelection->setCurrentIndex(int(*m_currentConditionIndex)); + else + conditionSelection->setCurrentIndex(-1); + + connect(conditionSelection, qOverload(&QComboBox::currentIndexChanged), [&](int index) + { + if (index >= 0) + m_currentConditionIndex = static_cast(index); + else + m_currentConditionIndex.reset(); + + UpdateConditionText(); + UpdatePreview(); + + Q_EMIT dataUpdated(0); + }); + + layout->addRow(tr("Condition"), conditionSelection); +} + +auto ConditionalExpression::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType +{ + switch (portType) + { + case QtNodes::PortType::In: + { + switch (portIndex) + { + case 0: + { + if (!m_truePath && !m_falsePath) + return VecData::Type(); + + return (m_truePath) ? m_truePath->type() : m_falsePath->type(); + } + + case 1: + { + if (!m_truePath && !m_falsePath) + return VecData::Type(); + + return (m_falsePath) ? m_falsePath->type() : m_truePath->type(); + } + + default: + break; + } + } + + case QtNodes::PortType::Out: + { + assert(portIndex == 0); + + if (!m_truePath && !m_falsePath) + return VecData::Type(); + + return (m_truePath) ? m_truePath->type() : m_falsePath->type(); + } + + default: + break; + } + + return VecData::Type(); +} + +QString ConditionalExpression::portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + switch (portType) + { + case QtNodes::PortType::In: + { + switch (portIndex) + { + case 0: + return "True expression"; + + case 1: + return "False expression"; + + default: + break; + } + } + + default: + break; + } + + return QString{}; +} + +bool ConditionalExpression::portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex /*portIndex*/) const +{ + return portType == QtNodes::PortType::In; +} + +std::shared_ptr ConditionalExpression::outData(QtNodes::PortIndex port) +{ + if (!m_currentConditionIndex) + return nullptr; + + assert(port == 0); + return (GetGraph().IsConditionEnabled(*m_currentConditionIndex)) ? m_truePath : m_falsePath; +} + +void ConditionalExpression::restore(const QJsonObject& data) +{ + m_currentConditionText = data["condition_name"].toString().toStdString(); + OnConditionListUpdate(); + + ShaderNode::restore(data); +} + +QJsonObject ConditionalExpression::save() const +{ + QJsonObject data = ShaderNode::save(); + data["condition_name"] = QString::fromStdString(m_currentConditionText); + + return data; +} + +void ConditionalExpression::setInData(std::shared_ptr value, int index) +{ + assert(index == 0 || index == 1); + + if (index == 0) + m_truePath = std::move(value); + else + m_falsePath = std::move(value); + + UpdatePreview(); +} + +QtNodes::NodeValidationState ConditionalExpression::validationState() const +{ + if (!m_truePath || !m_falsePath) + return QtNodes::NodeValidationState::Error; + + return QtNodes::NodeValidationState::Valid; +} + +QString ConditionalExpression::validationMessage() const +{ + if (!m_currentConditionIndex) + return "Invalid condition"; + + if (!m_truePath || !m_falsePath) + return "Missing input"; + + return QString(); +} + +bool ConditionalExpression::ComputePreview(QPixmap& pixmap) +{ + if (!m_currentConditionIndex) + return false; + + auto input = outData(0); + if (!input || input->type().id != VecData::Type().id) + return false; + + assert(dynamic_cast(input.get()) != nullptr); + const VecData& data = static_cast(*input); + + pixmap = QPixmap::fromImage(data.preview.GenerateImage()); + return true; +} + +void ConditionalExpression::OnConditionListUpdate() +{ + m_currentConditionIndex.reset(); + + std::size_t conditionIndex = 0; + for (const auto& conditionEntry : GetGraph().GetConditions()) + { + if (conditionEntry.name == m_currentConditionText) + { + m_currentConditionIndex = conditionIndex; + break; + } + + conditionIndex++; + } +} + +void ConditionalExpression::UpdateConditionText() +{ + if (m_currentConditionIndex) + { + auto& condition = GetGraph().GetCondition(*m_currentConditionIndex); + m_currentConditionText = condition.name; + } + else + m_currentConditionText.clear(); +} diff --git a/src/ShaderNode/DataModels/ConditionalExpression.hpp b/src/ShaderNode/DataModels/ConditionalExpression.hpp new file mode 100644 index 000000000..a2bd1eb3a --- /dev/null +++ b/src/ShaderNode/DataModels/ConditionalExpression.hpp @@ -0,0 +1,57 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_CONDITIONALEXPRESSION_HPP +#define NAZARA_SHADERNODES_CONDITIONALEXPRESSION_HPP + +#include +#include +#include +#include +#include + +class ConditionalExpression : public ShaderNode +{ + public: + ConditionalExpression(ShaderGraph& graph); + ~ConditionalExpression() = default; + + Nz::ShaderAst::NodePtr BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const override; + void BuildNodeEdition(QFormLayout* layout) override; + + QString caption() const override; + QString name() const override; + + unsigned int nPorts(QtNodes::PortType portType) const override; + + QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + QString portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + bool portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + std::shared_ptr outData(QtNodes::PortIndex port) override; + + void restore(const QJsonObject& data) override; + QJsonObject save() const override; + + void setInData(std::shared_ptr value, int index) override; + + QtNodes::NodeValidationState validationState() const override; + QString validationMessage() const override; + + private: + bool ComputePreview(QPixmap& pixmap) override; + void OnConditionListUpdate(); + void UpdateConditionText(); + + NazaraSlot(ShaderGraph, OnConditionListUpdate, m_onConditionListUpdateSlot); + NazaraSlot(ShaderGraph, OnConditionUpdate, m_onConditionUpdateSlot); + + std::optional m_currentConditionIndex; + std::shared_ptr m_falsePath; + std::shared_ptr m_truePath; + std::string m_currentConditionText; +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/ConditionalExpression.inl b/src/ShaderNode/DataModels/ConditionalExpression.inl new file mode 100644 index 000000000..67cd1a5e7 --- /dev/null +++ b/src/ShaderNode/DataModels/ConditionalExpression.inl @@ -0,0 +1,2 @@ +#include +#include diff --git a/src/ShaderNode/DataModels/Discard.cpp b/src/ShaderNode/DataModels/Discard.cpp new file mode 100644 index 000000000..aa3035155 --- /dev/null +++ b/src/ShaderNode/DataModels/Discard.cpp @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +Discard::Discard(ShaderGraph& graph) : +ShaderNode(graph) +{ + DisablePreview(); + DisableCustomVariableName(); +} + +Nz::ShaderAst::NodePtr Discard::BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const +{ + assert(count == 1); + assert(outputIndex == 0); + + using namespace Nz; + + auto condition = ShaderBuilder::Binary(ShaderAst::BinaryType::CompEq, std::move(expressions[0]), ShaderBuilder::Constant(true)); + return ShaderBuilder::Branch(std::move(condition), ShaderBuilder::Discard()); +} + +int Discard::GetOutputOrder() const +{ + return std::numeric_limits::lowest(); +} + +QtNodes::NodeDataType Discard::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + assert(portType == QtNodes::PortType::In); + assert(portIndex == 0); + + return BoolData::Type(); +} + +unsigned int Discard::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 1; + case QtNodes::PortType::Out: return 0; + } + + return 0; +} + +std::shared_ptr Discard::outData(QtNodes::PortIndex port) +{ + return {}; +} diff --git a/src/ShaderNode/DataModels/Discard.hpp b/src/ShaderNode/DataModels/Discard.hpp new file mode 100644 index 000000000..91f88edea --- /dev/null +++ b/src/ShaderNode/DataModels/Discard.hpp @@ -0,0 +1,32 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_DISCARD_HPP +#define NAZARA_SHADERNODES_DISCARD_HPP + +#include +#include +#include + +class QFormLayout; + +class Discard : public ShaderNode +{ + public: + Discard(ShaderGraph& graph); + + Nz::ShaderAst::NodePtr BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const override; + int GetOutputOrder() const; + + QString caption() const override { return "Discard"; } + QString name() const override { return "Discard"; } + + QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + unsigned int nPorts(QtNodes::PortType portType) const override; + + std::shared_ptr outData(QtNodes::PortIndex port) override; +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/Discard.inl b/src/ShaderNode/DataModels/Discard.inl new file mode 100644 index 000000000..61b5ba0de --- /dev/null +++ b/src/ShaderNode/DataModels/Discard.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/DataModels/FloatValue.cpp b/src/ShaderNode/DataModels/FloatValue.cpp index 23a4c766f..49513baa6 100644 --- a/src/ShaderNode/DataModels/FloatValue.cpp +++ b/src/ShaderNode/DataModels/FloatValue.cpp @@ -36,9 +36,13 @@ unsigned int FloatValue::nPorts(QtNodes::PortType portType) const { case QtNodes::PortType::In: return 0; case QtNodes::PortType::Out: return 1; + + default: + break; } - return 0; + assert(false); + throw std::runtime_error("Invalid port type"); } std::shared_ptr FloatValue::outData(QtNodes::PortIndex port) @@ -51,6 +55,20 @@ std::shared_ptr FloatValue::outData(QtNodes::PortIndex port) return out; } +QString FloatValue::portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + assert(portIndex == 0); + assert(portType == QtNodes::PortType::Out); + + return QString::number(m_value); +} + +bool FloatValue::portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + assert(portIndex == 0); + return portType == QtNodes::PortType::Out; +} + void FloatValue::BuildNodeEdition(QFormLayout* layout) { ShaderNode::BuildNodeEdition(layout); @@ -71,9 +89,10 @@ void FloatValue::BuildNodeEdition(QFormLayout* layout) layout->addRow(tr("Value"), spinbox); } -Nz::ShaderNodes::ExpressionPtr FloatValue::GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const +Nz::ShaderAst::NodePtr FloatValue::BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const { assert(count == 0); + assert(outputIndex == 0); return Nz::ShaderBuilder::Constant(m_value); } diff --git a/src/ShaderNode/DataModels/FloatValue.hpp b/src/ShaderNode/DataModels/FloatValue.hpp index fe77e5464..722ee44ca 100644 --- a/src/ShaderNode/DataModels/FloatValue.hpp +++ b/src/ShaderNode/DataModels/FloatValue.hpp @@ -17,6 +17,9 @@ class FloatValue : public ShaderNode FloatValue(ShaderGraph& graph); ~FloatValue() = default; + Nz::ShaderAst::NodePtr BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const override; + void BuildNodeEdition(QFormLayout* layout) override; + QString caption() const override; QString name() const override; @@ -26,9 +29,8 @@ class FloatValue : public ShaderNode std::shared_ptr outData(QtNodes::PortIndex port) override; - void BuildNodeEdition(QFormLayout* layout) override; - - Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const override; + QString portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + bool portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; private: bool ComputePreview(QPixmap& pixmap) override; diff --git a/src/ShaderNode/DataModels/InputValue.cpp b/src/ShaderNode/DataModels/InputValue.cpp index e4710e6f5..51dc4953b 100644 --- a/src/ShaderNode/DataModels/InputValue.cpp +++ b/src/ShaderNode/DataModels/InputValue.cpp @@ -109,15 +109,16 @@ void InputValue::BuildNodeEdition(QFormLayout* layout) layout->addRow(tr("Input"), inputSelection); } -Nz::ShaderNodes::ExpressionPtr InputValue::GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const +Nz::ShaderAst::NodePtr InputValue::BuildNode(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count, std::size_t outputIndex) const { assert(count == 0); + assert(outputIndex == 0); if (!m_currentInputIndex) throw std::runtime_error("no input"); const auto& inputEntry = GetGraph().GetInput(*m_currentInputIndex); - return Nz::ShaderBuilder::Identifier(Nz::ShaderBuilder::Input(inputEntry.name, ShaderGraph::ToShaderExpressionType(inputEntry.type))); + return Nz::ShaderBuilder::AccessMember(Nz::ShaderBuilder::Identifier("input"), { inputEntry.name }); } auto InputValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType @@ -184,6 +185,35 @@ std::shared_ptr InputValue::outData(QtNodes::PortIndex port) throw std::runtime_error("Unhandled input type"); } +QString InputValue::portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + assert(portIndex == 0); + assert(portType == QtNodes::PortType::Out); + + if (!m_currentInputIndex) + return QString(); + + const auto& inputEntry = GetGraph().GetInput(*m_currentInputIndex); + return QString::fromStdString(inputEntry.name); +} + +bool InputValue::portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + assert(portIndex == 0); + + switch (portType) + { + case QtNodes::PortType::In: return false; + case QtNodes::PortType::Out: return m_currentInputIndex.has_value(); + + default: + break; + } + + assert(false); + throw std::runtime_error("Invalid port type"); +} + QtNodes::NodeValidationState InputValue::validationState() const { if (!m_currentInputIndex) diff --git a/src/ShaderNode/DataModels/InputValue.hpp b/src/ShaderNode/DataModels/InputValue.hpp index d0e1593b9..63cbf197c 100644 --- a/src/ShaderNode/DataModels/InputValue.hpp +++ b/src/ShaderNode/DataModels/InputValue.hpp @@ -19,7 +19,7 @@ class InputValue : public ShaderNode void BuildNodeEdition(QFormLayout* layout) override; - Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const override; + Nz::ShaderAst::NodePtr BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const override; QString caption() const override { return "Input"; } QString name() const override { return "Input"; } @@ -30,6 +30,9 @@ class InputValue : public ShaderNode std::shared_ptr outData(QtNodes::PortIndex port) override; + QString portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + bool portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + QtNodes::NodeValidationState validationState() const override; QString validationMessage() const override; diff --git a/src/ShaderNode/DataModels/Mat4BinOp.hpp b/src/ShaderNode/DataModels/Mat4BinOp.hpp index c90549bdd..e752b21a4 100644 --- a/src/ShaderNode/DataModels/Mat4BinOp.hpp +++ b/src/ShaderNode/DataModels/Mat4BinOp.hpp @@ -6,14 +6,14 @@ #include #include -template +template class Mat4BinOp : public ShaderNode { public: Mat4BinOp(ShaderGraph& graph); ~Mat4BinOp() = default; - Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const override; + Nz::ShaderAst::NodePtr BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const; unsigned int nPorts(QtNodes::PortType portType) const override; @@ -35,28 +35,28 @@ class Mat4BinOp : public ShaderNode std::shared_ptr m_output; }; -class Mat4Add : public Mat4BinOp +class Mat4Add : public Mat4BinOp { public: - using Mat4BinOp::Mat4BinOp; + using Mat4BinOp::Mat4BinOp; QString caption() const override; QString name() const override; }; -class Mat4Mul : public Mat4BinOp +class Mat4Mul : public Mat4BinOp { public: - using Mat4BinOp::Mat4BinOp; + using Mat4BinOp::Mat4BinOp; QString caption() const override; QString name() const override; }; -class Mat4Sub : public Mat4BinOp +class Mat4Sub : public Mat4BinOp { public: - using Mat4BinOp::Mat4BinOp; + using Mat4BinOp::Mat4BinOp; QString caption() const override; QString name() const override; diff --git a/src/ShaderNode/DataModels/Mat4BinOp.inl b/src/ShaderNode/DataModels/Mat4BinOp.inl index 05cdb0479..894328be9 100644 --- a/src/ShaderNode/DataModels/Mat4BinOp.inl +++ b/src/ShaderNode/DataModels/Mat4BinOp.inl @@ -1,59 +1,60 @@ #include #include -template -Mat4BinOp::Mat4BinOp(ShaderGraph& graph) : +template +Mat4BinOp::Mat4BinOp(ShaderGraph& graph) : ShaderNode(graph) { UpdateOutput(); } -template -Nz::ShaderNodes::ExpressionPtr Mat4BinOp::GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const +template +Nz::ShaderAst::NodePtr Mat4BinOp::BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const { assert(count == 2); - using BuilderType = typename Nz::ShaderBuilder::template BinOpBuilder; - constexpr BuilderType builder; - return builder(expressions[0], expressions[1]); + assert(outputIndex == 0); + + return Nz::ShaderBuilder::Binary(Op, std::move(expressions[0]), std::move(expressions[1])); } -template -QtNodes::NodeDataType Mat4BinOp::dataType(QtNodes::PortType /*portType*/, QtNodes::PortIndex portIndex) const +template +QtNodes::NodeDataType Mat4BinOp::dataType(QtNodes::PortType /*portType*/, QtNodes::PortIndex portIndex) const { assert(portIndex == 0 || portIndex == 1); return Matrix4Data::Type(); } -template -unsigned int Mat4BinOp::nPorts(QtNodes::PortType portType) const +template +unsigned int Mat4BinOp::nPorts(QtNodes::PortType portType) const { switch (portType) { case QtNodes::PortType::In: return 2; case QtNodes::PortType::Out: return 1; + default: break; } - return 0; + assert(false); + throw std::runtime_error("invalid port type"); } -template -std::shared_ptr Mat4BinOp::outData(QtNodes::PortIndex port) +template +std::shared_ptr Mat4BinOp::outData(QtNodes::PortIndex port) { assert(port == 0); return m_output; } -template -void Mat4BinOp::setInData(std::shared_ptr value, int index) +template +void Mat4BinOp::setInData(std::shared_ptr value, int index) { assert(index == 0 || index == 1); std::shared_ptr castedValue; - if (value) + if (value && value->type().id == Matrix4Data::Type().id) { assert(dynamic_cast(value.get()) != nullptr); - castedValue = std::static_pointer_cast(value); } @@ -65,8 +66,8 @@ void Mat4BinOp::setInData(std::shared_ptr value, int i UpdateOutput(); } -template -QtNodes::NodeValidationState Mat4BinOp::validationState() const +template +QtNodes::NodeValidationState Mat4BinOp::validationState() const { if (!m_lhs || !m_rhs) return QtNodes::NodeValidationState::Error; @@ -74,8 +75,8 @@ QtNodes::NodeValidationState Mat4BinOp::validationState() const return QtNodes::NodeValidationState::Valid; } -template -QString Mat4BinOp::validationMessage() const +template +QString Mat4BinOp::validationMessage() const { if (!m_lhs || !m_rhs) return "Missing operands"; @@ -83,8 +84,8 @@ QString Mat4BinOp::validationMessage() const return QString(); } -template -bool Mat4BinOp::ComputePreview(QPixmap& pixmap) +template +bool Mat4BinOp::ComputePreview(QPixmap& pixmap) { if (!m_lhs || !m_rhs) return false; @@ -95,8 +96,8 @@ bool Mat4BinOp::ComputePreview(QPixmap& pixmap) //return true; } -template -void Mat4BinOp::UpdateOutput() +template +void Mat4BinOp::UpdateOutput() { if (validationState() != QtNodes::NodeValidationState::Valid) { diff --git a/src/ShaderNode/DataModels/Mat4VecMul.cpp b/src/ShaderNode/DataModels/Mat4VecMul.cpp index 983545973..0e723584d 100644 --- a/src/ShaderNode/DataModels/Mat4VecMul.cpp +++ b/src/ShaderNode/DataModels/Mat4VecMul.cpp @@ -1,5 +1,6 @@ #include -#include +#include +#include Mat4VecMul::Mat4VecMul(ShaderGraph& graph) : ShaderNode(graph) @@ -7,11 +8,12 @@ ShaderNode(graph) UpdateOutput(); } -Nz::ShaderNodes::ExpressionPtr Mat4VecMul::GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const +Nz::ShaderAst::NodePtr Mat4VecMul::BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const { assert(count == 2); - using namespace Nz::ShaderNodes; - return BinaryOp::Build(BinaryType::Multiply, expressions[0], expressions[1]); + assert(outputIndex == 0); + + return Nz::ShaderBuilder::Binary(Nz::ShaderAst::BinaryType::Multiply, std::move(expressions[0]), std::move(expressions[1])); } QString Mat4VecMul::caption() const @@ -77,7 +79,7 @@ void Mat4VecMul::setInData(std::shared_ptr value, int index) { case 0: { - if (value) + if (value && value->type().id == Matrix4Data::Type().id) { assert(dynamic_cast(value.get()) != nullptr); m_lhs = std::static_pointer_cast(value); @@ -90,7 +92,7 @@ void Mat4VecMul::setInData(std::shared_ptr value, int index) case 1: { - if (value) + if (value && value->type().id == VecData::Type().id) { assert(dynamic_cast(value.get()) != nullptr); m_rhs = std::static_pointer_cast(value); diff --git a/src/ShaderNode/DataModels/Mat4VecMul.hpp b/src/ShaderNode/DataModels/Mat4VecMul.hpp index 608439fcb..76debc88f 100644 --- a/src/ShaderNode/DataModels/Mat4VecMul.hpp +++ b/src/ShaderNode/DataModels/Mat4VecMul.hpp @@ -13,7 +13,7 @@ class Mat4VecMul : public ShaderNode Mat4VecMul(ShaderGraph& graph); ~Mat4VecMul() = default; - Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const override; + Nz::ShaderAst::NodePtr BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const override; QString caption() const override; QString name() const override; diff --git a/src/ShaderNode/DataModels/OutputValue.cpp b/src/ShaderNode/DataModels/OutputValue.cpp index 63a481588..e3471fff8 100644 --- a/src/ShaderNode/DataModels/OutputValue.cpp +++ b/src/ShaderNode/DataModels/OutputValue.cpp @@ -54,20 +54,24 @@ void OutputValue::BuildNodeEdition(QFormLayout* layout) layout->addRow(tr("Output"), outputSelection); } -Nz::ShaderNodes::ExpressionPtr OutputValue::GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const +Nz::ShaderAst::NodePtr OutputValue::BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const { - using namespace Nz::ShaderBuilder; - using namespace Nz::ShaderNodes; - assert(count == 1); + assert(outputIndex == 0); if (!m_currentOutputIndex) throw std::runtime_error("no output"); const auto& outputEntry = GetGraph().GetOutput(*m_currentOutputIndex); - auto output = Nz::ShaderBuilder::Identifier(Nz::ShaderBuilder::Output(outputEntry.name, ShaderGraph::ToShaderExpressionType(outputEntry.type))); + auto output = Nz::ShaderBuilder::AccessMember(Nz::ShaderBuilder::Identifier("output"), { outputEntry.name }); - return Nz::ShaderBuilder::Assign(std::move(output), *expressions); + using namespace Nz; + return Nz::ShaderBuilder::Assign(ShaderAst::AssignType::Simple, std::move(output), std::move(expressions[0])); +} + +std::shared_ptr OutputValue::outData(QtNodes::PortIndex /*port*/) +{ + return {}; } QtNodes::NodeDataType OutputValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const @@ -88,14 +92,40 @@ unsigned int OutputValue::nPorts(QtNodes::PortType portType) const { case QtNodes::PortType::In: return 1; case QtNodes::PortType::Out: return 0; + default: break; } - return 0; + assert(false); + throw std::runtime_error("invalid port type"); } -std::shared_ptr OutputValue::outData(QtNodes::PortIndex /*port*/) +QString OutputValue::portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { - return {}; + assert(portType == QtNodes::PortType::In); + assert(portIndex == 0); + + if (!m_currentOutputIndex) + return QString(); + + const auto& outputEntry = GetGraph().GetOutput(*m_currentOutputIndex); + return QString::fromStdString(outputEntry.name); +} + +bool OutputValue::portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + assert(portIndex == 0); + + switch (portType) + { + case QtNodes::PortType::In: return m_currentOutputIndex.has_value(); + case QtNodes::PortType::Out: return false; + + default: + break; + } + + assert(false); + throw std::runtime_error("Invalid port type"); } void OutputValue::setInData(std::shared_ptr value, int index) @@ -126,6 +156,9 @@ QtNodes::NodeValidationState OutputValue::validationState() const case PrimitiveType::Float3: case PrimitiveType::Float4: { + if (m_input->type().id != VecData::Type().id) + return QtNodes::NodeValidationState::Error; + assert(dynamic_cast(m_input.get()) != nullptr); const VecData& vec = static_cast(*m_input); if (GetComponentCount(outputEntry.type) != vec.componentCount) @@ -156,6 +189,9 @@ QString OutputValue::validationMessage() const case PrimitiveType::Float3: case PrimitiveType::Float4: { + if (m_input->type().id != VecData::Type().id) + return "Expected vector"; + assert(dynamic_cast(m_input.get()) != nullptr); const VecData& vec = static_cast(*m_input); @@ -179,6 +215,9 @@ bool OutputValue::ComputePreview(QPixmap& pixmap) { case PrimitiveType::Bool: { + if (m_input->type().id != BoolData::Type().id) + return false; + assert(dynamic_cast(m_input.get()) != nullptr); const BoolData& data = static_cast(*m_input); @@ -188,6 +227,9 @@ bool OutputValue::ComputePreview(QPixmap& pixmap) case PrimitiveType::Float1: { + if (m_input->type().id != FloatData::Type().id) + return false; + assert(dynamic_cast(m_input.get()) != nullptr); const FloatData& data = static_cast(*m_input); @@ -208,6 +250,9 @@ bool OutputValue::ComputePreview(QPixmap& pixmap) case PrimitiveType::Float3: case PrimitiveType::Float4: { + if (m_input->type().id != VecData::Type().id) + return false; + assert(dynamic_cast(m_input.get()) != nullptr); const VecData& data = static_cast(*m_input); @@ -223,16 +268,16 @@ void OutputValue::OnOutputListUpdate() { m_currentOutputIndex.reset(); - std::size_t inputIndex = 0; - for (const auto& inputEntry : GetGraph().GetOutputs()) + std::size_t outputIndex = 0; + for (const auto& outputEntry : GetGraph().GetOutputs()) { - if (inputEntry.name == m_currentOutputText) + if (outputEntry.name == m_currentOutputText) { - m_currentOutputIndex = inputIndex; + m_currentOutputIndex = outputIndex; break; } - inputIndex++; + outputIndex++; } } diff --git a/src/ShaderNode/DataModels/OutputValue.hpp b/src/ShaderNode/DataModels/OutputValue.hpp index 12c812c5c..a44284e1a 100644 --- a/src/ShaderNode/DataModels/OutputValue.hpp +++ b/src/ShaderNode/DataModels/OutputValue.hpp @@ -16,7 +16,7 @@ class OutputValue : public ShaderNode void BuildNodeEdition(QFormLayout* layout) override; - Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const override; + Nz::ShaderAst::NodePtr BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const override; QString caption() const override { return "Output"; } QString name() const override { return "Output"; } @@ -27,6 +27,9 @@ class OutputValue : public ShaderNode std::shared_ptr outData(QtNodes::PortIndex port) override; + QString portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + bool portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + void setInData(std::shared_ptr value, int index) override; QtNodes::NodeValidationState validationState() const override; diff --git a/src/ShaderNode/DataModels/PositionOutputValue.cpp b/src/ShaderNode/DataModels/PositionOutputValue.cpp index c3d252f54..dd82ac2b2 100644 --- a/src/ShaderNode/DataModels/PositionOutputValue.cpp +++ b/src/ShaderNode/DataModels/PositionOutputValue.cpp @@ -14,15 +14,15 @@ ShaderNode(graph) DisableCustomVariableName(); } -Nz::ShaderNodes::ExpressionPtr PositionOutputValue::GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const +Nz::ShaderAst::NodePtr PositionOutputValue::BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const { - using namespace Nz::ShaderBuilder; - using namespace Nz::ShaderNodes; + using namespace Nz; assert(count == 1); + assert(outputIndex == 0); - auto output = Nz::ShaderBuilder::Identifier(Nz::ShaderBuilder::Builtin(BuiltinEntry::VertexPosition)); - return Nz::ShaderBuilder::Assign(std::move(output), *expressions); + auto output = Nz::ShaderBuilder::AccessMember(Nz::ShaderBuilder::Identifier("output"), { "position" }); + return ShaderBuilder::Assign(ShaderAst::AssignType::Simple, std::move(output), std::move(expressions[0])); } QtNodes::NodeDataType PositionOutputValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const @@ -52,7 +52,7 @@ std::shared_ptr PositionOutputValue::outData(QtNodes::PortInd void PositionOutputValue::setInData(std::shared_ptr value, int index) { assert(index == 0); - if (value) + if (value && value->type().id == VecData::Type().id) { assert(dynamic_cast(value.get()) != nullptr); m_input = std::static_pointer_cast(value); diff --git a/src/ShaderNode/DataModels/PositionOutputValue.hpp b/src/ShaderNode/DataModels/PositionOutputValue.hpp index 2c2b6eb54..1cb8ed8ef 100644 --- a/src/ShaderNode/DataModels/PositionOutputValue.hpp +++ b/src/ShaderNode/DataModels/PositionOutputValue.hpp @@ -14,7 +14,7 @@ class PositionOutputValue : public ShaderNode public: PositionOutputValue(ShaderGraph& graph); - Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const override; + Nz::ShaderAst::NodePtr BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const override; QString caption() const override { return "PositionOutputValue"; } QString name() const override { return "PositionOutputValue"; } diff --git a/src/ShaderNode/DataModels/SampleTexture.cpp b/src/ShaderNode/DataModels/SampleTexture.cpp index c784b83af..7a697f7a7 100644 --- a/src/ShaderNode/DataModels/SampleTexture.cpp +++ b/src/ShaderNode/DataModels/SampleTexture.cpp @@ -71,13 +71,18 @@ bool SampleTexture::ComputePreview(QPixmap& pixmap) return true; } -Nz::ShaderNodes::ExpressionPtr SampleTexture::GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const +Nz::ShaderAst::NodePtr SampleTexture::BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const { assert(m_texture); assert(m_uv); assert(count == 2); + assert(outputIndex == 0); - return Nz::ShaderBuilder::Sample2D(expressions[0], expressions[1]); + std::vector params; + params.push_back(std::move(expressions[0])); + params.push_back(std::move(expressions[1])); + + return Nz::ShaderBuilder::Intrinsic(Nz::ShaderAst::IntrinsicType::SampleTexture, std::move(params)); } auto SampleTexture::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType @@ -154,10 +159,9 @@ void SampleTexture::setInData(std::shared_ptr value, int inde { case 0: { - if (value) + if (value && value->type().id == Texture2Data::Type().id) { assert(dynamic_cast(value.get()) != nullptr); - m_texture = std::static_pointer_cast(value); } else @@ -168,10 +172,9 @@ void SampleTexture::setInData(std::shared_ptr value, int inde case 1: { - if (value) + if (value && value->type().id == VecData::Type().id) { assert(dynamic_cast(value.get()) != nullptr); - m_uv = std::static_pointer_cast(value); } else diff --git a/src/ShaderNode/DataModels/SampleTexture.hpp b/src/ShaderNode/DataModels/SampleTexture.hpp index 5b1dd98fd..d09c71521 100644 --- a/src/ShaderNode/DataModels/SampleTexture.hpp +++ b/src/ShaderNode/DataModels/SampleTexture.hpp @@ -17,7 +17,7 @@ class SampleTexture : public ShaderNode SampleTexture(ShaderGraph& graph); ~SampleTexture() = default; - Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const override; + Nz::ShaderAst::NodePtr BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const override; QString caption() const override { return "Sample texture"; } QString name() const override { return "SampleTexture"; } diff --git a/src/ShaderNode/DataModels/ShaderNode.cpp b/src/ShaderNode/DataModels/ShaderNode.cpp index 7ed3bc84c..abda9cd6b 100644 --- a/src/ShaderNode/DataModels/ShaderNode.cpp +++ b/src/ShaderNode/DataModels/ShaderNode.cpp @@ -8,6 +8,7 @@ ShaderNode::ShaderNode(ShaderGraph& graph) : m_previewSize(64, 64), m_pixmapLabel(nullptr), +m_embeddedWidget(nullptr), m_graph(graph), m_enableCustomVariableName(true), m_isPreviewEnabled(false) @@ -84,9 +85,31 @@ void ShaderNode::EnablePreview(bool enable) } } +int ShaderNode::GetOutputOrder() const +{ + return 0; +} + QWidget* ShaderNode::embeddedWidget() { - return m_pixmapLabel; + if (!m_embeddedWidget) + { + QWidget* embedded = EmbeddedWidget(); + if (embedded) + { + QVBoxLayout* layout = new QVBoxLayout; + layout->addWidget(embedded); + layout->addWidget(m_pixmapLabel); + + m_embeddedWidget = new QWidget; + m_embeddedWidget->setStyleSheet("background-color: rgba(0,0,0,0)"); + m_embeddedWidget->setLayout(layout); + } + else + m_embeddedWidget = m_pixmapLabel; + } + + return m_embeddedWidget; } void ShaderNode::restore(const QJsonObject& data) @@ -121,6 +144,11 @@ bool ShaderNode::ComputePreview(QPixmap& /*pixmap*/) return false; } +QWidget* ShaderNode::EmbeddedWidget() +{ + return nullptr; +} + void ShaderNode::UpdatePreview() { if (!m_pixmap) diff --git a/src/ShaderNode/DataModels/ShaderNode.hpp b/src/ShaderNode/DataModels/ShaderNode.hpp index 6d3dd5cc1..c0aa8afcf 100644 --- a/src/ShaderNode/DataModels/ShaderNode.hpp +++ b/src/ShaderNode/DataModels/ShaderNode.hpp @@ -4,7 +4,7 @@ #define NAZARA_SHADERNODES_SHADERNODE_HPP #include -#include +#include #include #include #include @@ -18,14 +18,15 @@ class ShaderNode : public QtNodes::NodeDataModel public: ShaderNode(ShaderGraph& graph); + virtual Nz::ShaderAst::NodePtr BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const = 0; virtual void BuildNodeEdition(QFormLayout* layout); inline void DisablePreview(); void EnablePreview(bool enable = true); - virtual Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const = 0; inline ShaderGraph& GetGraph(); inline const ShaderGraph& GetGraph() const; + virtual int GetOutputOrder() const; inline const std::string& GetVariableName() const; inline void SetPreviewSize(const Nz::Vector2i& size); @@ -41,6 +42,7 @@ class ShaderNode : public QtNodes::NodeDataModel protected: inline void DisableCustomVariableName(); inline void EnableCustomVariableName(bool enable = true); + virtual QWidget* EmbeddedWidget(); void UpdatePreview(); private: @@ -48,6 +50,7 @@ class ShaderNode : public QtNodes::NodeDataModel Nz::Vector2i m_previewSize; QLabel* m_pixmapLabel; + QWidget* m_embeddedWidget; std::optional m_pixmap; std::string m_variableName; ShaderGraph& m_graph; diff --git a/src/ShaderNode/DataModels/TextureValue.cpp b/src/ShaderNode/DataModels/TextureValue.cpp index c400d0469..0be18dd88 100644 --- a/src/ShaderNode/DataModels/TextureValue.cpp +++ b/src/ShaderNode/DataModels/TextureValue.cpp @@ -110,27 +110,16 @@ void TextureValue::BuildNodeEdition(QFormLayout* layout) layout->addRow(tr("Texture"), textureSelection); } -Nz::ShaderNodes::ExpressionPtr TextureValue::GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const +Nz::ShaderAst::NodePtr TextureValue::BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const { if (!m_currentTextureIndex) throw std::runtime_error("invalid texture input"); assert(count == 0); + assert(outputIndex == 0); const auto& textureEntry = GetGraph().GetTexture(*m_currentTextureIndex); - - Nz::ShaderNodes::BasicType expression = [&] - { - switch (textureEntry.type) - { - case TextureType::Sampler2D: return Nz::ShaderNodes::BasicType::Sampler2D; - } - - assert(false); - throw std::runtime_error("Unhandled texture type"); - }(); - - return Nz::ShaderBuilder::Identifier(Nz::ShaderBuilder::Uniform(textureEntry.name, expression)); + return Nz::ShaderBuilder::Identifier(textureEntry.name); } auto TextureValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType @@ -178,6 +167,32 @@ std::shared_ptr TextureValue::outData(QtNodes::PortIndex port return textureData; } +QString TextureValue::portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + assert(portType == QtNodes::PortType::Out); + + if (!m_currentTextureIndex) + return QString(); + + const auto& textureEntry = GetGraph().GetTexture(*m_currentTextureIndex); + return QString::fromStdString(textureEntry.name); +} + +bool TextureValue::portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + switch (portType) + { + case QtNodes::PortType::In: return false; + case QtNodes::PortType::Out: return m_currentTextureIndex.has_value(); + + default: + break; + } + + assert(false); + throw std::runtime_error("Invalid port type"); +} + QtNodes::NodeValidationState TextureValue::validationState() const { if (!m_currentTextureIndex) diff --git a/src/ShaderNode/DataModels/TextureValue.hpp b/src/ShaderNode/DataModels/TextureValue.hpp index d328e2f05..5de2a556d 100644 --- a/src/ShaderNode/DataModels/TextureValue.hpp +++ b/src/ShaderNode/DataModels/TextureValue.hpp @@ -18,7 +18,7 @@ class TextureValue : public ShaderNode void BuildNodeEdition(QFormLayout* layout) override; - Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const override; + Nz::ShaderAst::NodePtr BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const override; QString caption() const override { return "Texture"; } QString name() const override { return "Texture"; } @@ -29,6 +29,9 @@ class TextureValue : public ShaderNode std::shared_ptr outData(QtNodes::PortIndex port) override; + QString portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + bool portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + QtNodes::NodeValidationState validationState() const override; QString validationMessage() const override; diff --git a/src/ShaderNode/DataModels/VecBinOp.cpp b/src/ShaderNode/DataModels/VecBinOp.cpp deleted file mode 100644 index f99591420..000000000 --- a/src/ShaderNode/DataModels/VecBinOp.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include - -QString VecAdd::caption() const -{ - static QString caption = "Vector addition"; - return caption; -} - -QString VecAdd::name() const -{ - static QString name = "vec_add"; - return name; -} - -void VecAdd::ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) -{ - for (std::size_t i = 0; i < pixelCount; ++i) - output[i] = left[i] + right[i]; -} - -QString VecMul::caption() const -{ - static QString caption = "Vector multiplication"; - return caption; -} - -QString VecMul::name() const -{ - static QString name = "vec_mul"; - return name; -} - -void VecMul::ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) -{ - for (std::size_t i = 0; i < pixelCount; ++i) - output[i] = left[i] * right[i]; -} - -QString VecSub::caption() const -{ - static QString caption = "Vector subtraction"; - return caption; -} - - -QString VecSub::name() const -{ - static QString name = "vec_sub"; - return name; -} - -void VecSub::ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) -{ - for (std::size_t i = 0; i < pixelCount; ++i) - output[i] = left[i] - right[i]; -} - -QString VecDiv::caption() const -{ - static QString caption = "Vector divide"; - return caption; -} - - -QString VecDiv::name() const -{ - static QString name = "vec_div"; - return name; -} - -void VecDiv::ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) -{ - for (std::size_t i = 0; i < pixelCount; ++i) - output[i] = left[i] / right[i]; -} diff --git a/src/ShaderNode/DataModels/VecBinOp.hpp b/src/ShaderNode/DataModels/VecBinOp.hpp deleted file mode 100644 index 3c0a5aebd..000000000 --- a/src/ShaderNode/DataModels/VecBinOp.hpp +++ /dev/null @@ -1,86 +0,0 @@ -#pragma once - -#ifndef NAZARA_SHADERNODES_VECBINOP_HPP -#define NAZARA_SHADERNODES_VECBINOP_HPP - -#include -#include - -template -class VecBinOp : public ShaderNode -{ - public: - VecBinOp(ShaderGraph& graph); - ~VecBinOp() = default; - - Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const override; - - unsigned int nPorts(QtNodes::PortType portType) const override; - - QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; - - std::shared_ptr outData(QtNodes::PortIndex port) override; - - void setInData(std::shared_ptr value, int index) override; - - QtNodes::NodeValidationState validationState() const override; - QString validationMessage() const override; - - private: - virtual void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) = 0; - - bool ComputePreview(QPixmap& pixmap) override; - void UpdateOutput(); - - std::shared_ptr m_lhs; - std::shared_ptr m_rhs; - std::shared_ptr m_output; -}; - -class VecAdd : public VecBinOp -{ - public: - using VecBinOp::VecBinOp; - - QString caption() const override; - QString name() const override; - - void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) override; -}; - -class VecMul : public VecBinOp -{ - public: - using VecBinOp::VecBinOp; - - QString caption() const override; - QString name() const override; - - void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) override; -}; - -class VecSub : public VecBinOp -{ - public: - using VecBinOp::VecBinOp; - - QString caption() const override; - QString name() const override; - - void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) override; -}; - -class VecDiv : public VecBinOp -{ - public: - using VecBinOp::VecBinOp; - - QString caption() const override; - QString name() const override; - - void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) override; -}; - -#include - -#endif diff --git a/src/ShaderNode/DataModels/VecBinOp.inl b/src/ShaderNode/DataModels/VecBinOp.inl deleted file mode 100644 index d16347799..000000000 --- a/src/ShaderNode/DataModels/VecBinOp.inl +++ /dev/null @@ -1,135 +0,0 @@ -#include -#include - -template -VecBinOp::VecBinOp(ShaderGraph& graph) : -ShaderNode(graph) -{ - UpdateOutput(); -} - -template -Nz::ShaderNodes::ExpressionPtr VecBinOp::GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const -{ - assert(count == 2); - using BuilderType = typename Nz::ShaderBuilder::template BinOpBuilder; - constexpr BuilderType builder; - return builder(expressions[0], expressions[1]); -} - -template -QtNodes::NodeDataType VecBinOp::dataType(QtNodes::PortType /*portType*/, QtNodes::PortIndex portIndex) const -{ - assert(portIndex == 0 || portIndex == 1); - - return VecData::Type(); -} - -template -unsigned int VecBinOp::nPorts(QtNodes::PortType portType) const -{ - switch (portType) - { - case QtNodes::PortType::In: return 2; - case QtNodes::PortType::Out: return 1; - } - - return 0; -} - -template -std::shared_ptr VecBinOp::outData(QtNodes::PortIndex port) -{ - assert(port == 0); - return m_output; -} - -template -void VecBinOp::setInData(std::shared_ptr value, int index) -{ - assert(index == 0 || index == 1); - - std::shared_ptr castedValue; - if (value) - { - assert(dynamic_cast(value.get()) != nullptr); - - castedValue = std::static_pointer_cast(value); - } - - if (index == 0) - m_lhs = std::move(castedValue); - else - m_rhs = std::move(castedValue); - - UpdateOutput(); -} - -template -QtNodes::NodeValidationState VecBinOp::validationState() const -{ - if (!m_lhs || !m_rhs) - return QtNodes::NodeValidationState::Error; - - if (m_lhs->componentCount != m_rhs->componentCount) - return QtNodes::NodeValidationState::Error; - - return QtNodes::NodeValidationState::Valid; -} - -template -QString VecBinOp::validationMessage() const -{ - if (!m_lhs || !m_rhs) - return "Missing operands"; - - if (m_lhs->componentCount != m_rhs->componentCount) - return "Incompatible components count (left has " + QString::number(m_lhs->componentCount) + ", right has " + QString::number(m_rhs->componentCount) + ")"; - - return QString(); -} - -template -bool VecBinOp::ComputePreview(QPixmap& pixmap) -{ - if (!m_lhs || !m_rhs) - return false; - - pixmap = QPixmap::fromImage(m_output->preview.GenerateImage()); - return true; -} - -template -void VecBinOp::UpdateOutput() -{ - if (validationState() != QtNodes::NodeValidationState::Valid) - { - m_output = std::make_shared(4); - m_output->preview = PreviewValues(1, 1); - m_output->preview.Fill(Nz::Vector4f::Zero()); - return; - } - - m_output = std::make_shared(m_lhs->componentCount); - - const PreviewValues& leftPreview = m_lhs->preview; - const PreviewValues& rightPreview = m_rhs->preview; - std::size_t maxWidth = std::max(leftPreview.GetWidth(), rightPreview.GetWidth()); - std::size_t maxHeight = std::max(leftPreview.GetHeight(), rightPreview.GetHeight()); - - // FIXME: Prevent useless copy - PreviewValues leftResized = leftPreview; - if (leftResized.GetWidth() != maxWidth || leftResized.GetHeight() != maxHeight) - leftResized = leftResized.Resized(maxWidth, maxHeight); - - PreviewValues rightResized = rightPreview; - if (rightResized.GetWidth() != maxWidth || rightResized.GetHeight() != maxHeight) - rightResized = rightResized.Resized(maxWidth, maxHeight); - - m_output->preview = PreviewValues(maxWidth, maxHeight); - ApplyOp(leftResized.GetData(), rightResized.GetData(), m_output->preview.GetData(), maxWidth * maxHeight); - - Q_EMIT dataUpdated(0); - - UpdatePreview(); -} diff --git a/src/ShaderNode/DataModels/VecComposition.hpp b/src/ShaderNode/DataModels/VecComposition.hpp new file mode 100644 index 000000000..d6dfca579 --- /dev/null +++ b/src/ShaderNode/DataModels/VecComposition.hpp @@ -0,0 +1,49 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_VECTOR_COMPOSITION_HPP +#define NAZARA_SHADERNODES_VECTOR_COMPOSITION_HPP + +#include +#include +#include +#include +#include +#include + +template +class VecComposition : public ShaderNode +{ + public: + VecComposition(ShaderGraph& graph); + ~VecComposition() = default; + + Nz::ShaderAst::NodePtr BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const override; + + QString caption() const override; + QString name() const override; + + QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + unsigned int nPorts(QtNodes::PortType portType) const override; + + std::shared_ptr outData(QtNodes::PortIndex port) override; + + void setInData(std::shared_ptr value, int index) override; + + QtNodes::NodeValidationState validationState() const override; + QString validationMessage() const override; + + private: + bool ComputePreview(QPixmap& pixmap) override; + void UpdateOutput(); + + std::array, ComponentCount> m_inputs; + std::shared_ptr m_output; +}; + +using Vec2Composition = VecComposition<2>; +using Vec3Composition = VecComposition<3>; +using Vec4Composition = VecComposition<4>; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/VecComposition.inl b/src/ShaderNode/DataModels/VecComposition.inl new file mode 100644 index 000000000..70e8c15a6 --- /dev/null +++ b/src/ShaderNode/DataModels/VecComposition.inl @@ -0,0 +1,191 @@ +#include +#include +#include +#include +#include + +template +VecComposition::VecComposition(ShaderGraph& graph) : +ShaderNode(graph) +{ + static_assert(ComponentCount <= s_vectorComponents.size()); + + m_output = std::make_shared(ComponentCount); +} + +template +Nz::ShaderAst::NodePtr VecComposition::BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const +{ + assert(count == ComponentCount); + assert(outputIndex == 0); + + std::vector params; + for (std::size_t i = 0; i < count; ++i) + params.emplace_back(std::move(expressions[i])); + + return Nz::ShaderBuilder::Cast(Nz::ShaderAst::VectorType{ ComponentCount, Nz::ShaderAst::PrimitiveType::Float32 }, std::move(params)); +} + +template +QString VecComposition::caption() const +{ + static QString caption = "Compose Vector" + QString::number(ComponentCount); + return caption; +} + +template +QString VecComposition::name() const +{ + static QString name = "vec_compose" + QString::number(ComponentCount); + return name; +} + +template +QtNodes::NodeDataType VecComposition::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + switch (portType) + { + case QtNodes::PortType::In: + { + assert(portIndex >= 0); + assert(portIndex < ComponentCount); + return FloatData::Type(); + } + + case QtNodes::PortType::Out: + { + assert(portIndex == 0); + return VecData::Type(); + } + + default: break; + } + + assert(false); + throw std::runtime_error("Invalid port type"); +} + +template +unsigned int VecComposition::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return ComponentCount; + case QtNodes::PortType::Out: return 1; + + default: break; + } + + assert(false); + throw std::runtime_error("Invalid port type"); +} + +template +std::shared_ptr VecComposition::outData(QtNodes::PortIndex port) +{ + assert(port == 0); + + if (validationState() != QtNodes::NodeValidationState::Valid) + return nullptr; + + return m_output; +} + +template +void VecComposition::setInData(std::shared_ptr value, int index) +{ + assert(index >= 0 && index < ComponentCount); + + if (value && value->type().id == FloatData::Type().id) + { + assert(dynamic_cast(value.get()) != nullptr); + m_inputs[index] = std::static_pointer_cast(value); + } + else + m_inputs[index].reset(); + + UpdateOutput(); +} + +template +QtNodes::NodeValidationState VecComposition::validationState() const +{ + for (std::size_t i = 0; i < ComponentCount; ++i) + { + if (!m_inputs[i]) + return QtNodes::NodeValidationState::Error; + } + + return QtNodes::NodeValidationState::Valid; +} + +template +QString VecComposition::validationMessage() const +{ + for (std::size_t i = 0; i < ComponentCount; ++i) + { + if (!m_inputs[i]) + return "Missing input #" + QString::number(i + 1); + } + + return QString(); +} + +template +bool VecComposition::ComputePreview(QPixmap& pixmap) +{ + if (validationState() != QtNodes::NodeValidationState::Valid) + return false; + + pixmap = QPixmap::fromImage(m_output->preview.GenerateImage()); + return true; +} + +template +void VecComposition::UpdateOutput() +{ + if (validationState() != QtNodes::NodeValidationState::Valid) + { + m_output->preview = PreviewValues(1, 1); + m_output->preview(0, 0) = Nz::Vector4f::Zero(); + return; + } + + std::array previewResized; + std::size_t maxInputWidth = 0; + std::size_t maxInputHeight = 0; + + for (std::size_t i = 0; i < ComponentCount; ++i) + { + // FIXME: Prevent useless copy + previewResized[i] = m_inputs[i]->preview; + + maxInputWidth = std::max(maxInputWidth, previewResized[i].GetWidth()); + maxInputHeight = std::max(maxInputHeight, previewResized[i].GetHeight()); + } + + PreviewValues& output = m_output->preview; + output = PreviewValues(maxInputWidth, maxInputHeight); + + for (std::size_t i = 0; i < ComponentCount; ++i) + { + if (previewResized[i].GetWidth() != maxInputWidth || previewResized[i].GetHeight() != maxInputHeight) + previewResized[i] = previewResized[i].Resized(maxInputWidth, maxInputHeight); + } + + for (std::size_t y = 0; y < maxInputHeight; ++y) + { + for (std::size_t x = 0; x < maxInputWidth; ++x) + { + Nz::Vector4f color(0.f, 0.f, 0.f, 1.f); + for (std::size_t i = 0; i < ComponentCount; ++i) + color[i] = previewResized[i](x, y)[0]; + + output(x, y) = color; + } + } + + Q_EMIT dataUpdated(0); + + UpdatePreview(); +} diff --git a/src/ShaderNode/DataModels/VecDecomposition.cpp b/src/ShaderNode/DataModels/VecDecomposition.cpp new file mode 100644 index 000000000..f36fcea50 --- /dev/null +++ b/src/ShaderNode/DataModels/VecDecomposition.cpp @@ -0,0 +1,176 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +VecDecomposition::VecDecomposition(ShaderGraph& graph) : +ShaderNode(graph) +{ + DisablePreview(); + DisableCustomVariableName(); +} + +Nz::ShaderAst::NodePtr VecDecomposition::BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const +{ + assert(count == 1); + assert(outputIndex < m_outputs.size()); + + using namespace Nz; + + ShaderAst::SwizzleComponent swizzleComponent = static_cast(Nz::UnderlyingCast(ShaderAst::SwizzleComponent::First) + outputIndex); + return ShaderBuilder::Swizzle(std::move(expressions[0]), { swizzleComponent }); +} + +QString VecDecomposition::caption() const +{ + return "Vector decomposition"; +} + +QString VecDecomposition::name() const +{ + return "vec_decompose"; +} + +QtNodes::NodeDataType VecDecomposition::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + switch (portType) + { + case QtNodes::PortType::In: + { + assert(portIndex == 0); + return VecData::Type(); + } + + case QtNodes::PortType::Out: + { + assert(portIndex >= 0 && portIndex < m_outputs.size()); + return FloatData::Type(); + } + + default: + break; + } + + assert(false); + throw std::runtime_error("Invalid port type"); +} + +unsigned int VecDecomposition::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 1; + case QtNodes::PortType::Out: return m_outputs.size(); + + default: + break; + } + + assert(false); + throw std::runtime_error("Invalid port type"); +} + +QString VecDecomposition::portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + assert(portType == QtNodes::PortType::Out); + assert(portIndex >= 0 && portIndex < s_vectorComponents.size()); + + return QString(QChar(s_vectorComponents[portIndex])); +} + +bool VecDecomposition::portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + switch (portType) + { + case QtNodes::PortType::In: return false; + case QtNodes::PortType::Out: return true; + + default: + break; + } + + assert(false); + throw std::runtime_error("Invalid port type"); +} + +std::shared_ptr VecDecomposition::outData(QtNodes::PortIndex port) +{ + if (!m_input) + return {}; + + return m_outputs[port]; +} + +void VecDecomposition::setInData(std::shared_ptr value, int index) +{ + assert(index == 0); + + std::shared_ptr castedValue; + if (value && value->type().id == VecData::Type().id) + castedValue = std::static_pointer_cast(value); + + m_input = std::move(castedValue); + + UpdateOutputs(); +} + +QtNodes::NodeValidationState VecDecomposition::validationState() const +{ + if (!m_input) + return QtNodes::NodeValidationState::Error; + + return QtNodes::NodeValidationState::Valid; +} + +QString VecDecomposition::validationMessage() const +{ + if (!m_input) + return "Missing input"; + + return QString(); +} + +void VecDecomposition::UpdateOutputs() +{ + if (validationState() != QtNodes::NodeValidationState::Valid) + { + auto dummy = std::make_shared(); + dummy->preview = PreviewValues(1, 1); + dummy->preview.Fill(Nz::Vector4f::Zero()); + + m_outputs.fill(dummy); + return; + } + + std::size_t previewWidth = m_input->preview.GetWidth(); + std::size_t previewHeight = m_input->preview.GetHeight(); + std::size_t pixelCount = previewWidth * previewHeight; + + for (std::size_t i = 0; i < m_input->componentCount; ++i) + { + m_outputs[i] = std::make_shared(); + m_outputs[i]->preview = PreviewValues(previewWidth, previewHeight); + + const Nz::Vector4f* inputData = m_input->preview.GetData(); + Nz::Vector4f* outputData = m_outputs[i]->preview.GetData(); + for (std::size_t j = 0; j < pixelCount; ++j) + { + const Nz::Vector4f& input = *inputData++; + + *outputData++ = Nz::Vector4f(input[i], input[i], input[i], input[i]); + } + + Q_EMIT dataUpdated(i); + } + + for (std::size_t i = m_input->componentCount; i < m_outputs.size(); ++i) + m_outputs[i] = nullptr; + + UpdatePreview(); +} diff --git a/src/ShaderNode/DataModels/VecDecomposition.hpp b/src/ShaderNode/DataModels/VecDecomposition.hpp new file mode 100644 index 000000000..a66326fbf --- /dev/null +++ b/src/ShaderNode/DataModels/VecDecomposition.hpp @@ -0,0 +1,48 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_VECTOR_DECOMPOSITION_HPP +#define NAZARA_SHADERNODES_VECTOR_DECOMPOSITION_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +class VecDecomposition : public ShaderNode +{ + public: + VecDecomposition(ShaderGraph& graph); + ~VecDecomposition() = default; + + Nz::ShaderAst::NodePtr BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const override; + + QString caption() const override; + QString name() const override; + + QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + unsigned int nPorts(QtNodes::PortType portType) const override; + + QString portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + bool portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + std::shared_ptr outData(QtNodes::PortIndex port) override; + + void setInData(std::shared_ptr value, int index) override; + + QtNodes::NodeValidationState validationState() const override; + QString validationMessage() const override; + + private: + void UpdateOutputs(); + + std::shared_ptr m_input; + std::array, 4> m_outputs; +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/Cast.cpp b/src/ShaderNode/DataModels/VecDecomposition.inl similarity index 100% rename from src/ShaderNode/DataModels/Cast.cpp rename to src/ShaderNode/DataModels/VecDecomposition.inl diff --git a/src/ShaderNode/DataModels/VecDot.cpp b/src/ShaderNode/DataModels/VecDot.cpp index b083623d0..21849ec03 100644 --- a/src/ShaderNode/DataModels/VecDot.cpp +++ b/src/ShaderNode/DataModels/VecDot.cpp @@ -1,5 +1,6 @@ #include -#include +#include +#include VecDot::VecDot(ShaderGraph& graph) : ShaderNode(graph) @@ -8,11 +9,16 @@ ShaderNode(graph) UpdateOutput(); } -Nz::ShaderNodes::ExpressionPtr VecDot::GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const +Nz::ShaderAst::NodePtr VecDot::BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const { assert(count == 2); - using namespace Nz::ShaderNodes; - return IntrinsicCall::Build(IntrinsicType::DotProduct, { expressions[0], expressions[1] }); + assert(outputIndex == 0); + + std::vector params; + params.push_back(std::move(expressions[0])); + params.push_back(std::move(expressions[1])); + + return Nz::ShaderBuilder::Intrinsic(Nz::ShaderAst::IntrinsicType::DotProduct, std::move(params)); } QString VecDot::caption() const @@ -71,10 +77,9 @@ void VecDot::setInData(std::shared_ptr value, int index) assert(index == 0 || index == 1); std::shared_ptr castedValue; - if (value) + if (value && value->type().id == VecData::Type().id) { assert(dynamic_cast(value.get()) != nullptr); - castedValue = std::static_pointer_cast(value); } diff --git a/src/ShaderNode/DataModels/VecDot.hpp b/src/ShaderNode/DataModels/VecDot.hpp index 74e6a7266..194037bc6 100644 --- a/src/ShaderNode/DataModels/VecDot.hpp +++ b/src/ShaderNode/DataModels/VecDot.hpp @@ -13,7 +13,7 @@ class VecDot : public ShaderNode VecDot(ShaderGraph& graph); ~VecDot() = default; - Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const override; + Nz::ShaderAst::NodePtr BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const override; QString caption() const override; QString name() const override; diff --git a/src/ShaderNode/DataModels/VecFloatMul.cpp b/src/ShaderNode/DataModels/VecFloatMul.cpp index 9dd3b02c3..9ddcb8bc0 100644 --- a/src/ShaderNode/DataModels/VecFloatMul.cpp +++ b/src/ShaderNode/DataModels/VecFloatMul.cpp @@ -1,5 +1,6 @@ #include -#include +#include +#include VecFloatMul::VecFloatMul(ShaderGraph& graph) : ShaderNode(graph) @@ -7,11 +8,12 @@ ShaderNode(graph) UpdateOutput(); } -Nz::ShaderNodes::ExpressionPtr VecFloatMul::GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const +Nz::ShaderAst::NodePtr VecFloatMul::BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const { assert(count == 2); - using namespace Nz::ShaderNodes; - return BinaryOp::Build(BinaryType::Multiply, expressions[0], expressions[1]); + assert(outputIndex == 0); + + return Nz::ShaderBuilder::Binary(Nz::ShaderAst::BinaryType::Multiply, std::move(expressions[0]), std::move(expressions[1])); } QString VecFloatMul::caption() const @@ -77,10 +79,9 @@ void VecFloatMul::setInData(std::shared_ptr value, int index) { case 0: { - if (value) + if (value && value->type().id == FloatData::Type().id) { assert(dynamic_cast(value.get()) != nullptr); - m_lhs = std::static_pointer_cast(value); } else @@ -91,10 +92,9 @@ void VecFloatMul::setInData(std::shared_ptr value, int index) case 1: { - if (value) + if (value && value->type().id == VecData::Type().id) { assert(dynamic_cast(value.get()) != nullptr); - m_rhs = std::static_pointer_cast(value); } else diff --git a/src/ShaderNode/DataModels/VecFloatMul.hpp b/src/ShaderNode/DataModels/VecFloatMul.hpp index dd1fbd1af..7295d75ce 100644 --- a/src/ShaderNode/DataModels/VecFloatMul.hpp +++ b/src/ShaderNode/DataModels/VecFloatMul.hpp @@ -13,7 +13,7 @@ class VecFloatMul : public ShaderNode VecFloatMul(ShaderGraph& graph); ~VecFloatMul() = default; - Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const override; + Nz::ShaderAst::NodePtr BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const override; QString caption() const override; QString name() const override; diff --git a/src/ShaderNode/DataModels/VecValue.cpp b/src/ShaderNode/DataModels/VecValue.cpp deleted file mode 100644 index ede5bdfac..000000000 --- a/src/ShaderNode/DataModels/VecValue.cpp +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/src/ShaderNode/DataModels/VecValue.hpp b/src/ShaderNode/DataModels/VecValue.hpp index 86cd93692..40035655c 100644 --- a/src/ShaderNode/DataModels/VecValue.hpp +++ b/src/ShaderNode/DataModels/VecValue.hpp @@ -18,6 +18,9 @@ class VecValue : public ShaderNode VecValue(ShaderGraph& graph); ~VecValue() = default; + Nz::ShaderAst::NodePtr BuildNode(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const override; + void BuildNodeEdition(QFormLayout* layout) override; + QString caption() const override; QString name() const override; @@ -27,9 +30,8 @@ class VecValue : public ShaderNode std::shared_ptr outData(QtNodes::PortIndex port) override; - void BuildNodeEdition(QFormLayout* layout) override; - - Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const override; + QString portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + bool portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; private: bool ComputePreview(QPixmap& pixmap) override; diff --git a/src/ShaderNode/DataModels/VecValue.inl b/src/ShaderNode/DataModels/VecValue.inl index b07c46a9b..e65924845 100644 --- a/src/ShaderNode/DataModels/VecValue.inl +++ b/src/ShaderNode/DataModels/VecValue.inl @@ -75,6 +75,33 @@ std::shared_ptr VecValue::outData(QtNodes::Po return out; } +template +QString VecValue::portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + assert(portIndex == 0); + assert(portType == QtNodes::PortType::Out); + + QString caption = "vec" + QString::number(ComponentCount) + "("; + for (std::size_t i = 0; i < ComponentCount; ++i) + { + if (i > 0) + caption += ", "; + + caption += QString::number(m_value[i]); + } + + caption += ")"; + + return caption; +} + +template +bool VecValue::portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + assert(portIndex == 0); + return portType == QtNodes::PortType::Out; +} + template void VecValue::BuildNodeEdition(QFormLayout* layout) { @@ -89,7 +116,7 @@ void VecValue::BuildNodeEdition(QFormLayout* layout) connect(spinbox, qOverload(&QDoubleSpinBox::valueChanged), [=](double) { - m_value[i] = spinbox->value(); + m_value[i] = float(spinbox->value()); Q_EMIT dataUpdated(0); UpdatePreview(); @@ -100,9 +127,10 @@ void VecValue::BuildNodeEdition(QFormLayout* layout) } template -Nz::ShaderNodes::ExpressionPtr VecValue::GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const +Nz::ShaderAst::NodePtr VecValue::BuildNode(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count, std::size_t outputIndex) const { assert(count == 0); + assert(outputIndex == 0); return Nz::ShaderBuilder::Constant(m_value); } diff --git a/src/ShaderNode/DataTypes/Matrix4Data.hpp b/src/ShaderNode/DataTypes/Matrix4Data.hpp index 4eb63f136..bd2e9e978 100644 --- a/src/ShaderNode/DataTypes/Matrix4Data.hpp +++ b/src/ShaderNode/DataTypes/Matrix4Data.hpp @@ -3,7 +3,7 @@ #ifndef NAZARA_SHADERNODES_MATRIXDATA_HPP #define NAZARA_SHADERNODES_MATRIXDATA_HPP -#include +#include #include #include diff --git a/src/ShaderNode/DataTypes/TextureData.hpp b/src/ShaderNode/DataTypes/TextureData.hpp index 28b2b73d0..ab3bba1f2 100644 --- a/src/ShaderNode/DataTypes/TextureData.hpp +++ b/src/ShaderNode/DataTypes/TextureData.hpp @@ -4,7 +4,7 @@ #define NAZARA_SHADERNODES_TEXTUREDATA_HPP #include -#include +#include #include struct TextureData : public QtNodes::NodeData diff --git a/src/ShaderNode/DataTypes/VecData.cpp b/src/ShaderNode/DataTypes/VecData.cpp deleted file mode 100644 index 0402864e0..000000000 --- a/src/ShaderNode/DataTypes/VecData.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include -#include -#include - -Nz::ShaderNodes::BasicType VecData::GetExpressionType() const -{ - switch (componentCount) - { - case 2: return Nz::ShaderNodes::BasicType::Float2; - case 3: return Nz::ShaderNodes::BasicType::Float3; - case 4: return Nz::ShaderNodes::BasicType::Float4; - default: - break; - } - - assert(false); - throw std::runtime_error("invalid component count"); -} diff --git a/src/ShaderNode/DataTypes/VecData.hpp b/src/ShaderNode/DataTypes/VecData.hpp index f6e1bfdd9..1dcd265d5 100644 --- a/src/ShaderNode/DataTypes/VecData.hpp +++ b/src/ShaderNode/DataTypes/VecData.hpp @@ -3,7 +3,7 @@ #ifndef NAZARA_SHADERNODES_VECDATA_HPP #define NAZARA_SHADERNODES_VECDATA_HPP -#include +#include #include #include @@ -13,43 +13,12 @@ struct VecData : public QtNodes::NodeData inline QtNodes::NodeDataType type() const override; - Nz::ShaderNodes::BasicType GetExpressionType() const; - static inline QtNodes::NodeDataType Type(); std::size_t componentCount; PreviewValues preview; }; -template -struct VecExpressionTypeHelper; - -template<> -struct VecExpressionTypeHelper<1> -{ - static constexpr Nz::ShaderNodes::BasicType ExpressionType = Nz::ShaderNodes::BasicType::Float1; -}; - -template<> -struct VecExpressionTypeHelper<2> -{ - static constexpr Nz::ShaderNodes::BasicType ExpressionType = Nz::ShaderNodes::BasicType::Float2; -}; - -template<> -struct VecExpressionTypeHelper<3> -{ - static constexpr Nz::ShaderNodes::BasicType ExpressionType = Nz::ShaderNodes::BasicType::Float3; -}; - -template<> -struct VecExpressionTypeHelper<4> -{ - static constexpr Nz::ShaderNodes::BasicType ExpressionType = Nz::ShaderNodes::BasicType::Float4; -}; - -template constexpr Nz::ShaderNodes::BasicType VecExpressionType = VecExpressionTypeHelper::ExpressionType; - struct VecTypeDummy {}; diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index cc5995d27..ef02bf7a2 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -1,17 +1,26 @@ #include #include +#include +#include +#include +#include +#include #include #include +#include +#include +#include #include #include +#include +#include #include +#include #include #include #include -#include -#include -#include -#include +#include +#include #include #include #include @@ -38,17 +47,24 @@ namespace auto creator = [&] { return std::make_unique(graph); }; registry->registerModel(category, std::move(creator)); } + + template + std::unique_ptr static_unique_pointer_cast(std::unique_ptr&& ptr) + { + return std::unique_ptr(static_cast(ptr.release())); + } } ShaderGraph::ShaderGraph() : -m_flowScene(BuildRegistry()), m_type(ShaderType::NotSet) { + m_flowScene.emplace(BuildRegistry()); + m_previewModel = std::make_unique(); - QObject::connect(&m_flowScene, &QGraphicsScene::selectionChanged, [&] + QObject::connect(&m_flowScene.value(), &QGraphicsScene::selectionChanged, [&] { - auto selectedNodes = m_flowScene.selectedNodes(); + auto selectedNodes = m_flowScene->selectedNodes(); if (selectedNodes.size() == 1) OnSelectedNodeUpdate(this, static_cast(selectedNodes.front()->nodeDataModel())); else @@ -56,58 +72,38 @@ m_type(ShaderType::NotSet) }); // Test + m_type = ShaderType::Fragment; AddInput("UV", PrimitiveType::Float2, InputRole::TexCoord, 0, 0); AddOutput("RenderTarget0", PrimitiveType::Float4, 0); AddTexture("Potato", TextureType::Sampler2D, 1); - AddStruct("TestStruct", { - { - { "position", PrimitiveType::Float3 }, - { "normal", PrimitiveType::Float3 }, - { "uv", PrimitiveType::Float2 }, - { "inner", 2u } - } - }); - AddStruct("InnerStruct", { - { - { "a", PrimitiveType::Float3 }, - } - }); - AddStruct("OuterStruct", { - { - { "a", 1u }, - { "b", PrimitiveType::Float1 } - } - }); - - AddBuffer("testUBO", BufferType::UniformBufferObject, 0, 0); UpdateTexturePreview(0, QImage(R"(C:\Users\Lynix\Pictures\potatavril.png)")); - auto& node1 = m_flowScene.createNode(std::make_unique(*this)); + auto& node1 = m_flowScene->createNode(std::make_unique(*this)); node1.nodeGraphicsObject().setPos(0, 200); - auto& node2 = m_flowScene.createNode(std::make_unique(*this)); + auto& node2 = m_flowScene->createNode(std::make_unique(*this)); node2.nodeGraphicsObject().setPos(50, 350); - auto& node3 = m_flowScene.createNode(std::make_unique(*this)); + auto& node3 = m_flowScene->createNode(std::make_unique(*this)); node3.nodeGraphicsObject().setPos(200, 200); - auto& node4 = m_flowScene.createNode(std::make_unique(*this)); + auto& node4 = m_flowScene->createNode(std::make_unique(*this)); node4.nodeGraphicsObject().setPos(400, 200); - auto& node5 = m_flowScene.createNode(std::make_unique(*this)); + auto& node5 = m_flowScene->createNode(std::make_unique(*this)); node5.nodeGraphicsObject().setPos(600, 300); - m_flowScene.createConnection(node3, 0, node1, 0); - m_flowScene.createConnection(node3, 1, node2, 0); - m_flowScene.createConnection(node4, 0, node3, 0); - m_flowScene.createConnection(node4, 1, node3, 0); - m_flowScene.createConnection(node5, 0, node4, 0); + m_flowScene->createConnection(node3, 0, node1, 0); + m_flowScene->createConnection(node3, 1, node2, 0); + m_flowScene->createConnection(node4, 0, node3, 0); + m_flowScene->createConnection(node4, 1, node3, 0); + m_flowScene->createConnection(node5, 0, node4, 0); } ShaderGraph::~ShaderGraph() { - m_flowScene.clearScene(); + m_flowScene.reset(); } std::size_t ShaderGraph::AddBuffer(std::string name, BufferType bufferType, std::size_t structIndex, std::size_t bindingIndex) @@ -124,6 +120,17 @@ std::size_t ShaderGraph::AddBuffer(std::string name, BufferType bufferType, std: return index; } +std::size_t ShaderGraph::AddCondition(std::string name) +{ + std::size_t index = m_conditions.size(); + auto& conditionEntry = m_conditions.emplace_back(); + conditionEntry.name = std::move(name); + + OnConditionListUpdate(this); + + return index; +} + std::size_t ShaderGraph::AddInput(std::string name, PrimitiveType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex) { std::size_t index = m_inputs.size(); @@ -181,10 +188,11 @@ void ShaderGraph::Clear() { m_type = ShaderType::NotSet; - m_flowScene.clearScene(); - m_flowScene.clear(); + m_flowScene->clearScene(); + m_flowScene->clear(); m_buffers.clear(); + m_conditions.clear(); m_inputs.clear(); m_structs.clear(); m_outputs.clear(); @@ -197,6 +205,15 @@ void ShaderGraph::Clear() OnTextureListUpdate(this); } +void ShaderGraph::EnableCondition(std::size_t conditionIndex, bool enable) +{ + assert(conditionIndex < m_conditions.size()); + auto& conditionEntry = m_conditions[conditionIndex]; + conditionEntry.enabled = enable; + + OnConditionUpdate(this, conditionIndex); +} + void ShaderGraph::Load(const QJsonObject& data) { Clear(); @@ -218,6 +235,17 @@ void ShaderGraph::Load(const QJsonObject& data) OnBufferListUpdate(this); + QJsonArray conditionArray = data["conditions"].toArray(); + for (const auto& conditionDocRef : conditionArray) + { + QJsonObject conditionDoc = conditionDocRef.toObject(); + + ConditionEntry& condition = m_conditions.emplace_back(); + condition.name = conditionDoc["name"].toString().toStdString(); + } + + OnConditionListUpdate(this); + QJsonArray inputArray = data["inputs"].toArray(); for (const auto& inputDocRef : inputArray) { @@ -286,10 +314,10 @@ void ShaderGraph::Load(const QJsonObject& data) OnTextureListUpdate(this); for (QJsonValueRef node : data["nodes"].toArray()) - m_flowScene.restoreNode(node.toObject()); + m_flowScene->restoreNode(node.toObject()); for (QJsonValueRef connection : data["connections"].toArray()) - m_flowScene.restoreConnection(connection.toObject()); + m_flowScene->restoreConnection(connection.toObject()); } QJsonObject ShaderGraph::Save() @@ -312,6 +340,18 @@ QJsonObject ShaderGraph::Save() } sceneJson["buffers"] = bufferArray; + QJsonArray conditionArray; + { + for (const auto& condition : m_conditions) + { + QJsonObject inputDoc; + inputDoc["name"] = QString::fromStdString(condition.name); + + conditionArray.append(inputDoc); + } + } + sceneJson["conditions"] = conditionArray; + QJsonArray inputArray; { for (const auto& input : m_inputs) @@ -391,14 +431,14 @@ QJsonObject ShaderGraph::Save() QJsonArray nodesJsonArray; { - for (auto&& [uuid, node] : m_flowScene.nodes()) + for (auto&& [uuid, node] : m_flowScene->nodes()) nodesJsonArray.append(node->save()); } sceneJson["nodes"] = nodesJsonArray; QJsonArray connectionJsonArray; { - for (auto&& [uuid, connection] : m_flowScene.connections()) + for (auto&& [uuid, connection] : m_flowScene->connections()) { QJsonObject connectionJson = connection->save(); @@ -411,119 +451,109 @@ QJsonObject ShaderGraph::Save() return sceneJson; } -Nz::ShaderNodes::StatementPtr ShaderGraph::ToAst() +Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() const { - std::vector statements; - QHash usageCount; + std::vector statements; - std::function DetectVariables; - DetectVariables = [&](QtNodes::Node* node) + // Declare all options + for (const auto& condition : m_conditions) + statements.push_back(Nz::ShaderBuilder::DeclareOption(condition.name, Nz::ShaderAst::PrimitiveType::Boolean)); + + // Declare all structures + for (const auto& structInfo : m_structs) { - auto it = usageCount.find(node->id()); - if (it == usageCount.end()) - { - for (const auto& connectionSet : node->nodeState().getEntries(QtNodes::PortType::In)) - { - for (const auto& [uuid, conn] : connectionSet) - { - DetectVariables(conn->getNode(QtNodes::PortType::Out)); - } - } + Nz::ShaderAst::StructDescription structDesc; + structDesc.layout = Nz::StructLayout::Std140; + structDesc.name = structInfo.name; - it = usageCount.insert(node->id(), 0); + for (const auto& memberInfo : structInfo.members) + { + auto& structMember = structDesc.members.emplace_back(); + structMember.name = memberInfo.name; + structMember.type = ToShaderExpressionType(memberInfo.type); } - (*it)++; - }; + statements.push_back(Nz::ShaderBuilder::DeclareStruct(std::move(structDesc))); + } - m_flowScene.iterateOverNodes([&](QtNodes::Node* node) + // External block + auto external = std::make_unique(); + + for (const auto& buffer : m_buffers) { - if (node->nodeDataModel()->nPorts(QtNodes::PortType::Out) == 0) - DetectVariables(node); - }); + if (buffer.structIndex >= m_structs.size()) + throw std::runtime_error("buffer " + buffer.name + " references out-of-bounds struct #" + std::to_string(buffer.structIndex)); - QHash variableExpressions; + const auto& structInfo = m_structs[buffer.structIndex]; - unsigned int varCount = 0; - std::unordered_set usedVariableNames; + auto& extVar = external->externalVars.emplace_back(); + extVar.bindingIndex = buffer.bindingIndex; + extVar.name = buffer.name; + extVar.type = Nz::ShaderAst::UniformType{ Nz::ShaderAst::IdentifierType{ structInfo.name } }; + } - std::function HandleNode; - HandleNode = [&](QtNodes::Node* node) -> Nz::ShaderNodes::ExpressionPtr + for (const auto& texture : m_textures) { - ShaderNode* shaderNode = static_cast(node->nodeDataModel()); - if (shaderNode->validationState() != QtNodes::NodeValidationState::Valid) - throw std::runtime_error(shaderNode->validationMessage().toStdString()); + auto& extVar = external->externalVars.emplace_back(); + extVar.bindingIndex = texture.bindingIndex; + extVar.name = texture.name; + extVar.type = ToShaderExpressionType(texture.type); + } - qDebug() << shaderNode->name() << node->id(); - if (auto it = variableExpressions.find(node->id()); it != variableExpressions.end()) - return *it; + if (!external->externalVars.empty()) + statements.push_back(std::move(external)); - auto it = usageCount.find(node->id()); - assert(it != usageCount.end()); + // Inputs / outputs + if (!m_inputs.empty()) + { + Nz::ShaderAst::StructDescription structDesc; + structDesc.name = "InputData"; - std::size_t inputCount = shaderNode->nPorts(QtNodes::PortType::In); - Nz::StackArray expressions = NazaraStackArray(Nz::ShaderNodes::ExpressionPtr, inputCount); - std::size_t i = 0; - - for (const auto& connectionSet : node->nodeState().getEntries(QtNodes::PortType::In)) + for (const auto& input : m_inputs) { - for (const auto& [uuid, conn] : connectionSet) - { - assert(i < expressions.size()); - expressions[i] = HandleNode(conn->getNode(QtNodes::PortType::Out)); - i++; - } + auto& structMember = structDesc.members.emplace_back(); + structMember.name = input.name; + structMember.type = ToShaderExpressionType(input.type); + structMember.locationIndex = input.locationIndex; } - auto expression = shaderNode->GetExpression(expressions.data(), expressions.size()); + statements.push_back(Nz::ShaderBuilder::DeclareStruct(std::move(structDesc))); + } - const std::string& variableName = shaderNode->GetVariableName(); - if (*it > 1 || !variableName.empty()) - { - Nz::ShaderNodes::ExpressionPtr varExpression; - if (expression->GetExpressionCategory() == Nz::ShaderNodes::ExpressionCategory::RValue) - { - std::string name; - if (variableName.empty()) - name = "var" + std::to_string(varCount++); - else - name = variableName; - - if (usedVariableNames.find(name) != usedVariableNames.end()) - throw std::runtime_error("duplicate variable found: " + name); - - usedVariableNames.insert(name); - - auto variable = Nz::ShaderBuilder::Local(std::move(name), expression->GetExpressionType()); - statements.emplace_back(Nz::ShaderBuilder::DeclareVariable(variable, expression)); - - varExpression = Nz::ShaderBuilder::Identifier(variable); - } - else - varExpression = expression; - - variableExpressions.insert(node->id(), varExpression); - - return varExpression; - } - else - return expression; - }; - - m_flowScene.iterateOverNodes([&](QtNodes::Node* node) + Nz::ShaderAst::ExpressionType returnType; + if (!m_outputs.empty()) { - if (node->nodeDataModel()->nPorts(QtNodes::PortType::Out) == 0) - { - statements.emplace_back(Nz::ShaderBuilder::ExprStatement(HandleNode(node))); - } - }); + Nz::ShaderAst::StructDescription structDesc; + structDesc.name = "OutputData"; - return Nz::ShaderNodes::StatementBlock::Build(std::move(statements)); + for (const auto& output : m_outputs) + { + auto& structMember = structDesc.members.emplace_back(); + structMember.name = output.name; + structMember.type = ToShaderExpressionType(output.type); + structMember.locationIndex = output.locationIndex; + } + + if (m_type == ShaderType::Vertex) + { + auto& position = structDesc.members.emplace_back(); + position.builtin = Nz::ShaderAst::BuiltinEntry::VertexPosition; + position.name = "position"; + position.type = Nz::ShaderAst::VectorType{ 4, Nz::ShaderAst::PrimitiveType::Float32 }; + } + + statements.push_back(Nz::ShaderBuilder::DeclareStruct(std::move(structDesc))); + } + + // Functions + statements.push_back(ToFunction()); + + return Nz::ShaderBuilder::MultiStatement(std::move(statements)); } -Nz::ShaderExpressionType ShaderGraph::ToShaderExpressionType(const std::variant& type) const +Nz::ShaderAst::ExpressionType ShaderGraph::ToShaderExpressionType(const std::variant& type) const { - return std::visit([&](auto&& arg) -> Nz::ShaderExpressionType + return std::visit([&](auto&& arg) -> Nz::ShaderAst::ExpressionType { using T = std::decay_t; if constexpr (std::is_same_v) @@ -532,7 +562,7 @@ Nz::ShaderExpressionType ShaderGraph::ToShaderExpressionType(const std::variant< { assert(arg < m_structs.size()); const auto& s = m_structs[arg]; - return s.name; + return Nz::ShaderAst::IdentifierType{ s.name }; } else static_assert(Nz::AlwaysFalse::value, "non-exhaustive visitor"); @@ -551,6 +581,15 @@ void ShaderGraph::UpdateBuffer(std::size_t bufferIndex, std::string name, Buffer OnBufferUpdate(this, bufferIndex); } +void ShaderGraph::UpdateCondition(std::size_t conditionIndex, std::string condition) +{ + assert(conditionIndex < m_conditions.size()); + auto& conditionEntry = m_conditions[conditionIndex]; + conditionEntry.name = std::move(condition); + + OnConditionUpdate(this, conditionIndex); +} + void ShaderGraph::UpdateInput(std::size_t inputIndex, std::string name, PrimitiveType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex) { assert(inputIndex < m_inputs.size()); @@ -600,8 +639,12 @@ void ShaderGraph::UpdateTexturePreview(std::size_t textureIndex, QImage preview) { assert(textureIndex < m_textures.size()); auto& textureEntry = m_textures[textureIndex]; +#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) textureEntry.preview = std::move(preview); textureEntry.preview.convertTo(QImage::Format_RGBA8888); +#else + textureEntry.preview = preview.convertToFormat(QImage::Format_RGBA8888); +#endif OnTexturePreviewUpdate(this, textureIndex); } @@ -638,27 +681,27 @@ QtNodes::NodeDataType ShaderGraph::ToNodeDataType(PrimitiveType type) throw std::runtime_error("Unhandled input type"); } -Nz::ShaderExpressionType ShaderGraph::ToShaderExpressionType(PrimitiveType type) +Nz::ShaderAst::ExpressionType ShaderGraph::ToShaderExpressionType(PrimitiveType type) { switch (type) { - case PrimitiveType::Bool: return Nz::ShaderNodes::BasicType::Boolean; - case PrimitiveType::Float1: return Nz::ShaderNodes::BasicType::Float1; - case PrimitiveType::Float2: return Nz::ShaderNodes::BasicType::Float2; - case PrimitiveType::Float3: return Nz::ShaderNodes::BasicType::Float3; - case PrimitiveType::Float4: return Nz::ShaderNodes::BasicType::Float4; - case PrimitiveType::Mat4x4: return Nz::ShaderNodes::BasicType::Mat4x4; + case PrimitiveType::Bool: return Nz::ShaderAst::PrimitiveType::Boolean; + case PrimitiveType::Float1: return Nz::ShaderAst::PrimitiveType::Float32; + case PrimitiveType::Float2: return Nz::ShaderAst::VectorType{ 2, Nz::ShaderAst::PrimitiveType::Float32 }; + case PrimitiveType::Float3: return Nz::ShaderAst::VectorType{ 3, Nz::ShaderAst::PrimitiveType::Float32 }; + case PrimitiveType::Float4: return Nz::ShaderAst::VectorType{ 4, Nz::ShaderAst::PrimitiveType::Float32 }; + case PrimitiveType::Mat4x4: return Nz::ShaderAst::MatrixType{ 4, 4, Nz::ShaderAst::PrimitiveType::Float32 }; } assert(false); throw std::runtime_error("Unhandled primitive type"); } -Nz::ShaderExpressionType ShaderGraph::ToShaderExpressionType(TextureType type) +Nz::ShaderAst::ExpressionType ShaderGraph::ToShaderExpressionType(TextureType type) { switch (type) { - case TextureType::Sampler2D: return Nz::ShaderNodes::BasicType::Sampler2D; + case TextureType::Sampler2D: return Nz::ShaderAst::SamplerType{ Nz::ImageType::E2D, Nz::ShaderAst::PrimitiveType::Float32 }; } assert(false); @@ -683,29 +726,232 @@ Nz::ShaderStageType ShaderGraph::ToShaderStageType(ShaderType type) std::shared_ptr ShaderGraph::BuildRegistry() { auto registry = std::make_shared(); - RegisterShaderNode(*this, registry, "Inputs"); + + // Casts RegisterShaderNode(*this, registry, "Casts"); RegisterShaderNode(*this, registry, "Casts"); RegisterShaderNode(*this, registry, "Casts"); + + // Constants + RegisterShaderNode(*this, registry, "Constants"); RegisterShaderNode(*this, registry, "Constants"); + RegisterShaderNode(*this, registry, "Constants"); + RegisterShaderNode(*this, registry, "Constants"); + RegisterShaderNode(*this, registry, "Constants"); + + // Inputs + RegisterShaderNode(*this, registry, "Inputs"); RegisterShaderNode(*this, registry, "Inputs"); - RegisterShaderNode(*this, registry, "Outputs"); + + // Outputs + RegisterShaderNode(*this, registry, "Outputs"); RegisterShaderNode(*this, registry, "Outputs"); - RegisterShaderNode(*this, registry, "Texture"); - RegisterShaderNode(*this, registry, "Texture"); + RegisterShaderNode(*this, registry, "Outputs"); + + // Float comparison + RegisterShaderNode(*this, registry, "Float comparisons"); + RegisterShaderNode(*this, registry, "Float comparisons"); + RegisterShaderNode(*this, registry, "Float comparisons"); + RegisterShaderNode(*this, registry, "Float comparisons"); + RegisterShaderNode(*this, registry, "Float comparisons"); + RegisterShaderNode(*this, registry, "Float comparisons"); + + // Float operations + RegisterShaderNode(*this, registry, "Float operations"); + RegisterShaderNode(*this, registry, "Float operations"); + RegisterShaderNode(*this, registry, "Float operations"); + RegisterShaderNode(*this, registry, "Float operations"); + + // Matrix operations RegisterShaderNode(*this, registry, "Matrix operations"); RegisterShaderNode(*this, registry, "Matrix operations"); RegisterShaderNode(*this, registry, "Matrix operations"); RegisterShaderNode(*this, registry, "Matrix operations"); + + // Shader + RegisterShaderNode(*this, registry, "Shader"); + + // Texture + RegisterShaderNode(*this, registry, "Texture"); + RegisterShaderNode(*this, registry, "Texture"); + + // Vector comparison + RegisterShaderNode(*this, registry, "Vector comparisons"); + RegisterShaderNode(*this, registry, "Vector comparisons"); + RegisterShaderNode(*this, registry, "Vector comparisons"); + RegisterShaderNode(*this, registry, "Vector comparisons"); + RegisterShaderNode(*this, registry, "Vector comparisons"); + RegisterShaderNode(*this, registry, "Vector comparisons"); + + // Vector operations RegisterShaderNode(*this, registry, "Vector operations"); + RegisterShaderNode(*this, registry, "Vector operations"); + RegisterShaderNode(*this, registry, "Vector operations"); + RegisterShaderNode(*this, registry, "Vector operations"); + RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Vector operations"); - RegisterShaderNode(*this, registry, "Constants"); - RegisterShaderNode(*this, registry, "Constants"); - RegisterShaderNode(*this, registry, "Constants"); return registry; } + +std::unique_ptr ShaderGraph::ToFunction() const +{ + std::vector statements; + + std::vector parameters; + if (!m_inputs.empty()) + { + parameters.push_back({ + "input", + Nz::ShaderAst::IdentifierType{ "InputData" } + }); + } + + Nz::ShaderAst::ExpressionType returnType; + if (!m_outputs.empty()) + { + returnType = Nz::ShaderAst::IdentifierType{ "OutputData" }; + + statements.push_back(Nz::ShaderBuilder::DeclareVariable("output", returnType)); + } + + using Key = QPair; + auto BuildKey = [](QUuid uuid, std::size_t index) + { + return Key(uuid, index); + }; + + std::map usageCount; + + std::function DetectVariables; + DetectVariables = [&](QtNodes::Node* node, std::size_t outputIndex) + { + auto it = usageCount.find(BuildKey(node->id(), outputIndex)); + if (it == usageCount.end()) + { + for (const auto& connectionSet : node->nodeState().getEntries(QtNodes::PortType::In)) + { + for (const auto& [uuid, conn] : connectionSet) + { + DetectVariables(conn->getNode(QtNodes::PortType::Out), conn->getPortIndex(QtNodes::PortType::Out)); + } + } + + it = usageCount.emplace(BuildKey(node->id(), outputIndex), 0).first; + } + + it->second++; + }; + + std::vector outputNodes; + + m_flowScene->iterateOverNodes([&](QtNodes::Node* node) + { + if (node->nodeDataModel()->nPorts(QtNodes::PortType::Out) == 0) + { + DetectVariables(node, 0); + outputNodes.push_back(node); + } + }); + + std::map variableExpressions; + + unsigned int varCount = 0; + std::unordered_set usedVariableNames; + + std::function HandleNode; + HandleNode = [&](QtNodes::Node* node, std::size_t portIndex) -> Nz::ShaderAst::NodePtr + { + ShaderNode* shaderNode = static_cast(node->nodeDataModel()); + if (shaderNode->validationState() != QtNodes::NodeValidationState::Valid) + throw std::runtime_error(shaderNode->validationMessage().toStdString()); + + qDebug() << shaderNode->name() << node->id(); + if (auto it = variableExpressions.find(BuildKey(node->id(), portIndex)); it != variableExpressions.end()) + return Nz::ShaderAst::Clone(it->second); + + auto it = usageCount.find(BuildKey(node->id(), portIndex)); + assert(it != usageCount.end()); + + std::size_t inputCount = shaderNode->nPorts(QtNodes::PortType::In); + Nz::StackArray expressions = NazaraStackArray(Nz::ShaderAst::ExpressionPtr, inputCount); + std::size_t i = 0; + + for (const auto& connectionSet : node->nodeState().getEntries(QtNodes::PortType::In)) + { + for (const auto& [uuid, conn] : connectionSet) + { + assert(i < expressions.size()); + Nz::ShaderAst::NodePtr inputNode = HandleNode(conn->getNode(QtNodes::PortType::Out), conn->getPortIndex(QtNodes::PortType::Out)); + if (!Nz::ShaderAst::IsExpression(inputNode->GetType())) + throw std::runtime_error("unexpected statement"); + + expressions[i] = static_unique_pointer_cast(std::move(inputNode)); + i++; + } + } + + auto astNode = shaderNode->BuildNode(expressions.data(), expressions.size(), portIndex); + if (!Nz::ShaderAst::IsExpression(astNode->GetType())) + return astNode; + + Nz::ShaderAst::ExpressionPtr expression = static_unique_pointer_cast(std::move(astNode)); + + const std::string& variableName = shaderNode->GetVariableName(); + if (it->second > 1 || !variableName.empty()) + { + Nz::ShaderAst::ExpressionPtr varExpression; + if (Nz::ShaderAst::GetExpressionCategory(*expression) == Nz::ShaderAst::ExpressionCategory::RValue) + { + std::string name; + if (variableName.empty()) + name = "var" + std::to_string(varCount++); + else + name = variableName; + + if (usedVariableNames.find(name) != usedVariableNames.end()) + throw std::runtime_error("duplicate variable found: " + name); + + usedVariableNames.insert(name); + + statements.emplace_back(Nz::ShaderBuilder::DeclareVariable(name, std::move(expression))); + + varExpression = Nz::ShaderBuilder::Identifier(name); + } + else + varExpression = std::move(expression); + + variableExpressions[BuildKey(node->id(), portIndex)] = Nz::ShaderAst::Clone(varExpression); + + return varExpression; + } + else + return expression; + }; + + std::sort(outputNodes.begin(), outputNodes.end(), [](QtNodes::Node* lhs, QtNodes::Node* rhs) + { + ShaderNode* leftNode = static_cast(lhs->nodeDataModel()); + ShaderNode* rightNode = static_cast(rhs->nodeDataModel()); + + return leftNode->GetOutputOrder() < rightNode->GetOutputOrder(); + }); + + for (QtNodes::Node* node : outputNodes) + { + auto astNode = HandleNode(node, 0); + if (!Nz::ShaderAst::IsStatement(astNode->GetType())) + statements.emplace_back(Nz::ShaderBuilder::ExpressionStatement(static_unique_pointer_cast(std::move(astNode)))); + else + statements.emplace_back(static_unique_pointer_cast(std::move(astNode))); + } + + if (!m_outputs.empty()) + statements.push_back(Nz::ShaderBuilder::Return(Nz::ShaderBuilder::Identifier("output"))); + + return Nz::ShaderBuilder::DeclareFunction(ToShaderStageType(m_type), "main", std::move(parameters), std::move(statements), std::move(returnType)); +} diff --git a/src/ShaderNode/ShaderGraph.hpp b/src/ShaderNode/ShaderGraph.hpp index 1df336ce6..2e278a8ac 100644 --- a/src/ShaderNode/ShaderGraph.hpp +++ b/src/ShaderNode/ShaderGraph.hpp @@ -5,10 +5,11 @@ #include #include -#include +#include #include #include #include +#include #include #include @@ -18,6 +19,7 @@ class ShaderGraph { public: struct BufferEntry; + struct ConditionEntry; struct InputEntry; struct OutputEntry; struct StructEntry; @@ -28,6 +30,7 @@ class ShaderGraph ~ShaderGraph(); std::size_t AddBuffer(std::string name, BufferType bufferType, std::size_t structIndex, std::size_t bindingIndex); + std::size_t AddCondition(std::string name); std::size_t AddInput(std::string name, PrimitiveType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex); std::size_t AddOutput(std::string name, PrimitiveType type, std::size_t locationIndex); std::size_t AddStruct(std::string name, std::vector members); @@ -35,9 +38,14 @@ class ShaderGraph void Clear(); + void EnableCondition(std::size_t conditionIndex, bool enable); + inline const BufferEntry& GetBuffer(std::size_t bufferIndex) const; inline std::size_t GetBufferCount() const; inline const std::vector& GetBuffers() const; + inline const ConditionEntry& GetCondition(std::size_t conditionIndex) const; + inline std::size_t GetConditionCount() const; + inline const std::vector& GetConditions() const; inline const InputEntry& GetInput(std::size_t bufferIndex) const; inline std::size_t GetInputCount() const; inline const std::vector& GetInputs() const; @@ -54,13 +62,16 @@ class ShaderGraph inline const std::vector& GetTextures() const; inline ShaderType GetType() const; + inline bool IsConditionEnabled(std::size_t conditionIndex) const; + void Load(const QJsonObject& data); QJsonObject Save(); - Nz::ShaderNodes::StatementPtr ToAst(); - Nz::ShaderExpressionType ToShaderExpressionType(const std::variant& type) const; + Nz::ShaderAst::StatementPtr ToAst() const; + Nz::ShaderAst::ExpressionType ToShaderExpressionType(const std::variant& type) const; void UpdateBuffer(std::size_t bufferIndex, std::string name, BufferType bufferType, std::size_t structIndex, std::size_t bindingIndex); + void UpdateCondition(std::size_t conditionIndex, std::string condition); void UpdateInput(std::size_t inputIndex, std::string name, PrimitiveType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex); void UpdateOutput(std::size_t outputIndex, std::string name, PrimitiveType type, std::size_t locationIndex); void UpdateStruct(std::size_t structIndex, std::string name, std::vector members); @@ -76,6 +87,12 @@ class ShaderGraph BufferType type; }; + struct ConditionEntry + { + std::string name; + bool enabled = false; + }; + struct InputEntry { std::size_t locationIndex; @@ -113,7 +130,9 @@ class ShaderGraph }; NazaraSignal(OnBufferListUpdate, ShaderGraph*); - NazaraSignal(OnBufferUpdate, ShaderGraph*, std::size_t /*outputIndex*/); + NazaraSignal(OnBufferUpdate, ShaderGraph*, std::size_t /*bufferIndex*/); + NazaraSignal(OnConditionListUpdate, ShaderGraph*); + NazaraSignal(OnConditionUpdate, ShaderGraph*, std::size_t /*conditionIndex*/); NazaraSignal(OnInputListUpdate, ShaderGraph*); NazaraSignal(OnInputUpdate, ShaderGraph*, std::size_t /*inputIndex*/); NazaraSignal(OnOutputListUpdate, ShaderGraph*); @@ -127,15 +146,17 @@ class ShaderGraph NazaraSignal(OnTypeUpdated, ShaderGraph*); static QtNodes::NodeDataType ToNodeDataType(PrimitiveType type); - static Nz::ShaderExpressionType ToShaderExpressionType(PrimitiveType type); - static Nz::ShaderExpressionType ToShaderExpressionType(TextureType type); + static Nz::ShaderAst::ExpressionType ToShaderExpressionType(PrimitiveType type); + static Nz::ShaderAst::ExpressionType ToShaderExpressionType(TextureType type); static Nz::ShaderStageType ToShaderStageType(ShaderType type); private: std::shared_ptr BuildRegistry(); + std::unique_ptr ToFunction() const; - QtNodes::FlowScene m_flowScene; + mutable std::optional m_flowScene; std::vector m_buffers; + std::vector m_conditions; std::vector m_inputs; std::vector m_outputs; std::vector m_structs; diff --git a/src/ShaderNode/ShaderGraph.inl b/src/ShaderNode/ShaderGraph.inl index afa867dcd..bb2aebca6 100644 --- a/src/ShaderNode/ShaderGraph.inl +++ b/src/ShaderNode/ShaderGraph.inl @@ -16,6 +16,22 @@ inline auto ShaderGraph::GetBuffers() const -> const std::vector& return m_buffers; } +inline auto ShaderGraph::GetCondition(std::size_t conditionIndex) const -> const ConditionEntry& +{ + assert(conditionIndex < m_conditions.size()); + return m_conditions[conditionIndex]; +} + +inline std::size_t ShaderGraph::GetConditionCount() const +{ + return m_conditions.size(); +} + +inline auto ShaderGraph::GetConditions() const -> const std::vector& +{ + return m_conditions; +} + inline auto ShaderGraph::GetInput(std::size_t inputIndex) const -> const InputEntry& { assert(inputIndex < m_inputs.size()); @@ -71,7 +87,7 @@ inline const PreviewModel& ShaderGraph::GetPreviewModel() const inline QtNodes::FlowScene& ShaderGraph::GetScene() { - return m_flowScene; + return *m_flowScene; } inline auto ShaderGraph::GetTexture(std::size_t textureIndex) const -> const TextureEntry& @@ -95,3 +111,9 @@ inline ShaderType ShaderGraph::GetType() const return m_type; } +inline bool ShaderGraph::IsConditionEnabled(std::size_t conditionIndex) const +{ + assert(conditionIndex < m_conditions.size()); + return m_conditions[conditionIndex].enabled; +} + diff --git a/src/ShaderNode/Widgets/CodeOutputWidget.cpp b/src/ShaderNode/Widgets/CodeOutputWidget.cpp new file mode 100644 index 000000000..551657ba4 --- /dev/null +++ b/src/ShaderNode/Widgets/CodeOutputWidget.cpp @@ -0,0 +1,115 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum class OutputLanguage +{ + GLSL, + Nazalang, + SpirV +}; + +CodeOutputWidget::CodeOutputWidget(const ShaderGraph& shaderGraph) : +m_shaderGraph(shaderGraph) +{ + m_textOutput = new QTextEdit; + + m_outputLang = new QComboBox; + m_outputLang->addItem("GLSL", int(OutputLanguage::GLSL)); + m_outputLang->addItem("Nazalang", int(OutputLanguage::Nazalang)); + m_outputLang->addItem("SPIR-V", int(OutputLanguage::SpirV)); + connect(m_outputLang, qOverload(&QComboBox::currentIndexChanged), [this](int) + { + Refresh(); + }); + + m_optimisationCheckbox = new QCheckBox; + m_optimisationCheckbox->setText("Enable optimisation"); + connect(m_optimisationCheckbox, &QCheckBox::stateChanged, [this](int) + { + Refresh(); + }); + + QVBoxLayout* verticalLayout = new QVBoxLayout; + verticalLayout->addWidget(m_textOutput); + verticalLayout->addWidget(m_outputLang); + verticalLayout->addWidget(m_optimisationCheckbox); + + setLayout(verticalLayout); + + Refresh(); +} + +void CodeOutputWidget::Refresh() +{ + try + { + Nz::UInt64 enabledConditions = 0; + for (std::size_t i = 0; i < m_shaderGraph.GetConditionCount(); ++i) + { + if (m_shaderGraph.IsConditionEnabled(i)) + enabledConditions = Nz::SetBit(enabledConditions, i); + } + + Nz::ShaderAst::StatementPtr shaderAst = m_shaderGraph.ToAst(); + + if (m_optimisationCheckbox->isChecked()) + { + shaderAst = Nz::ShaderAst::Sanitize(shaderAst); + + Nz::ShaderAst::AstOptimizer optimiser; + shaderAst = optimiser.Optimise(shaderAst, enabledConditions); + } + + Nz::ShaderWriter::States states; + states.enabledOptions = enabledConditions; + + std::string output; + OutputLanguage outputLang = static_cast(m_outputLang->currentIndex()); + switch (outputLang) + { + case OutputLanguage::GLSL: + { + Nz::GlslWriter writer; + output = writer.Generate(ShaderGraph::ToShaderStageType(m_shaderGraph.GetType()), shaderAst, states); + break; + } + + case OutputLanguage::Nazalang: + { + Nz::LangWriter writer; + output = writer.Generate(shaderAst, states); + break; + } + + case OutputLanguage::SpirV: + { + Nz::SpirvWriter writer; + std::vector spirv = writer.Generate(shaderAst, states); + + Nz::SpirvPrinter printer; + output = printer.Print(spirv.data(), spirv.size()); + break; + } + } + + int scrollValue = m_textOutput->verticalScrollBar()->value(); + m_textOutput->setText(QString::fromStdString(output)); + m_textOutput->verticalScrollBar()->setValue(scrollValue); + } + catch (const std::exception& e) + { + m_textOutput->setText("Generation failed: " + QString::fromStdString(e.what())); + } +} diff --git a/src/ShaderNode/Widgets/CodeOutputWidget.hpp b/src/ShaderNode/Widgets/CodeOutputWidget.hpp new file mode 100644 index 000000000..47945ca34 --- /dev/null +++ b/src/ShaderNode/Widgets/CodeOutputWidget.hpp @@ -0,0 +1,31 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_CODEOUTPUTWIDGET_HPP +#define NAZARA_SHADERNODES_CODEOUTPUTWIDGET_HPP + +#include +#include + +class QCheckBox; +class QComboBox; +class QTextEdit; +class ShaderGraph; + +class CodeOutputWidget : public QWidget +{ + public: + CodeOutputWidget(const ShaderGraph& shaderGraph); + ~CodeOutputWidget() = default; + + void Refresh(); + + private: + const ShaderGraph& m_shaderGraph; + QCheckBox* m_optimisationCheckbox; + QComboBox* m_outputLang; + QTextEdit* m_textOutput; +}; + +#include + +#endif diff --git a/src/ShaderNode/Widgets/CodeOutputWidget.inl b/src/ShaderNode/Widgets/CodeOutputWidget.inl new file mode 100644 index 000000000..26a824b63 --- /dev/null +++ b/src/ShaderNode/Widgets/CodeOutputWidget.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/Widgets/ConditionEditDialog.cpp b/src/ShaderNode/Widgets/ConditionEditDialog.cpp new file mode 100644 index 000000000..4d04932a6 --- /dev/null +++ b/src/ShaderNode/Widgets/ConditionEditDialog.cpp @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +ConditionEditDialog::ConditionEditDialog(QWidget* parent) : +QDialog(parent) +{ + setWindowTitle(tr("Condition edit dialog")); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + m_conditionName = new QLineEdit; + + QFormLayout* formLayout = new QFormLayout; + formLayout->addRow(tr("Name"), m_conditionName); + + QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(buttonBox, &QDialogButtonBox::accepted, this, &ConditionEditDialog::OnAccept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + + QVBoxLayout* verticalLayout = new QVBoxLayout; + verticalLayout->addLayout(formLayout); + verticalLayout->addWidget(buttonBox); + + setLayout(verticalLayout); +} + +ConditionEditDialog::ConditionEditDialog(const ConditionInfo& condition, QWidget* parent) : +ConditionEditDialog(parent) +{ + m_conditionName->setText(QString::fromStdString(condition.name)); +} + +ConditionInfo ConditionEditDialog::GetConditionInfo() const +{ + ConditionInfo inputInfo; + inputInfo.name = m_conditionName->text().toStdString(); + + return inputInfo; +} + +void ConditionEditDialog::OnAccept() +{ + if (m_conditionName->text().isEmpty()) + { + QMessageBox::critical(this, tr("Empty name"), tr("Condition name must be set"), QMessageBox::Ok); + return; + } + + accept(); +} diff --git a/src/ShaderNode/Widgets/ConditionEditDialog.hpp b/src/ShaderNode/Widgets/ConditionEditDialog.hpp new file mode 100644 index 000000000..22cebb2f8 --- /dev/null +++ b/src/ShaderNode/Widgets/ConditionEditDialog.hpp @@ -0,0 +1,35 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_CONDITIONEDITDIALOG_HPP +#define NAZARA_SHADERNODES_CONDITIONEDITDIALOG_HPP + +#include +#include + +class QComboBox; +class QLineEdit; +class QSpinBox; + +struct ConditionInfo +{ + std::string name; +}; + +class ConditionEditDialog : public QDialog +{ + public: + ConditionEditDialog(QWidget* parent = nullptr); + ConditionEditDialog(const ConditionInfo& input, QWidget* parent = nullptr); + ~ConditionEditDialog() = default; + + ConditionInfo GetConditionInfo() const; + + private: + void OnAccept(); + + QLineEdit* m_conditionName; +}; + +#include + +#endif diff --git a/src/ShaderNode/Widgets/ConditionEditDialog.inl b/src/ShaderNode/Widgets/ConditionEditDialog.inl new file mode 100644 index 000000000..157a5289b --- /dev/null +++ b/src/ShaderNode/Widgets/ConditionEditDialog.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/Widgets/ConditionEditor.cpp b/src/ShaderNode/Widgets/ConditionEditor.cpp new file mode 100644 index 000000000..e16527254 --- /dev/null +++ b/src/ShaderNode/Widgets/ConditionEditor.cpp @@ -0,0 +1,119 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +ConditionEditor::ConditionEditor(ShaderGraph& graph) : +m_shaderGraph(graph) +{ + QTableView* tableView = new QTableView; + m_model = new QStandardItemModel(0, 2, tableView); + tableView->setModel(m_model); + + m_model->setHorizontalHeaderLabels({ tr("Condition"), tr("Enabled") }); + + connect(tableView, &QTableView::doubleClicked, [this](const QModelIndex& index) + { + if (index.column() == 0) + OnEditCondition(index.row()); + }); + + connect(m_model, &QStandardItemModel::itemChanged, [this](QStandardItem* item) + { + if (item->column() == 1) + { + std::size_t conditionIndex = static_cast(item->row()); + bool value = item->checkState() == Qt::Checked; + m_shaderGraph.EnableCondition(conditionIndex, value); + } + }); + + + QPushButton* addStructButton = new QPushButton(tr("Add condition...")); + connect(addStructButton, &QPushButton::released, this, &ConditionEditor::OnAddCondition); + + m_layout = new QVBoxLayout; + m_layout->addWidget(tableView); + m_layout->addWidget(addStructButton); + + setLayout(m_layout); + + m_onConditionListUpdateSlot.Connect(m_shaderGraph.OnConditionListUpdate, this, &ConditionEditor::OnConditionListUpdate); + m_onConditionUpdateSlot.Connect(m_shaderGraph.OnConditionUpdate, this, &ConditionEditor::OnConditionUpdate); + + RefreshConditions(); +} + +void ConditionEditor::OnAddCondition() +{ + ConditionEditDialog* dialog = new ConditionEditDialog(this); + dialog->setAttribute(Qt::WA_DeleteOnClose, true); + connect(dialog, &QDialog::accepted, [this, dialog] + { + ConditionInfo conditionInfo = dialog->GetConditionInfo(); + m_shaderGraph.AddCondition(std::move(conditionInfo.name)); + }); + + dialog->open(); +} + +void ConditionEditor::OnEditCondition(int conditionIndex) +{ + const auto& conditionInfo = m_shaderGraph.GetCondition(conditionIndex); + + ConditionInfo info; + info.name = conditionInfo.name; + + ConditionEditDialog* dialog = new ConditionEditDialog(info, this); + dialog->setAttribute(Qt::WA_DeleteOnClose, true); + connect(dialog, &QDialog::accepted, [this, dialog, conditionIndex] + { + ConditionInfo conditionInfo = dialog->GetConditionInfo(); + + m_shaderGraph.UpdateCondition(conditionIndex, std::move(conditionInfo.name)); + }); + + dialog->open(); +} + +void ConditionEditor::OnConditionListUpdate(ShaderGraph* /*graph*/) +{ + RefreshConditions(); +} + +void ConditionEditor::OnConditionUpdate(ShaderGraph* /*graph*/, std::size_t conditionIndex) +{ + const auto& conditionEntry = m_shaderGraph.GetCondition(conditionIndex); + + int row = int(conditionIndex); + m_model->item(row, 0)->setText(QString::fromStdString(conditionEntry.name)); + m_model->item(row, 1)->setCheckState((conditionEntry.enabled) ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); +} + +void ConditionEditor::RefreshConditions() +{ + m_model->setRowCount(int(m_shaderGraph.GetConditionCount())); + + int rowIndex = 0; + for (const auto& conditionEntry : m_shaderGraph.GetConditions()) + { + QStandardItem* label = new QStandardItem(1); + label->setEditable(false); + label->setText(QString::fromStdString(conditionEntry.name)); + + m_model->setItem(rowIndex, 0, label); + + QStandardItem* checkbox = new QStandardItem(1); + checkbox->setCheckable(true); + checkbox->setCheckState((conditionEntry.enabled) ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); + + m_model->setItem(rowIndex, 1, checkbox); + + rowIndex++; + } +} diff --git a/src/ShaderNode/Widgets/ConditionEditor.hpp b/src/ShaderNode/Widgets/ConditionEditor.hpp new file mode 100644 index 000000000..b88b035fe --- /dev/null +++ b/src/ShaderNode/Widgets/ConditionEditor.hpp @@ -0,0 +1,36 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_CONDITIONEDITOR_HPP +#define NAZARA_SHADERNODES_CONDITIONEDITOR_HPP + +#include +#include +#include + +class QStandardItemModel; +class QVBoxLayout; + +class ConditionEditor : public QWidget +{ + public: + ConditionEditor(ShaderGraph& graph); + ~ConditionEditor() = default; + + private: + void OnAddCondition(); + void OnConditionListUpdate(ShaderGraph* graph); + void OnConditionUpdate(ShaderGraph* graph, std::size_t conditionIndex); + void OnEditCondition(int inputIndex); + void RefreshConditions(); + + NazaraSlot(ShaderGraph, OnStructListUpdate, m_onConditionListUpdateSlot); + NazaraSlot(ShaderGraph, OnStructUpdate, m_onConditionUpdateSlot); + + ShaderGraph& m_shaderGraph; + QStandardItemModel* m_model; + QVBoxLayout* m_layout; +}; + +#include + +#endif diff --git a/src/ShaderNode/Widgets/ConditionEditor.inl b/src/ShaderNode/Widgets/ConditionEditor.inl new file mode 100644 index 000000000..7367d2757 --- /dev/null +++ b/src/ShaderNode/Widgets/ConditionEditor.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/Widgets/MainWindow.cpp b/src/ShaderNode/Widgets/MainWindow.cpp index b313ee083..ed4055714 100644 --- a/src/ShaderNode/Widgets/MainWindow.cpp +++ b/src/ShaderNode/Widgets/MainWindow.cpp @@ -1,9 +1,11 @@ #include #include #include -#include +#include #include #include +#include +#include #include #include #include @@ -13,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -34,7 +37,6 @@ m_shaderGraph(graph) InputEditor* inputEditor = new InputEditor(m_shaderGraph); QDockWidget* inputDock = new QDockWidget(tr("Inputs")); - inputDock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable); inputDock->setWidget(inputEditor); addDockWidget(Qt::LeftDockWidgetArea, inputDock); @@ -43,7 +45,6 @@ m_shaderGraph(graph) OutputEditor* outputEditor = new OutputEditor(m_shaderGraph); QDockWidget* outputDock = new QDockWidget(tr("Outputs")); - outputDock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable); outputDock->setWidget(outputEditor); addDockWidget(Qt::LeftDockWidgetArea, outputDock); @@ -52,7 +53,6 @@ m_shaderGraph(graph) TextureEditor* textureEditor = new TextureEditor(m_shaderGraph); QDockWidget* textureDock = new QDockWidget(tr("Textures")); - textureDock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable); textureDock->setWidget(textureEditor); addDockWidget(Qt::LeftDockWidgetArea, textureDock); @@ -61,7 +61,6 @@ m_shaderGraph(graph) m_nodeEditor = new NodeEditor; QDockWidget* nodeEditorDock = new QDockWidget(tr("Node editor")); - nodeEditorDock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable); nodeEditorDock->setWidget(m_nodeEditor); addDockWidget(Qt::RightDockWidgetArea, nodeEditorDock); @@ -70,7 +69,6 @@ m_shaderGraph(graph) BufferEditor* bufferEditor = new BufferEditor(m_shaderGraph); QDockWidget* bufferDock = new QDockWidget(tr("Buffers")); - bufferDock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable); bufferDock->setWidget(bufferEditor); addDockWidget(Qt::RightDockWidgetArea, bufferDock); @@ -79,11 +77,26 @@ m_shaderGraph(graph) StructEditor* structEditor = new StructEditor(m_shaderGraph); QDockWidget* structDock = new QDockWidget(tr("Structs")); - structDock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable); structDock->setWidget(structEditor); addDockWidget(Qt::RightDockWidgetArea, structDock); + // Condition editor + ConditionEditor* conditionEditor = new ConditionEditor(m_shaderGraph); + + QDockWidget* conditionDock = new QDockWidget(tr("Conditions")); + conditionDock->setWidget(conditionEditor); + + addDockWidget(Qt::RightDockWidgetArea, conditionDock); + + // Code output + CodeOutputWidget* codeOutput = new CodeOutputWidget(m_shaderGraph); + + QDockWidget* codeOutputDock = new QDockWidget(tr("Code output")); + codeOutputDock->setWidget(codeOutput); + + addDockWidget(Qt::BottomDockWidgetArea, codeOutputDock); + m_onSelectedNodeUpdate.Connect(m_shaderGraph.OnSelectedNodeUpdate, [&](ShaderGraph*, ShaderNode* node) { if (node) @@ -99,6 +112,46 @@ m_shaderGraph(graph) BuildMenu(); + { + QMenu* view = menuBar()->addMenu("View"); + view->addAction(inputDock->toggleViewAction()); + view->addAction(outputDock->toggleViewAction()); + view->addAction(textureDock->toggleViewAction()); + view->addAction(nodeEditorDock->toggleViewAction()); + view->addAction(bufferDock->toggleViewAction()); + view->addAction(structDock->toggleViewAction()); + view->addAction(conditionDock->toggleViewAction()); + view->addAction(codeOutputDock->toggleViewAction()); + } + + connect(scene, &QtNodes::FlowScene::connectionCreated, [=](const QtNodes::Connection& /*connection*/) + { + QTimer::singleShot(0, [=] + { + if (codeOutput->isVisible()) + codeOutput->Refresh(); + }); + }); + + connect(scene, &QtNodes::FlowScene::connectionDeleted, [=](const QtNodes::Connection& /*connection*/) + { + QTimer::singleShot(0, [=] + { + if (codeOutput->isVisible()) + codeOutput->Refresh(); + }); + }); + + m_onConditionUpdate.Connect(m_shaderGraph.OnConditionUpdate, [=](ShaderGraph*, std::size_t /*conditionIndex*/) + { + if (codeOutput->isVisible()) + codeOutput->Refresh(); + }); +} + +MainWindow::~MainWindow() +{ + m_shaderGraph.Clear(); } void MainWindow::BuildMenu() @@ -109,6 +162,7 @@ void MainWindow::BuildMenu() { QAction* loadShader = file->addAction(tr("Load...")); QObject::connect(loadShader, &QAction::triggered, this, &MainWindow::OnLoad); + QAction* saveShader = file->addAction(tr("Save...")); QObject::connect(saveShader, &QAction::triggered, this, &MainWindow::OnSave); } @@ -117,22 +171,17 @@ void MainWindow::BuildMenu() { QAction* settings = shader->addAction(tr("Settings...")); QObject::connect(settings, &QAction::triggered, this, &MainWindow::OnUpdateInfo); + QAction* compileShader = shader->addAction(tr("Compile...")); QObject::connect(compileShader, &QAction::triggered, this, &MainWindow::OnCompile); } - - QMenu* generateMenu = menu->addMenu(tr("&Generate")); - { - QAction* generateGlsl = generateMenu->addAction(tr("GLSL")); - connect(generateGlsl, &QAction::triggered, [&](bool) { OnGenerateGLSL(); }); - } } void MainWindow::OnCompile() { try { - auto shader = ToShader(); + auto shader = m_shaderGraph.ToAst(); QString fileName = QFileDialog::getSaveFileName(nullptr, tr("Save shader"), QString(), tr("Shader Files (*.shader)")); if (fileName.isEmpty()) @@ -141,8 +190,8 @@ void MainWindow::OnCompile() if (!fileName.endsWith("shader", Qt::CaseInsensitive)) fileName += ".shader"; - Nz::File file(fileName.toStdString(), Nz::OpenMode_WriteOnly); - file.Write(Nz::SerializeShader(shader)); + Nz::File file(fileName.toStdString(), Nz::OpenMode::WriteOnly); + file.Write(Nz::ShaderAst::SerializeShader(shader)); } catch (const std::exception& e) { @@ -150,28 +199,6 @@ void MainWindow::OnCompile() } } -void MainWindow::OnGenerateGLSL() -{ - try - { - Nz::GlslWriter writer; - std::string glsl = writer.Generate(ToShader()); - - std::cout << glsl << std::endl; - - QTextEdit* output = new QTextEdit; - output->setReadOnly(true); - output->setText(QString::fromStdString(glsl)); - output->setAttribute(Qt::WA_DeleteOnClose, true); - output->setWindowTitle("GLSL Output"); - output->show(); - } - catch (const std::exception& e) - { - QMessageBox::critical(this, tr("Generation failed"), QString("Generation failed: ") + e.what()); - } -} - void MainWindow::OnLoad() { QString fileName = QFileDialog::getOpenFileName(this, tr("Open shader flow"), QString(), tr("Shader Flow Files (*.shaderflow)")); @@ -232,51 +259,3 @@ void MainWindow::OnUpdateInfo() dialog->open(); } - -Nz::ShaderAst MainWindow::ToShader() -{ - Nz::ShaderNodes::StatementPtr shaderAst = m_shaderGraph.ToAst(); - - Nz::ShaderAst shader(ShaderGraph::ToShaderStageType(m_shaderGraph.GetType())); //< FIXME - for (const auto& input : m_shaderGraph.GetInputs()) - shader.AddInput(input.name, m_shaderGraph.ToShaderExpressionType(input.type), input.locationIndex); - - for (const auto& output : m_shaderGraph.GetOutputs()) - shader.AddOutput(output.name, m_shaderGraph.ToShaderExpressionType(output.type), output.locationIndex); - - for (const auto& buffer : m_shaderGraph.GetBuffers()) - { - const auto& structInfo = m_shaderGraph.GetStruct(buffer.structIndex); - shader.AddUniform(buffer.name, structInfo.name, buffer.bindingIndex, Nz::ShaderNodes::MemoryLayout::Std140); - } - - for (const auto& uniform : m_shaderGraph.GetTextures()) - shader.AddUniform(uniform.name, m_shaderGraph.ToShaderExpressionType(uniform.type), uniform.bindingIndex, {}); - - for (const auto& s : m_shaderGraph.GetStructs()) - { - std::vector members; - for (const auto& sMember : s.members) - { - auto& member = members.emplace_back(); - member.name = sMember.name; - - std::visit([&](auto&& arg) - { - using T = std::decay_t; - if constexpr (std::is_same_v) - member.type = m_shaderGraph.ToShaderExpressionType(arg); - else if constexpr (std::is_same_v) - member.type = m_shaderGraph.GetStruct(arg).name; - else - static_assert(Nz::AlwaysFalse::value, "non-exhaustive visitor"); - }, sMember.type); - } - - shader.AddStruct(s.name, std::move(members)); - } - - shader.AddFunction("main", shaderAst); - - return shader; -} diff --git a/src/ShaderNode/Widgets/MainWindow.hpp b/src/ShaderNode/Widgets/MainWindow.hpp index 76615bb98..eaedd6aea 100644 --- a/src/ShaderNode/Widgets/MainWindow.hpp +++ b/src/ShaderNode/Widgets/MainWindow.hpp @@ -9,26 +9,20 @@ class NodeEditor; -namespace Nz -{ - class ShaderAst; -} - class MainWindow : public QMainWindow { public: MainWindow(ShaderGraph& graph); - ~MainWindow() = default; + ~MainWindow(); private: void BuildMenu(); void OnCompile(); - void OnGenerateGLSL(); void OnLoad(); void OnSave(); void OnUpdateInfo(); - Nz::ShaderAst ToShader(); + NazaraSlot(ShaderGraph, OnConditionUpdate, m_onConditionUpdate); NazaraSlot(ShaderGraph, OnSelectedNodeUpdate, m_onSelectedNodeUpdate); NodeEditor* m_nodeEditor; diff --git a/src/ShaderNode/Widgets/TextureEditor.cpp b/src/ShaderNode/Widgets/TextureEditor.cpp index 99b40316a..c9bcf7d1c 100644 --- a/src/ShaderNode/Widgets/TextureEditor.cpp +++ b/src/ShaderNode/Widgets/TextureEditor.cpp @@ -19,11 +19,15 @@ m_shaderGraph(graph) m_pixmapLabel = new QLabel; - QPushButton* updateTextureButton = new QPushButton(tr("Load texture...")); + QPushButton* addTextureButton = new QPushButton(tr("Add texture...")); + connect(addTextureButton, &QPushButton::released, this, &TextureEditor::OnAddTexture); + + QPushButton* updateTextureButton = new QPushButton(tr("Load texture preview...")); connect(updateTextureButton, &QPushButton::released, this, &TextureEditor::OnLoadTexture); m_layout = new QVBoxLayout; m_layout->addWidget(m_textureList); + m_layout->addWidget(addTextureButton); m_layout->addWidget(updateTextureButton); m_layout->addWidget(m_pixmapLabel); diff --git a/tests/Engine/Audio/AlgorithmAudio.cpp b/tests/Engine/Audio/AlgorithmAudioTest.cpp similarity index 94% rename from tests/Engine/Audio/AlgorithmAudio.cpp rename to tests/Engine/Audio/AlgorithmAudioTest.cpp index 1d6de09c3..5e175425a 100644 --- a/tests/Engine/Audio/AlgorithmAudio.cpp +++ b/tests/Engine/Audio/AlgorithmAudioTest.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include diff --git a/tests/Engine/Audio/Music.cpp b/tests/Engine/Audio/MusicTest.cpp similarity index 77% rename from tests/Engine/Audio/Music.cpp rename to tests/Engine/Audio/MusicTest.cpp index 14cc2ede5..0ccd02452 100644 --- a/tests/Engine/Audio/Music.cpp +++ b/tests/Engine/Audio/MusicTest.cpp @@ -1,9 +1,11 @@ #include #include -#include +#include #include #include +std::filesystem::path GetResourceDir(); + SCENARIO("Music", "[AUDIO][MUSIC]") { GIVEN("A music") @@ -12,18 +14,18 @@ SCENARIO("Music", "[AUDIO][MUSIC]") WHEN("We load our music") { - REQUIRE(music.OpenFromFile("resources/Engine/Audio/The_Brabanconne.ogg")); + REQUIRE(music.OpenFromFile(GetResourceDir() / "Engine/Audio/The_Brabanconne.ogg")); THEN("We can ask the informations of the file") { CHECK(music.GetDuration() <= 64000); // 1 min 03 = 63s = 63000ms CHECK(music.GetDuration() >= 63000); - CHECK(music.GetFormat() == Nz::AudioFormat_Stereo); + CHECK(music.GetFormat() == Nz::AudioFormat::I16_Stereo); CHECK(music.GetPlayingOffset() == 0); CHECK(music.GetSampleCount() <= 5644800); // 64s * 44100 Hz * 2 (stereo) CHECK(music.GetSampleCount() >= 5556600); // 63s * 44100 Hz * 2 (stereo) CHECK(music.GetSampleRate() == 44100 /* Hz */); - CHECK(music.GetStatus() == Nz::SoundStatus_Stopped); + CHECK(music.GetStatus() == Nz::SoundStatus::Stopped); CHECK(music.IsLooping() == false); } @@ -37,7 +39,7 @@ SCENARIO("Music", "[AUDIO][MUSIC]") std::this_thread::sleep_for(std::chrono::milliseconds(200)); REQUIRE(music.GetPlayingOffset() <= 1300); music.Pause(); - REQUIRE(music.GetStatus() == Nz::SoundStatus_Paused); + REQUIRE(music.GetStatus() == Nz::SoundStatus::Paused); music.SetPlayingOffset(3500); REQUIRE(music.GetPlayingOffset() >= 3500); diff --git a/tests/Engine/Audio/SoundBuffer.cpp b/tests/Engine/Audio/SoundBufferTest.cpp similarity index 60% rename from tests/Engine/Audio/SoundBuffer.cpp rename to tests/Engine/Audio/SoundBufferTest.cpp index 292a1e98e..06cadd383 100644 --- a/tests/Engine/Audio/SoundBuffer.cpp +++ b/tests/Engine/Audio/SoundBufferTest.cpp @@ -1,5 +1,7 @@ #include -#include +#include + +std::filesystem::path GetResourceDir(); SCENARIO("SoundBuffer", "[AUDIO][SOUNDBUFFER]") { @@ -7,8 +9,8 @@ SCENARIO("SoundBuffer", "[AUDIO][SOUNDBUFFER]") { WHEN("We load our sound") { - Nz::SoundBufferRef soundBuffer = Nz::SoundBuffer::LoadFromFile("resources/Engine/Audio/Cat.flac"); - REQUIRE(soundBuffer.IsValid()); + std::shared_ptr soundBuffer = Nz::SoundBuffer::LoadFromFile(GetResourceDir() / "Engine/Audio/Cat.flac"); + REQUIRE(soundBuffer); THEN("We can ask the informations of the file") { diff --git a/tests/Engine/Audio/SoundEmitter.cpp b/tests/Engine/Audio/SoundEmitterTest.cpp similarity index 86% rename from tests/Engine/Audio/SoundEmitter.cpp rename to tests/Engine/Audio/SoundEmitterTest.cpp index c2cf4f318..84dbc53d5 100644 --- a/tests/Engine/Audio/SoundEmitter.cpp +++ b/tests/Engine/Audio/SoundEmitterTest.cpp @@ -1,5 +1,7 @@ #include -#include +#include + +std::filesystem::path GetResourceDir(); SCENARIO("SoundEmitter", "[AUDIO][SOUNDEMITTER]") { @@ -9,7 +11,7 @@ SCENARIO("SoundEmitter", "[AUDIO][SOUNDEMITTER]") WHEN("We load our sound") { - REQUIRE(sound.LoadFromFile("resources/Engine/Audio/Cat.flac")); + REQUIRE(sound.LoadFromFile(GetResourceDir() / "Engine/Audio/Cat.flac")); THEN("We can ask information about position and velocity") { diff --git a/tests/Engine/Audio/Sound.cpp b/tests/Engine/Audio/SoundTest.cpp similarity index 77% rename from tests/Engine/Audio/Sound.cpp rename to tests/Engine/Audio/SoundTest.cpp index ec0f655b4..998f9f249 100644 --- a/tests/Engine/Audio/Sound.cpp +++ b/tests/Engine/Audio/SoundTest.cpp @@ -1,9 +1,11 @@ #include #include -#include +#include #include #include +std::filesystem::path GetResourceDir(); + SCENARIO("Sound", "[AUDIO][SOUND]") { GIVEN("A sound") @@ -12,13 +14,13 @@ SCENARIO("Sound", "[AUDIO][SOUND]") WHEN("We load our sound") { - REQUIRE(sound.LoadFromFile("resources/Engine/Audio/Cat.flac")); + REQUIRE(sound.LoadFromFile(GetResourceDir() / "Engine/Audio/Cat.flac")); THEN("We can ask the informations of the file") { REQUIRE(sound.GetDuration() <= 8500); // 8s = 8000ms REQUIRE(sound.GetDuration() >= 8000); - REQUIRE(sound.GetStatus() == Nz::SoundStatus_Stopped); + REQUIRE(sound.GetStatus() == Nz::SoundStatus::Stopped); REQUIRE(sound.IsLooping() == false); } @@ -32,7 +34,7 @@ SCENARIO("Sound", "[AUDIO][SOUND]") std::this_thread::sleep_for(std::chrono::milliseconds(200)); REQUIRE(sound.GetPlayingOffset() <= 1300); sound.Pause(); - REQUIRE(sound.GetStatus() == Nz::SoundStatus_Paused); + REQUIRE(sound.GetStatus() == Nz::SoundStatus::Paused); sound.SetPlayingOffset(3500); REQUIRE(sound.GetPlayingOffset() >= 3500); diff --git a/tests/Engine/Core/AbstractHash.cpp b/tests/Engine/Core/AbstractHashTest.cpp similarity index 91% rename from tests/Engine/Core/AbstractHash.cpp rename to tests/Engine/Core/AbstractHashTest.cpp index a2b4f49e1..1b3d40476 100644 --- a/tests/Engine/Core/AbstractHash.cpp +++ b/tests/Engine/Core/AbstractHashTest.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include @@ -9,7 +9,7 @@ SCENARIO("AbstractHash", "[CORE][ABSTRACTHASH]") { GIVEN("The hash SHA512") { - std::unique_ptr SHA512 = Nz::AbstractHash::Get(Nz::HashType_SHA512); + std::unique_ptr SHA512 = Nz::AbstractHash::Get(Nz::HashType::SHA512); SHA512->Begin(); WHEN("We introduce data") diff --git a/tests/Engine/Core/AlgorithmCore.cpp b/tests/Engine/Core/AlgorithmCoreTest.cpp similarity index 77% rename from tests/Engine/Core/AlgorithmCore.cpp rename to tests/Engine/Core/AlgorithmCoreTest.cpp index cdc07db90..0e4561bf8 100644 --- a/tests/Engine/Core/AlgorithmCore.cpp +++ b/tests/Engine/Core/AlgorithmCoreTest.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include TEST_CASE("Apply", "[CORE][ALGORITHM]") { @@ -32,61 +32,61 @@ TEST_CASE("ComputeHash", "[CORE][ALGORITHM]") { /*SECTION("Compute CRC32 of '1234'") { - auto result = Nz::ComputeHash(Nz::HashType_CRC32, "1234"); + auto result = Nz::ComputeHash(Nz::HashType::CRC32, "1234"); REQUIRE(Nz::ToUpper(result.ToHex()) == "596A3B55"); } SECTION("Compute CRC64 of '1234'") { - auto result = Nz::ComputeHash(Nz::HashType_CRC64, "1234"); + auto result = Nz::ComputeHash(Nz::HashType::CRC64, "1234"); REQUIRE(Nz::ToUpper(result.ToHex()) == "33302B9FC23855A8"); } SECTION("Compute Fletcher16 of '1234'") { - auto result = Nz::ComputeHash(Nz::HashType_Fletcher16, "1234"); + auto result = Nz::ComputeHash(Nz::HashType::Fletcher16, "1234"); REQUIRE(Nz::ToUpper(result.ToHex()) == "F5CA"); }*/ SECTION("Compute MD5 of '1234'") { - auto result = Nz::ComputeHash(Nz::HashType_MD5, "1234"); + auto result = Nz::ComputeHash(Nz::HashType::MD5, "1234"); REQUIRE(Nz::ToUpper(result.ToHex()) == "81DC9BDB52D04DC20036DBD8313ED055"); } SECTION("Compute SHA1 of '1234'") { - auto result = Nz::ComputeHash(Nz::HashType_SHA1, "1234"); + auto result = Nz::ComputeHash(Nz::HashType::SHA1, "1234"); REQUIRE(Nz::ToUpper(result.ToHex()) == "7110EDA4D09E062AA5E4A390B0A572AC0D2C0220"); } SECTION("Compute SHA224 of '1234'") { - auto result = Nz::ComputeHash(Nz::HashType_SHA224, "1234"); + auto result = Nz::ComputeHash(Nz::HashType::SHA224, "1234"); REQUIRE(Nz::ToUpper(result.ToHex()) == "99FB2F48C6AF4761F904FC85F95EB56190E5D40B1F44EC3A9C1FA319"); } SECTION("Compute SHA256 of '1234'") { - auto result = Nz::ComputeHash(Nz::HashType_SHA256, "1234"); + auto result = Nz::ComputeHash(Nz::HashType::SHA256, "1234"); REQUIRE(Nz::ToUpper(result.ToHex()) == "03AC674216F3E15C761EE1A5E255F067953623C8B388B4459E13F978D7C846F4"); } SECTION("Compute SHA384 of '1234'") { - auto result = Nz::ComputeHash(Nz::HashType_SHA384, "1234"); + auto result = Nz::ComputeHash(Nz::HashType::SHA384, "1234"); REQUIRE(Nz::ToUpper(result.ToHex()) == "504F008C8FCF8B2ED5DFCDE752FC5464AB8BA064215D9C5B5FC486AF3D9AB8C81B14785180D2AD7CEE1AB792AD44798C"); } SECTION("Compute SHA512 of '1234'") { - auto result = Nz::ComputeHash(Nz::HashType_SHA512, "1234"); + auto result = Nz::ComputeHash(Nz::HashType::SHA512, "1234"); REQUIRE(Nz::ToUpper(result.ToHex()) == "D404559F602EAB6FD602AC7680DACBFAADD13630335E951F097AF3900E9DE176B6DB28512F2E000B9D04FBA5133E8B1C6E8DF59DB3A8AB9D60BE4B97CC9E81DB"); } SECTION("Compute Whirlpool of '1234'") { - auto result = Nz::ComputeHash(Nz::HashType_Whirlpool, "1234"); + auto result = Nz::ComputeHash(Nz::HashType::Whirlpool, "1234"); REQUIRE(Nz::ToUpper(result.ToHex()) == "2F9959B230A44678DD2DC29F037BA1159F233AA9AB183CE3A0678EAAE002E5AA6F27F47144A1A4365116D3DB1B58EC47896623B92D85CB2F191705DAF11858B8"); } } diff --git a/tests/Engine/Core/Bitset.cpp b/tests/Engine/Core/BitsetTest.cpp similarity index 99% rename from tests/Engine/Core/Bitset.cpp rename to tests/Engine/Core/BitsetTest.cpp index 7d5c17d6f..8c4984202 100644 --- a/tests/Engine/Core/Bitset.cpp +++ b/tests/Engine/Core/BitsetTest.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include #include diff --git a/tests/Engine/Core/ByteArray.cpp b/tests/Engine/Core/ByteArrayTest.cpp similarity index 99% rename from tests/Engine/Core/ByteArray.cpp rename to tests/Engine/Core/ByteArrayTest.cpp index d7bf4cf3c..10f5eefdd 100644 --- a/tests/Engine/Core/ByteArray.cpp +++ b/tests/Engine/Core/ByteArrayTest.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include diff --git a/tests/Engine/Core/ByteStream.cpp b/tests/Engine/Core/ByteStreamTest.cpp similarity index 93% rename from tests/Engine/Core/ByteStream.cpp rename to tests/Engine/Core/ByteStreamTest.cpp index c948a6ec5..461054ec0 100644 --- a/tests/Engine/Core/ByteStream.cpp +++ b/tests/Engine/Core/ByteStreamTest.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include @@ -44,7 +44,7 @@ SCENARIO("ByteStream", "[CORE][BYTESTREAM]") Nz::ByteArray byteArray(numberOfBytes); Nz::ByteStream byteStream(&byteArray); - byteStream.SetDataEndianness(Nz::GetPlatformEndianness() == Nz::Endianness_BigEndian ? Nz::Endianness_LittleEndian : Nz::Endianness_BigEndian); + byteStream.SetDataEndianness(Nz::GetPlatformEndianness() == Nz::Endianness::BigEndian ? Nz::Endianness::LittleEndian : Nz::Endianness::BigEndian); WHEN("We write an integer") { diff --git a/tests/Engine/Core/Clock.cpp b/tests/Engine/Core/ClockTest.cpp similarity index 97% rename from tests/Engine/Core/Clock.cpp rename to tests/Engine/Core/ClockTest.cpp index 4e62996f1..9bef540b6 100644 --- a/tests/Engine/Core/Clock.cpp +++ b/tests/Engine/Core/ClockTest.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include diff --git a/tests/Engine/Core/Color.cpp b/tests/Engine/Core/ColorTest.cpp similarity index 99% rename from tests/Engine/Core/Color.cpp rename to tests/Engine/Core/ColorTest.cpp index 95669d382..ffb3854fa 100644 --- a/tests/Engine/Core/Color.cpp +++ b/tests/Engine/Core/ColorTest.cpp @@ -1,5 +1,5 @@ #include -#include +#include const float epsilon = 1.f; diff --git a/tests/Engine/Core/Error.cpp b/tests/Engine/Core/Error.cpp deleted file mode 100644 index e95f6d990..000000000 --- a/tests/Engine/Core/Error.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include - -SCENARIO("Error", "[CORE][ERROR]") -{ - Nz::UInt32 oldFlags = Nz::Error::GetFlags(); - - GIVEN("Multiple errors") - { - WHEN("Calling to error") - { - THEN("These errors should be written in the log file") - { - Nz::Error::Trigger(Nz::ErrorType_Internal, "ErrorType_Internal"); - Nz::Error::Trigger(Nz::ErrorType_Internal, "ErrorType_Internal", 2, "Error.cpp", "2nd place Internal"); - REQUIRE("ErrorType_Internal" == Nz::Error::GetLastError()); - Nz::Error::Trigger(Nz::ErrorType_Normal, "ErrorType_Normal"); - Nz::Error::Trigger(Nz::ErrorType_Normal, "ErrorType_Normal", 2, "Error.cpp", "2nd place Normal"); - REQUIRE("ErrorType_Normal" == Nz::Error::GetLastError()); - Nz::Error::Trigger(Nz::ErrorType_Warning, "ErrorType_Warning"); - Nz::Error::Trigger(Nz::ErrorType_Warning, "ErrorType_Warning", 2, "Error.cpp", "2nd place Warning"); - REQUIRE("ErrorType_Warning" == Nz::Error::GetLastError()); - } - } - } - - Nz::Error::SetFlags(oldFlags); -} diff --git a/tests/Engine/Core/ErrorTest.cpp b/tests/Engine/Core/ErrorTest.cpp new file mode 100644 index 000000000..fb9cfd868 --- /dev/null +++ b/tests/Engine/Core/ErrorTest.cpp @@ -0,0 +1,28 @@ +#include +#include + +SCENARIO("Error", "[CORE][ERROR]") +{ + Nz::ErrorModeFlags oldFlags = Nz::Error::GetFlags(); + + GIVEN("Multiple errors") + { + WHEN("Calling to error") + { + THEN("These errors should be written in the log file") + { + Nz::Error::Trigger(Nz::ErrorType::Internal, "ErrorType::Internal"); + Nz::Error::Trigger(Nz::ErrorType::Internal, "ErrorType::Internal", 2, "Error.cpp", "2nd place Internal"); + REQUIRE("ErrorType::Internal" == Nz::Error::GetLastError()); + Nz::Error::Trigger(Nz::ErrorType::Normal, "ErrorType::Normal"); + Nz::Error::Trigger(Nz::ErrorType::Normal, "ErrorType::Normal", 2, "Error.cpp", "2nd place Normal"); + REQUIRE("ErrorType::Normal" == Nz::Error::GetLastError()); + Nz::Error::Trigger(Nz::ErrorType::Warning, "ErrorType::Warning"); + Nz::Error::Trigger(Nz::ErrorType::Warning, "ErrorType::Warning", 2, "Error.cpp", "2nd place Warning"); + REQUIRE("ErrorType::Warning" == Nz::Error::GetLastError()); + } + } + } + + Nz::Error::SetFlags(oldFlags); +} diff --git a/tests/Engine/Core/File.cpp b/tests/Engine/Core/FileTest.cpp similarity index 85% rename from tests/Engine/Core/File.cpp rename to tests/Engine/Core/FileTest.cpp index cc3fa6661..fb915b768 100644 --- a/tests/Engine/Core/File.cpp +++ b/tests/Engine/Core/FileTest.cpp @@ -1,5 +1,7 @@ #include -#include +#include + +std::filesystem::path GetResourceDir(); SCENARIO("File", "[CORE][FILE]") { @@ -63,9 +65,9 @@ SCENARIO("File", "[CORE][FILE]") GIVEN("The test file") { - REQUIRE(std::filesystem::exists("resources/Engine/Core/FileTest.txt")); + REQUIRE(std::filesystem::exists(GetResourceDir() / "Engine/Core/FileTest.txt")); - Nz::File fileTest("resources/Engine/Core/FileTest.txt", Nz::OpenMode_ReadOnly | Nz::OpenMode_Text); + Nz::File fileTest(GetResourceDir() / "Engine/Core/FileTest.txt", Nz::OpenMode::ReadOnly | Nz::OpenMode::Text); WHEN("We read the first line of the file") { diff --git a/tests/Engine/Core/MemoryPool.cpp b/tests/Engine/Core/MemoryPoolTest.cpp similarity index 97% rename from tests/Engine/Core/MemoryPool.cpp rename to tests/Engine/Core/MemoryPoolTest.cpp index 2cd90a9dc..41987e45b 100644 --- a/tests/Engine/Core/MemoryPool.cpp +++ b/tests/Engine/Core/MemoryPoolTest.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include diff --git a/tests/Engine/Core/ObjectHandle.cpp b/tests/Engine/Core/ObjectHandleTest.cpp similarity index 99% rename from tests/Engine/Core/ObjectHandle.cpp rename to tests/Engine/Core/ObjectHandleTest.cpp index cffce4ecd..90dda82f5 100644 --- a/tests/Engine/Core/ObjectHandle.cpp +++ b/tests/Engine/Core/ObjectHandleTest.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include struct ObjectHandle_Test : public Nz::HandledObject { diff --git a/tests/Engine/Core/ObjectRef.cpp b/tests/Engine/Core/ObjectRefTest.cpp similarity index 68% rename from tests/Engine/Core/ObjectRef.cpp rename to tests/Engine/Core/ObjectRefTest.cpp index e44e5f1ff..232af9075 100644 --- a/tests/Engine/Core/ObjectRef.cpp +++ b/tests/Engine/Core/ObjectRefTest.cpp @@ -1,20 +1,22 @@ #include -#include +#include -#include +class Test : public Nz::RefCounted +{ +}; SCENARIO("ObjectRef", "[CORE][OBJECTREF]") { GIVEN("A ObjectRef") { - Nz::ObjectRef objectRef; + Nz::ObjectRef objectRef; WHEN("We have two objectRef handling the same object") { - Nz::Font font; + Test test; - objectRef = &font; - Nz::ObjectRef otherRef(&font); + objectRef = &test; + Nz::ObjectRef otherRef(&test); THEN("Pointers the same") { @@ -27,11 +29,11 @@ SCENARIO("ObjectRef", "[CORE][OBJECTREF]") WHEN("We assign it to a simple font") { - Nz::Font font; + Test test; THEN("Release suppress the reference to the object") { - objectRef.Reset(&font); + objectRef.Reset(&test); objectRef.Release(); REQUIRE(!objectRef.IsValid()); diff --git a/tests/Engine/Core/ParameterList.cpp b/tests/Engine/Core/ParameterListTest.cpp similarity index 99% rename from tests/Engine/Core/ParameterList.cpp rename to tests/Engine/Core/ParameterListTest.cpp index 557d4e3e1..3480308f1 100644 --- a/tests/Engine/Core/ParameterList.cpp +++ b/tests/Engine/Core/ParameterListTest.cpp @@ -1,5 +1,5 @@ #include -#include +#include void nullAction(void*) { diff --git a/tests/Engine/Core/PrimitiveList.cpp b/tests/Engine/Core/PrimitiveListTest.cpp similarity index 69% rename from tests/Engine/Core/PrimitiveList.cpp rename to tests/Engine/Core/PrimitiveListTest.cpp index e0098a75e..062c16ba7 100644 --- a/tests/Engine/Core/PrimitiveList.cpp +++ b/tests/Engine/Core/PrimitiveListTest.cpp @@ -1,5 +1,5 @@ #include -#include +#include SCENARIO("PrimitiveList", "[CORE][PRIMITIVELIST]") { @@ -25,19 +25,19 @@ SCENARIO("PrimitiveList", "[CORE][PRIMITIVELIST]") THEN("The first one is the cubic sphere") { - REQUIRE(primitiveList(0).type == Nz::PrimitiveType_Sphere); - REQUIRE(primitiveList(0).sphere.type == Nz::SphereType_Cubic); + REQUIRE(primitiveList(0).type == Nz::PrimitiveType::Sphere); + REQUIRE(primitiveList(0).sphere.type == Nz::SphereType::Cubic); } THEN("The second one is the box") { - REQUIRE(primitiveList(1).type == Nz::PrimitiveType_Box); + REQUIRE(primitiveList(1).type == Nz::PrimitiveType::Box); } THEN("The third one is the ico sphere") { - REQUIRE(primitiveList(2).type == Nz::PrimitiveType_Sphere); - REQUIRE(primitiveList(2).sphere.type == Nz::SphereType_Ico); + REQUIRE(primitiveList(2).type == Nz::PrimitiveType::Sphere); + REQUIRE(primitiveList(2).sphere.type == Nz::SphereType::Ico); } } } diff --git a/tests/Engine/Core/RefCounted.cpp b/tests/Engine/Core/RefCountedTest.cpp similarity index 96% rename from tests/Engine/Core/RefCounted.cpp rename to tests/Engine/Core/RefCountedTest.cpp index 0201f0beb..3b0270d1b 100644 --- a/tests/Engine/Core/RefCounted.cpp +++ b/tests/Engine/Core/RefCountedTest.cpp @@ -1,5 +1,5 @@ #include -#include +#include SCENARIO("RefCounted", "[CORE][REFCOUNTED]") { diff --git a/tests/Engine/Core/Serialization.cpp b/tests/Engine/Core/SerializationTest.cpp similarity index 99% rename from tests/Engine/Core/Serialization.cpp rename to tests/Engine/Core/SerializationTest.cpp index 3aa3f86af..d36226c09 100644 --- a/tests/Engine/Core/Serialization.cpp +++ b/tests/Engine/Core/SerializationTest.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include SCENARIO("Serialization", "[CORE][SERIALIZATION]") { diff --git a/tests/Engine/Core/Signal.cpp b/tests/Engine/Core/SignalTest.cpp similarity index 96% rename from tests/Engine/Core/Signal.cpp rename to tests/Engine/Core/SignalTest.cpp index c5582d866..9c5726f91 100644 --- a/tests/Engine/Core/Signal.cpp +++ b/tests/Engine/Core/SignalTest.cpp @@ -1,5 +1,5 @@ #include -#include +#include struct Incrementer { diff --git a/tests/Engine/Core/SparsePtr.cpp b/tests/Engine/Core/SparsePtrTest.cpp similarity index 97% rename from tests/Engine/Core/SparsePtr.cpp rename to tests/Engine/Core/SparsePtrTest.cpp index e0a921129..d3c832a71 100644 --- a/tests/Engine/Core/SparsePtr.cpp +++ b/tests/Engine/Core/SparsePtrTest.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include diff --git a/tests/Engine/Core/StackVector.cpp b/tests/Engine/Core/StackVectorTest.cpp similarity index 99% rename from tests/Engine/Core/StackVector.cpp rename to tests/Engine/Core/StackVectorTest.cpp index ff66116da..e6d7afede 100644 --- a/tests/Engine/Core/StackVector.cpp +++ b/tests/Engine/Core/StackVectorTest.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/tests/Engine/Core/StringExt.cpp b/tests/Engine/Core/StringExtTest.cpp similarity index 99% rename from tests/Engine/Core/StringExt.cpp rename to tests/Engine/Core/StringExtTest.cpp index b952c90df..2612f36ee 100644 --- a/tests/Engine/Core/StringExt.cpp +++ b/tests/Engine/Core/StringExtTest.cpp @@ -1,5 +1,5 @@ #include -#include +#include SCENARIO("String", "[CORE][STRING]") { diff --git a/tests/Engine/Math/AlgorithmMath.cpp b/tests/Engine/Math/AlgorithmMathTest.cpp similarity index 86% rename from tests/Engine/Math/AlgorithmMath.cpp rename to tests/Engine/Math/AlgorithmMathTest.cpp index de21817f4..7881acf9a 100644 --- a/tests/Engine/Math/AlgorithmMath.cpp +++ b/tests/Engine/Math/AlgorithmMathTest.cpp @@ -1,5 +1,6 @@ #include -#include +#include +#include #include TEST_CASE("Approach", "[MATH][ALGORITHM]") @@ -208,62 +209,62 @@ TEST_CASE("NormalizeAngle", "[MATH][ALGORITHM]") { SECTION("-90 should be normalized to +270") { - REQUIRE(Nz::NormalizeAngle(Nz::FromDegrees(-90.f)) == Nz::FromDegrees(270.f)); + REQUIRE(Nz::DegreeAnglef(-90.f).Normalize() == Nz::DegreeAnglef(270.f)); } SECTION("-540 should be normalized to +180") { - REQUIRE(Nz::NormalizeAngle(Nz::FromDegrees(-540.f)) == Nz::FromDegrees(180.f)); + REQUIRE(Nz::DegreeAnglef(-540.f).Normalize() == Nz::DegreeAnglef(180.f)); } SECTION("0 should remain 0") { - REQUIRE(Nz::NormalizeAngle(Nz::FromDegrees(0.f)) == Nz::FromDegrees(0.f)); + REQUIRE(Nz::DegreeAnglef(0.f).Normalize() == Nz::DegreeAnglef(0.f)); } SECTION("90 should remain 90") { - REQUIRE(Nz::NormalizeAngle(Nz::FromDegrees(90.f)) == Nz::FromDegrees(90.f)); + REQUIRE(Nz::DegreeAnglef(90.f).Normalize() == Nz::DegreeAnglef(90.f)); } SECTION("360 should be normalized to 0") { - REQUIRE(Nz::NormalizeAngle(Nz::FromDegrees(360.f)) == Nz::FromDegrees(0.f)); + REQUIRE(Nz::DegreeAnglef(360.f).Normalize() == Nz::DegreeAnglef(0.f)); } SECTION("450 should be normalized to 90") { - REQUIRE(Nz::NormalizeAngle(Nz::FromDegrees(450.f)) == Nz::FromDegrees(90.f)); + REQUIRE(Nz::DegreeAnglef(450.f).Normalize() == Nz::DegreeAnglef(90.f)); } SECTION("-90 should be normalized to +270") { - REQUIRE(Nz::NormalizeAngle(Nz::FromDegrees(-90)) == Nz::FromDegrees(270)); + REQUIRE(Nz::DegreeAnglef(-90).Normalize() == Nz::DegreeAnglef(270)); } SECTION("-540 should be normalized to +180") { - REQUIRE(Nz::NormalizeAngle(Nz::FromDegrees(-540)) == Nz::FromDegrees(180)); + REQUIRE(Nz::DegreeAnglef(-540).Normalize() == Nz::DegreeAnglef(180)); } SECTION("0 should remain 0") { - REQUIRE(Nz::NormalizeAngle(Nz::FromDegrees(0)) == Nz::FromDegrees(0)); + REQUIRE(Nz::DegreeAnglef(0).Normalize() == Nz::DegreeAnglef(0)); } SECTION("90 should remain 90") { - REQUIRE(Nz::NormalizeAngle(Nz::FromDegrees(90)) == Nz::FromDegrees(90)); + REQUIRE(Nz::DegreeAnglef(90).Normalize() == Nz::DegreeAnglef(90)); } SECTION("360 should be normalized to 0") { - REQUIRE(Nz::NormalizeAngle(Nz::FromDegrees(360)) == Nz::FromDegrees(0)); + REQUIRE(Nz::DegreeAnglef(360).Normalize() == Nz::DegreeAnglef(0)); } SECTION("450 should be normalized to 90") { - REQUIRE(Nz::NormalizeAngle(Nz::FromDegrees(450)) == Nz::FromDegrees(90)); + REQUIRE(Nz::DegreeAnglef(450).Normalize() == Nz::DegreeAnglef(90)); } } diff --git a/tests/Engine/Math/Angle.cpp b/tests/Engine/Math/AngleTest.cpp similarity index 99% rename from tests/Engine/Math/Angle.cpp rename to tests/Engine/Math/AngleTest.cpp index 7eddb3d3e..b0df420ef 100644 --- a/tests/Engine/Math/Angle.cpp +++ b/tests/Engine/Math/AngleTest.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include SCENARIO("Angle", "[MATH][ANGLE]") { diff --git a/tests/Engine/Math/BoundingVolume.cpp b/tests/Engine/Math/BoundingVolumeTest.cpp similarity index 99% rename from tests/Engine/Math/BoundingVolume.cpp rename to tests/Engine/Math/BoundingVolumeTest.cpp index a8213b09e..8762e9047 100644 --- a/tests/Engine/Math/BoundingVolume.cpp +++ b/tests/Engine/Math/BoundingVolumeTest.cpp @@ -1,5 +1,5 @@ #include -#include +#include SCENARIO("BoundingVolume", "[MATH][BOUNDINGVOLUME]") { diff --git a/tests/Engine/Math/Box.cpp b/tests/Engine/Math/BoxTest.cpp similarity index 99% rename from tests/Engine/Math/Box.cpp rename to tests/Engine/Math/BoxTest.cpp index ade117515..8052630e7 100644 --- a/tests/Engine/Math/Box.cpp +++ b/tests/Engine/Math/BoxTest.cpp @@ -1,5 +1,5 @@ #include -#include +#include SCENARIO("Box", "[MATH][BOX]") { diff --git a/tests/Engine/Math/EulerAngles.cpp b/tests/Engine/Math/EulerAnglesTest.cpp similarity index 59% rename from tests/Engine/Math/EulerAngles.cpp rename to tests/Engine/Math/EulerAnglesTest.cpp index 01bfaecff..ede4a07b6 100644 --- a/tests/Engine/Math/EulerAngles.cpp +++ b/tests/Engine/Math/EulerAnglesTest.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include SCENARIO("EulerAngles", "[MATH][EULERANGLES]") { @@ -16,8 +16,8 @@ SCENARIO("EulerAngles", "[MATH][EULERANGLES]") WHEN("We do some operations") { - Nz::EulerAnglesf euler90(Nz::FromDegrees(90.f), Nz::FromDegrees(90.f), Nz::FromDegrees(90.f)); - Nz::EulerAnglesf euler270(Nz::FromDegrees(270.f), Nz::FromDegrees(270.f), Nz::FromDegrees(270.f)); + Nz::EulerAnglesf euler90(Nz::DegreeAnglef(90.f), Nz::DegreeAnglef(90.f), Nz::DegreeAnglef(90.f)); + Nz::EulerAnglesf euler270(Nz::DegreeAnglef(270.f), Nz::DegreeAnglef(270.f), Nz::DegreeAnglef(270.f)); Nz::EulerAnglesf euler360 = euler90 + euler270; euler360.Normalize(); @@ -45,9 +45,9 @@ SCENARIO("EulerAngles", "[MATH][EULERANGLES]") GIVEN("Three rotation of 90 on each axis") { - Nz::EulerAnglesf euler90P(Nz::FromDegrees(90.f), 0.f, 0.f); - Nz::EulerAnglesf euler90Y(0.f, Nz::FromDegrees(90.f), 0.f); - Nz::EulerAnglesf euler90R(0.f, 0.f, Nz::FromDegrees(90.f)); + Nz::EulerAnglesf euler90P(Nz::DegreeAnglef(90.f), 0.f, 0.f); + Nz::EulerAnglesf euler90Y(0.f, Nz::DegreeAnglef(90.f), 0.f); + Nz::EulerAnglesf euler90R(0.f, 0.f, Nz::DegreeAnglef(90.f)); WHEN("We transform the axis") { @@ -70,37 +70,37 @@ SCENARIO("EulerAngles", "[MATH][EULERANGLES]") { THEN("These results are expected") { - CHECK(Nz::EulerAngles(Nz::FromDegrees(45.f), 0.f, 0.f) == Nz::EulerAngles(Nz::Quaternionf(0.923879504204f, 0.382683455944f, 0.f, 0.f).ToEulerAngles())); - CHECK(Nz::EulerAngles(0.f, Nz::FromDegrees(45.f), 0.f) == Nz::EulerAngles(Nz::Quaternionf(0.923879504204f, 0.f, 0.382683455944f, 0.f).ToEulerAngles())); - CHECK(Nz::EulerAngles(0.f, 0.f, Nz::FromDegrees(45.f)) == Nz::EulerAngles(Nz::Quaternionf(0.923879504204f, 0.f, 0.f, 0.382683455944f).ToEulerAngles())); + CHECK(Nz::EulerAnglesf(Nz::DegreeAnglef(45.f), 0.f, 0.f) == Nz::EulerAnglesf(Nz::Quaternionf(0.923879504204f, 0.382683455944f, 0.f, 0.f).ToEulerAngles())); + CHECK(Nz::EulerAnglesf(0.f, Nz::DegreeAnglef(45.f), 0.f) == Nz::EulerAnglesf(Nz::Quaternionf(0.923879504204f, 0.f, 0.382683455944f, 0.f).ToEulerAngles())); + CHECK(Nz::EulerAnglesf(0.f, 0.f, Nz::DegreeAnglef(45.f)) == Nz::EulerAnglesf(Nz::Quaternionf(0.923879504204f, 0.f, 0.f, 0.382683455944f).ToEulerAngles())); } } } GIVEN("Three euler angles: (0, 22.5, 22.5), (90, 90, 0) and (30, 0, 30)") { - Nz::EulerAnglesf euler45(Nz::FromDegrees(0.f), Nz::FromDegrees(22.5f), Nz::FromDegrees(22.5f)); - Nz::EulerAnglesf euler90(Nz::FromDegrees(90.f), Nz::FromDegrees(90.f), Nz::FromDegrees(0.f)); - Nz::EulerAnglesf euler30(Nz::FromDegrees(30.f), Nz::FromDegrees(0.f), Nz::FromDegrees(30.f)); + Nz::EulerAnglesf euler45(Nz::DegreeAnglef(0.f), Nz::DegreeAnglef(22.5f), Nz::DegreeAnglef(22.5f)); + Nz::EulerAnglesf euler90(Nz::DegreeAnglef(90.f), Nz::DegreeAnglef(90.f), Nz::DegreeAnglef(0.f)); + Nz::EulerAnglesf euler30(Nz::DegreeAnglef(30.f), Nz::DegreeAnglef(0.f), Nz::DegreeAnglef(30.f)); WHEN("We convert them to quaternion") { THEN("And then convert to euler angles, we have identity") { Nz::EulerAnglesf tmp = Nz::Quaternionf(euler45.ToQuaternion()).ToEulerAngles(); - CHECK(tmp.pitch == Approx(0.f)); - CHECK(tmp.yaw == Approx(22.5f)); - CHECK(tmp.roll == Approx(22.5f)); + CHECK(tmp.pitch.ToDegrees() == Approx(0.f)); + CHECK(tmp.yaw.ToDegrees() == Approx(22.5f)); + CHECK(tmp.roll.ToDegrees() == Approx(22.5f)); tmp = Nz::Quaternionf(euler90.ToQuaternion()).ToEulerAngles(); - CHECK(tmp.pitch == Approx(90.f)); - CHECK(tmp.yaw == Approx(90.f)); - CHECK(tmp.roll == Approx(0.f)); + CHECK(tmp.pitch.ToDegrees() == Approx(90.f)); + CHECK(tmp.yaw.ToDegrees() == Approx(90.f)); + CHECK(tmp.roll.ToDegrees() == Approx(0.f)); tmp = Nz::Quaternionf(euler30.ToQuaternion()).ToEulerAngles(); - CHECK(tmp.pitch == Approx(30.f)); - CHECK(tmp.yaw == Approx(0.f).margin(0.0001f)); - CHECK(tmp.roll == Approx(30.f)); + CHECK(tmp.pitch.ToDegrees() == Approx(30.f)); + CHECK(tmp.yaw.ToDegrees() == Approx(0.f).margin(0.0001f)); + CHECK(tmp.roll.ToDegrees() == Approx(30.f)); } } } diff --git a/tests/Engine/Math/Frustum.cpp b/tests/Engine/Math/FrustumTest.cpp similarity index 96% rename from tests/Engine/Math/Frustum.cpp rename to tests/Engine/Math/FrustumTest.cpp index d9fedebdd..1175b95a4 100644 --- a/tests/Engine/Math/Frustum.cpp +++ b/tests/Engine/Math/FrustumTest.cpp @@ -1,12 +1,12 @@ #include -#include +#include SCENARIO("Frustum", "[MATH][FRUSTUM]") { GIVEN("One frustum (90, 1, 1, 1000, (0, 0, 0), (1, 0, 0))") { Nz::Frustumf frustum; - frustum.Build(Nz::FromDegrees(90.f), 1.f, 1.f, 1000.f, Nz::Vector3f::Zero(), Nz::Vector3f::UnitX()); + frustum.Build(Nz::DegreeAnglef(90.f), 1.f, 1.f, 1000.f, Nz::Vector3f::Zero(), Nz::Vector3f::UnitX()); WHEN("We ask for intersection with objects outside the frustum") { diff --git a/tests/Engine/Math/Matrix4.cpp b/tests/Engine/Math/Matrix4Test.cpp similarity index 88% rename from tests/Engine/Math/Matrix4.cpp rename to tests/Engine/Math/Matrix4Test.cpp index ca4760e7b..a1e57e3ea 100644 --- a/tests/Engine/Math/Matrix4.cpp +++ b/tests/Engine/Math/Matrix4Test.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include @@ -102,42 +102,42 @@ SCENARIO("Matrix4", "[MATH][MATRIX4]") { THEN("Rotation around X") { - transformedMatrix.MakeTransform(Nz::Vector3f::Zero(), Nz::EulerAnglesf(Nz::FromDegrees(45.f), 0.f, 0.f).ToQuaternion()); + transformedMatrix.MakeTransform(Nz::Vector3f::Zero(), Nz::EulerAnglesf(Nz::DegreeAnglef(45.f), 0.f, 0.f).ToQuaternion()); Nz::Matrix4f rotation45X(1.f, 0.f, 0.f, 0.f, 0.f, std::sqrt(2.f) / 2.f, std::sqrt(2.f) / 2.f, 0.f, 0.f, -std::sqrt(2.f) / 2.f, std::sqrt(2.f) / 2.f, 0.f, 0.f, 0.f, 0.f, 1.f); CHECK(transformedMatrix == rotation45X); - transformedMatrix.MakeTransform(Nz::Vector3f::Unit(), Nz::EulerAnglesf(Nz::FromDegrees(45.f), 0.f, 0.f).ToQuaternion()); + transformedMatrix.MakeTransform(Nz::Vector3f::Unit(), Nz::EulerAnglesf(Nz::DegreeAnglef(45.f), 0.f, 0.f).ToQuaternion()); rotation45X.ApplyTranslation(Nz::Vector3f::Unit()); CHECK(transformedMatrix == rotation45X); } THEN("Rotation around Y") { - transformedMatrix.MakeTransform(Nz::Vector3f::Zero(), Nz::EulerAnglesf(0.f, Nz::FromDegrees(45.f), 0.f).ToQuaternion()); + transformedMatrix.MakeTransform(Nz::Vector3f::Zero(), Nz::EulerAnglesf(0.f, Nz::DegreeAnglef(45.f), 0.f).ToQuaternion()); Nz::Matrix4f rotation45Y(std::sqrt(2.f) / 2.f, 0.f, -std::sqrt(2.f) / 2.f, 0.f, 0.f, 1.f, 0.f, 0.f, std::sqrt(2.f) / 2.f, 0.f, std::sqrt(2.f) / 2.f, 0.f, 0.f, 0.f, 0.f, 1.f); CHECK(transformedMatrix == rotation45Y); - transformedMatrix.MakeTransform(Nz::Vector3f::Unit(), Nz::EulerAnglesf(0.f, Nz::FromDegrees(45.f), 0.f).ToQuaternion()); + transformedMatrix.MakeTransform(Nz::Vector3f::Unit(), Nz::EulerAnglesf(0.f, Nz::DegreeAnglef(45.f), 0.f).ToQuaternion()); rotation45Y.ApplyTranslation(Nz::Vector3f::Unit()); CHECK(transformedMatrix == rotation45Y); } THEN("Rotation around Z") { - transformedMatrix.MakeTransform(Nz::Vector3f::Zero(), Nz::EulerAnglesf(0.f, 0.f, Nz::FromDegrees(45.f)).ToQuaternion()); + transformedMatrix.MakeTransform(Nz::Vector3f::Zero(), Nz::EulerAnglesf(0.f, 0.f, Nz::DegreeAnglef(45.f)).ToQuaternion()); Nz::Matrix4f rotation45Z( std::sqrt(2.f) / 2.f, std::sqrt(2.f) / 2.f, 0.f, 0.f, -std::sqrt(2.f) / 2.f, std::sqrt(2.f) / 2.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f); CHECK(transformedMatrix == rotation45Z); - transformedMatrix.MakeTransform(Nz::Vector3f::Unit(), Nz::EulerAnglesf(Nz::EulerAnglesf(0.f, 0.f, Nz::FromDegrees(45.f)).ToQuaternion())); + transformedMatrix.MakeTransform(Nz::Vector3f::Unit(), Nz::EulerAnglesf(Nz::EulerAnglesf(0.f, 0.f, Nz::DegreeAnglef(45.f)).ToQuaternion())); rotation45Z.ApplyTranslation(Nz::Vector3f::Unit()); CHECK(transformedMatrix == rotation45Z); } @@ -157,7 +157,7 @@ SCENARIO("Matrix4", "[MATH][MATRIX4]") WHEN("We rotate it from pitch 30") { - Nz::Quaternionf rotation(Nz::EulerAnglesf(Nz::FromDegrees(30.f), 0.f, 0.f)); + Nz::Quaternionf rotation(Nz::EulerAnglesf(Nz::DegreeAnglef(30.f), 0.f, 0.f)); identity.ApplyRotation(rotation); THEN("We should retrieve it") @@ -168,7 +168,7 @@ SCENARIO("Matrix4", "[MATH][MATRIX4]") WHEN("We rotate it from yaw 30") { - Nz::Quaternionf rotation(Nz::EulerAnglesf(0.f, Nz::FromDegrees(30.f), 0.f)); + Nz::Quaternionf rotation(Nz::EulerAnglesf(0.f, Nz::DegreeAnglef(30.f), 0.f)); identity.ApplyRotation(rotation); THEN("We should retrieve it") @@ -179,7 +179,7 @@ SCENARIO("Matrix4", "[MATH][MATRIX4]") WHEN("We rotate it from roll 30") { - Nz::Quaternionf rotation(Nz::EulerAnglesf(0.f, 0.f, Nz::FromDegrees(30.f))); + Nz::Quaternionf rotation(Nz::EulerAnglesf(0.f, 0.f, Nz::DegreeAnglef(30.f))); identity.ApplyRotation(rotation); THEN("We should retrieve it") @@ -190,7 +190,7 @@ SCENARIO("Matrix4", "[MATH][MATRIX4]") WHEN("We rotate it from a strange rotation") { - Nz::Quaternionf rotation(Nz::EulerAnglesf(Nz::FromDegrees(10.f), Nz::FromDegrees(20.f), Nz::FromDegrees(30.f))); + Nz::Quaternionf rotation(Nz::EulerAnglesf(Nz::DegreeAnglef(10.f), Nz::DegreeAnglef(20.f), Nz::DegreeAnglef(30.f))); identity.ApplyRotation(rotation); THEN("We should retrieve it") @@ -213,7 +213,7 @@ SCENARIO("Matrix4", "[MATH][MATRIX4]") AND_THEN("With a rotation") { - identity.ApplyRotation(Nz::EulerAnglesf(Nz::FromDegrees(10.f), Nz::FromDegrees(20.f), Nz::FromDegrees(30.f))); + identity.ApplyRotation(Nz::EulerAnglesf(Nz::DegreeAnglef(10.f), Nz::DegreeAnglef(20.f), Nz::DegreeAnglef(30.f))); Nz::Vector3f retrievedScale = identity.GetScale(); CHECK(retrievedScale.x == Approx(scale.x)); CHECK(retrievedScale.y == Approx(scale.y)); @@ -248,12 +248,12 @@ SCENARIO("Matrix4", "[MATH][MATRIX4]") Nz::Matrix4f simple = Nz::Matrix4f::Transform(simpleTranslation, simpleRotation, simpleScale); Nz::Vector3f complexTranslation = Nz::Vector3f(-5.f, 7.f, 3.5f); - Nz::Quaternionf complexRotation = Nz::EulerAnglesf(Nz::FromDegrees(-22.5f), Nz::FromDegrees(30.f), Nz::FromDegrees(15.f)); + Nz::Quaternionf complexRotation = Nz::EulerAnglesf(Nz::DegreeAnglef(-22.5f), Nz::DegreeAnglef(30.f), Nz::DegreeAnglef(15.f)); Nz::Vector3f complexScale = Nz::Vector3f(1.f, 2.f, 0.5f); Nz::Matrix4f complex = Nz::Matrix4f::Transform(complexTranslation, complexRotation, complexScale); Nz::Vector3f oppositeTranslation = Nz::Vector3f(-5.f, 7.f, 3.5f); - Nz::Quaternionf oppositeRotation = Nz::EulerAnglesf(Nz::FromDegrees(-90.f), Nz::FromDegrees(0.f), Nz::FromDegrees(0.f)); + Nz::Quaternionf oppositeRotation = Nz::EulerAnglesf(Nz::DegreeAnglef(-90.f), Nz::DegreeAnglef(0.f), Nz::DegreeAnglef(0.f)); Nz::Vector3f oppositeScale = Nz::Vector3f(1.f, 2.f, 0.5f); Nz::Matrix4f opposite = Nz::Matrix4f::Transform(oppositeTranslation, oppositeRotation, oppositeScale); @@ -280,7 +280,7 @@ SCENARIO("Matrix4", "[MATH][MATRIX4]") { Nz::Vector3f translation(-5.f, 3.f, 0.5); Nz::Matrix4f initial = Nz::Matrix4f::Translate(translation); - Nz::Quaternionf rotation = Nz::EulerAnglesf(Nz::FromDegrees(30.f), Nz::FromDegrees(-90.f), 0.f); + Nz::Quaternionf rotation = Nz::EulerAnglesf(Nz::DegreeAnglef(30.f), Nz::DegreeAnglef(-90.f), 0.f); initial.ApplyRotation(rotation); Nz::Matrix4f simple = Nz::Matrix4f::Transform(-translation, rotation.GetInverse(), Nz::Vector3f::Unit()); diff --git a/tests/Engine/Math/OrientedBox.cpp b/tests/Engine/Math/OrientedBoxTest.cpp similarity index 98% rename from tests/Engine/Math/OrientedBox.cpp rename to tests/Engine/Math/OrientedBoxTest.cpp index 7a1035ee2..d5bb84268 100644 --- a/tests/Engine/Math/OrientedBox.cpp +++ b/tests/Engine/Math/OrientedBoxTest.cpp @@ -1,5 +1,5 @@ #include -#include +#include SCENARIO("OrientedBox", "[MATH][ORIENTEDBOX]") { diff --git a/tests/Engine/Math/Plane.cpp b/tests/Engine/Math/PlaneTest.cpp similarity index 99% rename from tests/Engine/Math/Plane.cpp rename to tests/Engine/Math/PlaneTest.cpp index 44377bf67..2ea12724e 100644 --- a/tests/Engine/Math/Plane.cpp +++ b/tests/Engine/Math/PlaneTest.cpp @@ -1,5 +1,5 @@ #include -#include +#include SCENARIO("Plane", "[MATH][PLANE]") { diff --git a/tests/Engine/Math/Quaternion.cpp b/tests/Engine/Math/QuaternionTest.cpp similarity index 78% rename from tests/Engine/Math/Quaternion.cpp rename to tests/Engine/Math/QuaternionTest.cpp index 3cae63386..c43c9753a 100644 --- a/tests/Engine/Math/Quaternion.cpp +++ b/tests/Engine/Math/QuaternionTest.cpp @@ -1,11 +1,11 @@ #include -#include +#include SCENARIO("Quaternion", "[MATH][QUATERNION]") { GIVEN("Two quaternions (0, 1, 0, 0)") { - Nz::Quaternionf firstQuaternion(Nz::FromDegrees(180.f), Nz::Vector3f::UnitX()); + Nz::Quaternionf firstQuaternion(Nz::DegreeAnglef(180.f), Nz::Vector3f::UnitX()); Nz::Quaternionf secondQuaternion(0.f, 1.f, 0.f, 0.f); WHEN("We compare them") @@ -97,7 +97,7 @@ SCENARIO("Quaternion", "[MATH][QUATERNION]") GIVEN("Two different quaternions (10, (1, 0, 0) and (20, (1, 0, 0))") { - Nz::Quaternionf x10 = Nz::Quaternionf(Nz::FromDegrees(10.f), Nz::Vector3f::UnitX()); + Nz::Quaternionf x10 = Nz::Quaternionf(Nz::DegreeAnglef(10.f), Nz::Vector3f::UnitX()); Nz::Quaternionf x20 = x10 * x10; Nz::Quaternionf x30a = x10 * x20; @@ -107,16 +107,16 @@ SCENARIO("Quaternion", "[MATH][QUATERNION]") { THEN("These results are expected") { - REQUIRE(x20 == Nz::Quaternionf(Nz::FromDegrees(20.f), Nz::Vector3f::UnitX())); + REQUIRE(x20 == Nz::Quaternionf(Nz::DegreeAnglef(20.f), Nz::Vector3f::UnitX())); REQUIRE(x30a == x30b); } } WHEN("Convert euler to quaternion") { - Nz::Quaternionf X45(Nz::EulerAnglesf(Nz::FromDegrees(45.f), 0.f, 0.f)); - Nz::Quaternionf Y45(Nz::EulerAnglesf(0.f, Nz::FromDegrees(45.f), 0.f)); - Nz::Quaternionf Z45(Nz::EulerAnglesf(0.f, 0.f, Nz::FromDegrees(45.f))); + Nz::Quaternionf X45(Nz::EulerAnglesf(Nz::DegreeAnglef(45.f), 0.f, 0.f)); + Nz::Quaternionf Y45(Nz::EulerAnglesf(0.f, Nz::DegreeAnglef(45.f), 0.f)); + Nz::Quaternionf Z45(Nz::EulerAnglesf(0.f, 0.f, Nz::DegreeAnglef(45.f))); THEN("They must be equal") { @@ -159,11 +159,11 @@ SCENARIO("Quaternion", "[MATH][QUATERNION]") AND_THEN("The half of 45 is 22.5") { - Nz::Quaternionf quaterionA(Nz::FromDegrees(0.f), Nz::Vector3f::UnitZ()); - Nz::Quaternionf quaterionB(Nz::FromDegrees(45.f), Nz::Vector3f::UnitZ()); + Nz::Quaternionf quaterionA(Nz::DegreeAnglef(0.f), Nz::Vector3f::UnitZ()); + Nz::Quaternionf quaterionB(Nz::DegreeAnglef(45.f), Nz::Vector3f::UnitZ()); Nz::Quaternionf quaternionC = Nz::Quaternionf::Slerp(quaterionA, quaterionB, 0.5f); - Nz::Quaternionf unitZ225(Nz::FromDegrees(22.5f), Nz::Vector3f::UnitZ()); + Nz::Quaternionf unitZ225(Nz::DegreeAnglef(22.5f), Nz::Vector3f::UnitZ()); REQUIRE(quaternionC.w == Approx(unitZ225.w)); REQUIRE(quaternionC.x == Approx(unitZ225.x)); REQUIRE(quaternionC.y == Approx(unitZ225.y)); @@ -176,21 +176,21 @@ SCENARIO("Quaternion", "[MATH][QUATERNION]") THEN("The rotation in right-handed is 90 degree on z") { Nz::Quaternionf rotationBetweenXY = Nz::Quaternionf::RotationBetween(Nz::Vector3f::UnitX(), Nz::Vector3f::UnitY()); - Nz::Quaternionf rotation90Z(Nz::FromDegrees(90.f), Nz::Vector3f::UnitZ()); + Nz::Quaternionf rotation90Z(Nz::DegreeAnglef(90.f), Nz::Vector3f::UnitZ()); REQUIRE(rotation90Z == rotationBetweenXY); } THEN("The rotation in right-handed is 90 degree on y") { Nz::Quaternionf rotationBetweenXZ = Nz::Quaternionf::RotationBetween(Nz::Vector3f::UnitX(), Nz::Vector3f::UnitZ()); - Nz::Quaternionf rotation90Y(Nz::FromDegrees(-90.f), Nz::Vector3f::UnitY()); + Nz::Quaternionf rotation90Y(Nz::DegreeAnglef(-90.f), Nz::Vector3f::UnitY()); REQUIRE(rotation90Y == rotationBetweenXZ); } THEN("The rotation in right-handed is 90 degree on x") { Nz::Quaternionf rotationBetweenYZ = Nz::Quaternionf::RotationBetween(Nz::Vector3f::UnitY(), Nz::Vector3f::UnitZ()); - Nz::Quaternionf rotation90X(Nz::FromDegrees(90.f), Nz::Vector3f::UnitX()); + Nz::Quaternionf rotation90X(Nz::DegreeAnglef(90.f), Nz::Vector3f::UnitX()); REQUIRE(rotation90X == rotationBetweenYZ); } @@ -224,21 +224,21 @@ SCENARIO("Quaternion", "[MATH][QUATERNION]") { THEN("Those are equal to") { - CHECK(Nz::NumberEquals(rotation90X.ToEulerAngles().pitch, Nz::FromDegrees(90.f), 0.1f)); - CHECK(Nz::NumberEquals(rotation90Y.ToEulerAngles().yaw, Nz::FromDegrees(90.f), 0.1f)); - CHECK(Nz::NumberEquals(rotation90Z.ToEulerAngles().roll, Nz::FromDegrees(90.f), 0.1f)); + CHECK(Nz::NumberEquals(rotation90X.ToEulerAngles().pitch.ToDegrees(), 90.f, 0.1f)); + CHECK(Nz::NumberEquals(rotation90Y.ToEulerAngles().yaw.ToDegrees(), 90.f, 0.1f)); + CHECK(Nz::NumberEquals(rotation90Z.ToEulerAngles().roll.ToDegrees(), 90.f, 0.1f)); CHECK(rotation180X == Nz::EulerAnglesf(180.f, 0.f, 0.f)); CHECK(rotation180Y == Nz::EulerAnglesf(0.f, 180.f, 0.f)); CHECK(rotation180Z == Nz::EulerAnglesf(0.f, 0.f, 180.f)); - CHECK(Nz::NumberEquals(rotation270X.ToEulerAngles().pitch, Nz::FromDegrees(-90.f), 0.1f)); - CHECK(Nz::NumberEquals(rotation270Y.ToEulerAngles().yaw, Nz::FromDegrees(-90.f), 0.1f)); - CHECK(Nz::NumberEquals(rotation270Z.ToEulerAngles().roll, Nz::FromDegrees(-90.f), 0.1f)); + CHECK(Nz::NumberEquals(rotation270X.ToEulerAngles().pitch.ToDegrees(), -90.f, 0.1f)); + CHECK(Nz::NumberEquals(rotation270Y.ToEulerAngles().yaw.ToDegrees(), -90.f, 0.1f)); + CHECK(Nz::NumberEquals(rotation270Z.ToEulerAngles().roll.ToDegrees(), -90.f, 0.1f)); - CHECK(Nz::NumberEquals(special.ToEulerAngles().pitch, Nz::FromDegrees(0.f), 0.1f)); - CHECK(Nz::NumberEquals(special.ToEulerAngles().yaw, Nz::FromDegrees(1.f), 0.1f)); - CHECK(Nz::NumberEquals(special.ToEulerAngles().roll, Nz::FromDegrees(90.f), 0.1f)); + CHECK(Nz::NumberEquals(special.ToEulerAngles().pitch.ToDegrees(), 0.f, 0.1f)); + CHECK(Nz::NumberEquals(special.ToEulerAngles().yaw.ToDegrees(), 1.f, 0.1f)); + CHECK(Nz::NumberEquals(special.ToEulerAngles().roll.ToDegrees(), 90.f, 0.1f)); } } } diff --git a/tests/Engine/Math/Ray.cpp b/tests/Engine/Math/RayTest.cpp similarity index 99% rename from tests/Engine/Math/Ray.cpp rename to tests/Engine/Math/RayTest.cpp index df1151f6d..6d39b936e 100644 --- a/tests/Engine/Math/Ray.cpp +++ b/tests/Engine/Math/RayTest.cpp @@ -1,5 +1,5 @@ #include -#include +#include SCENARIO("Ray", "[MATH][RAY]") { diff --git a/tests/Engine/Math/Rect.cpp b/tests/Engine/Math/RectTest.cpp similarity index 98% rename from tests/Engine/Math/Rect.cpp rename to tests/Engine/Math/RectTest.cpp index 7fe9d30fb..3aba4f41b 100644 --- a/tests/Engine/Math/Rect.cpp +++ b/tests/Engine/Math/RectTest.cpp @@ -1,5 +1,5 @@ #include -#include +#include SCENARIO("Rect", "[MATH][RECT]") { diff --git a/tests/Engine/Math/Sphere.cpp b/tests/Engine/Math/SphereTest.cpp similarity index 99% rename from tests/Engine/Math/Sphere.cpp rename to tests/Engine/Math/SphereTest.cpp index a6f23236d..e8c5d89a0 100644 --- a/tests/Engine/Math/Sphere.cpp +++ b/tests/Engine/Math/SphereTest.cpp @@ -1,5 +1,5 @@ #include -#include +#include SCENARIO("Sphere", "[MATH][SPHERE]") { diff --git a/tests/Engine/Math/Vector2.cpp b/tests/Engine/Math/Vector2Test.cpp similarity index 93% rename from tests/Engine/Math/Vector2.cpp rename to tests/Engine/Math/Vector2Test.cpp index 45ca1468c..4c02b0f1d 100644 --- a/tests/Engine/Math/Vector2.cpp +++ b/tests/Engine/Math/Vector2Test.cpp @@ -1,6 +1,6 @@ -#include -#include +#include +#include #include SCENARIO("Vector2", "[MATH][VECTOR2]") @@ -27,9 +27,9 @@ SCENARIO("Vector2", "[MATH][VECTOR2]") { REQUIRE(firstUnit.AbsDotProduct(tmp) == Approx(2.f)); REQUIRE(firstUnit.DotProduct(tmp) == Approx(0.f)); - REQUIRE(firstUnit.AngleBetween(tmp) == Approx(Nz::FromDegrees(90.f))); + REQUIRE(firstUnit.AngleBetween(tmp) == Nz::DegreeAnglef(90.f)); Nz::Vector2f negativeUnitX = -Nz::Vector2f::UnitX(); - REQUIRE(negativeUnitX.AngleBetween(negativeUnitX + Nz::Vector2f(0, 0.0000001f)) == Approx(Nz::FromDegrees(360.f))); + REQUIRE(negativeUnitX.AngleBetween(negativeUnitX + Nz::Vector2f(0, 0.0000001f)) == Nz::DegreeAnglef(360.f)); } } diff --git a/tests/Engine/Math/Vector3.cpp b/tests/Engine/Math/Vector3Test.cpp similarity index 93% rename from tests/Engine/Math/Vector3.cpp rename to tests/Engine/Math/Vector3Test.cpp index faeb03cca..427ead064 100644 --- a/tests/Engine/Math/Vector3.cpp +++ b/tests/Engine/Math/Vector3Test.cpp @@ -1,7 +1,6 @@ -#include -#include - +#include #include +#include #include SCENARIO("Vector3", "[MATH][VECTOR3]") @@ -27,8 +26,8 @@ SCENARIO("Vector3", "[MATH][VECTOR3]") { REQUIRE(firstUnit.AbsDotProduct(tmp) == Approx(2.f)); REQUIRE(firstUnit.DotProduct(tmp) == Approx(0.f)); - REQUIRE(firstUnit.AngleBetween(tmp) == Approx(Nz::FromDegrees(90.f))); - REQUIRE(firstUnit.AngleBetween(-firstUnit) == Approx(Nz::FromDegrees(180.f))); + REQUIRE(firstUnit.AngleBetween(tmp) == Nz::DegreeAnglef(90.f)); + REQUIRE(firstUnit.AngleBetween(-firstUnit) == Nz::DegreeAnglef(180.f)); } } diff --git a/tests/Engine/Math/Vector4.cpp b/tests/Engine/Math/Vector4Test.cpp similarity index 97% rename from tests/Engine/Math/Vector4.cpp rename to tests/Engine/Math/Vector4Test.cpp index 85c321ac1..76554737b 100644 --- a/tests/Engine/Math/Vector4.cpp +++ b/tests/Engine/Math/Vector4Test.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include diff --git a/tests/Engine/Network/IpAddress.cpp b/tests/Engine/Network/IpAddressTest.cpp similarity index 91% rename from tests/Engine/Network/IpAddress.cpp rename to tests/Engine/Network/IpAddressTest.cpp index 36fead7a2..b8767ab2f 100644 --- a/tests/Engine/Network/IpAddress.cpp +++ b/tests/Engine/Network/IpAddressTest.cpp @@ -1,5 +1,5 @@ #include -#include +#include SCENARIO("IpAddress", "[NETWORK][IPADDRESS]") { @@ -27,7 +27,7 @@ SCENARIO("IpAddress", "[NETWORK][IPADDRESS]") { WHEN("We get the IP of Nazara") { - std::vector hostnameInfos = Nz::IpAddress::ResolveHostname(Nz::NetProtocol_IPv4, "nazara.digitalpulsesoftware.net"); + std::vector hostnameInfos = Nz::IpAddress::ResolveHostname(Nz::NetProtocol::IPv4, "nazara.digitalpulsesoftware.net"); THEN("Result is not null") { diff --git a/tests/Engine/Network/RUdpConnection.cpp b/tests/Engine/Network/RUdpConnection.cpp deleted file mode 100644 index cd30b3e1e..000000000 --- a/tests/Engine/Network/RUdpConnection.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include - -#include - -SCENARIO("RUdpConnection", "[NETWORK][RUDPCONNECTION]") -{ - GIVEN("Two RUdpConnection, one client, one server") - { - // Disabled for now - - /*Nz::UInt16 port = 64266; - Nz::RUdpConnection server; - REQUIRE(server.Listen(Nz::NetProtocol_IPv4, port)); - - Nz::IpAddress serverIP(Nz::IpAddress::LoopbackIpV4.ToIPv4(), port); - REQUIRE(serverIP.IsValid()); - - Nz::RUdpConnection client; - REQUIRE(client.Listen(Nz::NetProtocol_IPv4, port + 1)); - - Nz::IpAddress clientIP = client.GetBoundAddress(); - REQUIRE(client.Connect(serverIP)); - REQUIRE(clientIP.IsValid()); - - WHEN("We send data from client") - { - Nz::NetPacket packet(1); - Nz::Vector3f vector123(1.f, 2.f, 3.f); - packet << vector123; - REQUIRE(client.Send(serverIP, Nz::PacketPriority_Immediate, Nz::PacketReliability_Reliable, packet)); - client.Update(); - - THEN("We should get it on the server") - { - Nz::RUdpMessage rudpMessage; - server.Update(); - - REQUIRE(server.PollMessage(&rudpMessage)); - - Nz::Vector3f result; - rudpMessage.data >> result; - REQUIRE(result == vector123); - } - }*/ - } -} diff --git a/tests/Engine/Network/SocketPoller.cpp b/tests/Engine/Network/SocketPollerTest.cpp similarity index 91% rename from tests/Engine/Network/SocketPoller.cpp rename to tests/Engine/Network/SocketPollerTest.cpp index 2e880cf5c..1ba14999c 100644 --- a/tests/Engine/Network/SocketPoller.cpp +++ b/tests/Engine/Network/SocketPollerTest.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include SCENARIO("SocketPoller", "[NETWORK][SOCKETPOLLER]") @@ -17,7 +17,7 @@ SCENARIO("SocketPoller", "[NETWORK][SOCKETPOLLER]") Nz::TcpServer server; server.EnableBlocking(false); - REQUIRE(server.Listen(Nz::NetProtocol_IPv4, port) == Nz::SocketState_Bound); + REQUIRE(server.Listen(Nz::NetProtocol::IPv4, port) == Nz::SocketState::Bound); Nz::IpAddress serverIP(Nz::IpAddress::LoopbackIpV4.ToIPv4(), port); REQUIRE(serverIP.IsValid()); @@ -27,7 +27,7 @@ SCENARIO("SocketPoller", "[NETWORK][SOCKETPOLLER]") WHEN("We register the server socket to the poller") { - REQUIRE(serverPoller.RegisterSocket(server, Nz::SocketPollEvent_Read)); + REQUIRE(serverPoller.RegisterSocket(server, Nz::SocketPollEvent::Read)); THEN("The poller should have registered our socket") { @@ -37,7 +37,7 @@ SCENARIO("SocketPoller", "[NETWORK][SOCKETPOLLER]") { Nz::SocketState state = clientToServer.Connect(serverIP); - CHECK(state != Nz::SocketState_NotConnected); + CHECK(state != Nz::SocketState::NotConnected); AND_THEN("We wait on our selector, it should return true") { @@ -48,7 +48,7 @@ SCENARIO("SocketPoller", "[NETWORK][SOCKETPOLLER]") WHEN("We register the client socket to the poller") { - REQUIRE(serverPoller.RegisterSocket(serverToClient, Nz::SocketPollEvent_Read)); + REQUIRE(serverPoller.RegisterSocket(serverToClient, Nz::SocketPollEvent::Read)); THEN("The poller should have registered our socket") { diff --git a/tests/Engine/Network/TCP.cpp b/tests/Engine/Network/TCPTest.cpp similarity index 87% rename from tests/Engine/Network/TCP.cpp rename to tests/Engine/Network/TCPTest.cpp index 0bc90483c..04ef2928a 100644 --- a/tests/Engine/Network/TCP.cpp +++ b/tests/Engine/Network/TCPTest.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include #include @@ -19,13 +19,13 @@ SCENARIO("TCP", "[NETWORK][TCP]") Nz::TcpServer server; server.EnableBlocking(false); - REQUIRE(server.Listen(Nz::NetProtocol_IPv4, port) == Nz::SocketState_Bound); + REQUIRE(server.Listen(Nz::NetProtocol::IPv4, port) == Nz::SocketState::Bound); Nz::IpAddress serverIP(Nz::IpAddress::LoopbackIpV4.ToIPv4(), port); REQUIRE(serverIP.IsValid()); Nz::TcpClient client; - REQUIRE(client.Connect(serverIP) == Nz::SocketState_Connecting); + REQUIRE(client.Connect(serverIP) == Nz::SocketState::Connecting); Nz::IpAddress clientIP = client.GetRemoteAddress(); CHECK(clientIP.IsValid()); diff --git a/tests/Engine/Network/UdpSocket.cpp b/tests/Engine/Network/UdpSocketTest.cpp similarity index 80% rename from tests/Engine/Network/UdpSocket.cpp rename to tests/Engine/Network/UdpSocketTest.cpp index 00d793e7a..e078dd734 100644 --- a/tests/Engine/Network/UdpSocket.cpp +++ b/tests/Engine/Network/UdpSocketTest.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include SCENARIO("UdpSocket", "[NETWORK][UDPSOCKET]") @@ -12,14 +12,14 @@ SCENARIO("UdpSocket", "[NETWORK][UDPSOCKET]") std::uniform_int_distribution dis(1025, 65535); Nz::UInt16 port = dis(rd); - Nz::UdpSocket server(Nz::NetProtocol_IPv4); - REQUIRE(server.Bind(port) == Nz::SocketState_Bound); + Nz::UdpSocket server(Nz::NetProtocol::IPv4); + REQUIRE(server.Bind(port) == Nz::SocketState::Bound); Nz::IpAddress serverIP(Nz::IpAddress::LoopbackIpV4.ToIPv4(), port); REQUIRE(serverIP.IsValid()); - Nz::UdpSocket client(Nz::NetProtocol_IPv4); - REQUIRE(client.Bind(port + 1) == Nz::SocketState_Bound); + Nz::UdpSocket client(Nz::NetProtocol::IPv4); + REQUIRE(client.Bind(port + 1) == Nz::SocketState::Bound); Nz::IpAddress clientIP = client.GetBoundAddress(); REQUIRE(clientIP.IsValid()); diff --git a/tests/Engine/Physics2D/Collider2D.cpp b/tests/Engine/Physics2D/Collider2DTest.cpp similarity index 80% rename from tests/Engine/Physics2D/Collider2D.cpp rename to tests/Engine/Physics2D/Collider2DTest.cpp index 811b75ded..4f0e115ca 100644 --- a/tests/Engine/Physics2D/Collider2D.cpp +++ b/tests/Engine/Physics2D/Collider2DTest.cpp @@ -1,5 +1,5 @@ #include -#include +#include SCENARIO("Collider2D", "[PHYSICS2D][COLLIDER2D]") { @@ -14,7 +14,7 @@ SCENARIO("Collider2D", "[PHYSICS2D][COLLIDER2D]") { CHECK(box.GetRect() == aabb); CHECK(box.GetSize() == aabb.GetLengths()); - CHECK(box.GetType() == Nz::ColliderType2D_Box); + CHECK(box.GetType() == Nz::ColliderType2D::Box); } } @@ -28,7 +28,7 @@ SCENARIO("Collider2D", "[PHYSICS2D][COLLIDER2D]") { CHECK(box.GetRect() == aabb); CHECK(box.GetSize() == vec); - CHECK(box.GetType() == Nz::ColliderType2D_Box); + CHECK(box.GetType() == Nz::ColliderType2D::Box); } } @@ -41,25 +41,25 @@ SCENARIO("Collider2D", "[PHYSICS2D][COLLIDER2D]") THEN("We expect those to be true") { CHECK(circle.GetRadius() == Approx(radius)); - CHECK(circle.GetType() == Nz::ColliderType2D_Circle); + CHECK(circle.GetType() == Nz::ColliderType2D::Circle); } } WHEN("We construct a compound") { Nz::Rectf aabb(0.f, 0.f, 1.f, 1.f); - Nz::BoxCollider2DRef box1 = Nz::BoxCollider2D::New(aabb); + std::shared_ptr box1 = std::make_shared(aabb); aabb.Translate(Nz::Vector2f::Unit()); - Nz::BoxCollider2DRef box2 = Nz::BoxCollider2D::New(aabb); + std::shared_ptr box2 = std::make_shared(aabb); - std::vector colliders; + std::vector> colliders; colliders.push_back(box1); colliders.push_back(box2); Nz::CompoundCollider2D compound(colliders); THEN("We expect those to be true") { - CHECK(compound.GetType() == Nz::ColliderType2D_Compound); + CHECK(compound.GetType() == Nz::ColliderType2D::Compound); } } @@ -75,7 +75,7 @@ SCENARIO("Collider2D", "[PHYSICS2D][COLLIDER2D]") THEN("We expect those to be true") { - CHECK(convex.GetType() == Nz::ColliderType2D_Convex); + CHECK(convex.GetType() == Nz::ColliderType2D::Convex); } } @@ -85,7 +85,7 @@ SCENARIO("Collider2D", "[PHYSICS2D][COLLIDER2D]") THEN("We expect those to be true") { - CHECK(null.GetType() == Nz::ColliderType2D_Null); + CHECK(null.GetType() == Nz::ColliderType2D::Null); } } @@ -100,7 +100,7 @@ SCENARIO("Collider2D", "[PHYSICS2D][COLLIDER2D]") CHECK(segment.GetFirstPoint() == firstPoint); CHECK(segment.GetLength() == Approx(firstPoint.Distance(secondPoint))); CHECK(segment.GetSecondPoint() == secondPoint); - CHECK(segment.GetType() == Nz::ColliderType2D_Segment); + CHECK(segment.GetType() == Nz::ColliderType2D::Segment); } } diff --git a/tests/Engine/Physics2D/PhysWorld2D.cpp b/tests/Engine/Physics2D/PhysWorld2DTest.cpp similarity index 94% rename from tests/Engine/Physics2D/PhysWorld2D.cpp rename to tests/Engine/Physics2D/PhysWorld2DTest.cpp index e71c9f2cb..f1772519a 100644 --- a/tests/Engine/Physics2D/PhysWorld2D.cpp +++ b/tests/Engine/Physics2D/PhysWorld2DTest.cpp @@ -1,5 +1,5 @@ #include -#include +#include Nz::RigidBody2D CreateBody(Nz::PhysWorld2D& world, const Nz::Vector2f& position, bool isMoving = true, const Nz::Vector2f& lengths = Nz::Vector2f::Unit()); @@ -106,22 +106,24 @@ SCENARIO("PhysWorld2D", "[PHYSICS2D][PHYSWORLD2D]") unsigned int WALL_COLLISION_ID = 2; unsigned int TRIGGER_COLLISION_ID = 3; + int statusTriggerCollision = 0; + Nz::PhysWorld2D world; Nz::Rectf characterAABB(0.f, 0.f, 1.f, 1.f); - Nz::Collider2DRef characterBox = Nz::BoxCollider2D::New(characterAABB); + std::shared_ptr characterBox = std::make_shared(characterAABB); characterBox->SetCollisionId(CHARACTER_COLLISION_ID); Nz::RigidBody2D character(&world, 1.f, characterBox); character.SetPosition(Nz::Vector2f::Zero()); Nz::Rectf wallAABB(0.f, 0.f, 1.f, 2.f); - Nz::Collider2DRef wallBox = Nz::BoxCollider2D::New(wallAABB); + std::shared_ptr wallBox = std::make_shared(wallAABB); wallBox->SetCollisionId(WALL_COLLISION_ID); Nz::RigidBody2D wall(&world, 0.f, wallBox); wall.SetPosition(Nz::Vector2f(5.f, 0.f)); Nz::Rectf triggerAABB(0.f, 0.f, 1.f, 1.f); - Nz::Collider2DRef triggerBox = Nz::BoxCollider2D::New(triggerAABB); + std::shared_ptr triggerBox = std::make_shared(triggerAABB); triggerBox->SetTrigger(true); triggerBox->SetCollisionId(TRIGGER_COLLISION_ID); Nz::RigidBody2D trigger(&world, 0.f, triggerBox); @@ -129,7 +131,6 @@ SCENARIO("PhysWorld2D", "[PHYSICS2D][PHYSWORLD2D]") world.Step(0.f); - int statusTriggerCollision = 0; Nz::PhysWorld2D::Callback characterTriggerCallback; characterTriggerCallback.startCallback = [&](Nz::PhysWorld2D&, Nz::Arbiter2D&, Nz::RigidBody2D&, Nz::RigidBody2D&, void*) -> bool { statusTriggerCollision = statusTriggerCollision | 1 << 0; @@ -192,7 +193,7 @@ SCENARIO("PhysWorld2D", "[PHYSICS2D][PHYSWORLD2D]") Nz::RigidBody2D CreateBody(Nz::PhysWorld2D& world, const Nz::Vector2f& position, bool isMoving, const Nz::Vector2f& lengths) { Nz::Rectf aabb(0.f, 0.f, lengths.x, lengths.y); - Nz::Collider2DRef box = Nz::BoxCollider2D::New(aabb); + std::shared_ptr box = std::make_shared(aabb); box->SetCategoryMask(categoryMask); box->SetCollisionMask(collisionMask); float mass = isMoving ? 1.f : 0.f; diff --git a/tests/Engine/Physics2D/RigidBody2D.cpp b/tests/Engine/Physics2D/RigidBody2DTest.cpp similarity index 86% rename from tests/Engine/Physics2D/RigidBody2D.cpp rename to tests/Engine/Physics2D/RigidBody2DTest.cpp index e554746d8..36b6f7323 100644 --- a/tests/Engine/Physics2D/RigidBody2D.cpp +++ b/tests/Engine/Physics2D/RigidBody2DTest.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include @@ -17,7 +17,7 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]") Nz::Vector2f positionAABB(3.f, 4.f); Nz::Rectf aabb(positionAABB.x, positionAABB.y, 1.f, 2.f); - Nz::Collider2DRef box = Nz::BoxCollider2D::New(aabb); + std::shared_ptr box = std::make_shared(aabb); float mass = 1.f; Nz::RigidBody2D body(&world, mass, box); float angularVelocity = 0.2f; @@ -69,7 +69,7 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]") WHEN("We set a new geometry") { float radius = 5.f; - body.SetGeom(Nz::CircleCollider2D::New(radius)); + body.SetGeom(std::make_shared(radius)); world.Step(1.f); @@ -112,7 +112,7 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]") Nz::Vector2f positionAABB(3.f, 4.f); Nz::Rectf aabb(positionAABB.x, positionAABB.y, 1.f, 2.f); - Nz::Collider2DRef box = Nz::BoxCollider2D::New(aabb); + std::shared_ptr box = std::make_shared(aabb); float mass = 1.f; Nz::RigidBody2D body(&world, mass); body.SetGeom(box, true, false); @@ -131,7 +131,7 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]") { CHECK(body.GetAABB() == aabb); CHECK(body.GetAngularVelocity() == 0.f); - CHECK(body.GetMassCenter(Nz::CoordSys_Global) == position); + CHECK(body.GetMassCenter(Nz::CoordSys::Global) == position); CHECK(body.GetGeom() == box); CHECK(body.GetMass() == Approx(mass)); CHECK(body.GetPosition() == position); @@ -155,7 +155,7 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]") { aabb.Translate(velocity); CHECK(body.GetAABB() == aabb); - CHECK(body.GetMassCenter(Nz::CoordSys_Global) == position); + CHECK(body.GetMassCenter(Nz::CoordSys::Global) == position); CHECK(body.GetPosition() == position); CHECK(body.GetVelocity() == velocity); } @@ -214,7 +214,7 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]") Nz::Vector2f position(3.f, 4.f); float radius = 5.f; - Nz::Collider2DRef circle = Nz::CircleCollider2D::New(radius, position); + std::shared_ptr circle = std::make_shared(radius, position); float mass = 1.f; Nz::RigidBody2D body(&world, mass); body.SetGeom(circle, true, false); @@ -237,14 +237,14 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]") world.SetMaxStepCount(std::numeric_limits::max()); Nz::Rectf aabb(0.f, 0.f, 1.f, 1.f); - Nz::BoxCollider2DRef box1 = Nz::BoxCollider2D::New(aabb); + std::shared_ptr box1 = std::make_shared(aabb); aabb.Translate(Nz::Vector2f::Unit()); - Nz::BoxCollider2DRef box2 = Nz::BoxCollider2D::New(aabb); + std::shared_ptr box2 = std::make_shared(aabb); - std::vector colliders; + std::vector> colliders; colliders.push_back(box1); colliders.push_back(box2); - Nz::CompoundCollider2DRef compound = Nz::CompoundCollider2D::New(colliders); + std::shared_ptr compound = std::make_shared(colliders); float mass = 1.f; Nz::RigidBody2D body(&world, mass); @@ -268,13 +268,13 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]") world.SetMaxStepCount(std::numeric_limits::max()); std::vector vertices; - vertices.push_back(Nz::Vector2f(0.f, 0.f)); - vertices.push_back(Nz::Vector2f(0.f, 1.f)); - vertices.push_back(Nz::Vector2f(1.f, 1.f)); - vertices.push_back(Nz::Vector2f(1.f, 0.f)); + vertices.emplace_back(0.f, 0.f); + vertices.emplace_back(0.f, 1.f); + vertices.emplace_back(1.f, 1.f); + vertices.emplace_back(1.f, 0.f); Nz::SparsePtr sparsePtr(vertices.data()); - Nz::ConvexCollider2DRef convex = Nz::ConvexCollider2D::New(sparsePtr, vertices.size()); + std::shared_ptr convex = std::make_shared(sparsePtr, vertices.size()); float mass = 1.f; Nz::RigidBody2D body(&world, mass); body.SetGeom(convex, true, false); @@ -298,7 +298,7 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]") Nz::Vector2f positionA(3.f, 4.f); Nz::Vector2f positionB(1.f, -4.f); - Nz::Collider2DRef segment = Nz::SegmentCollider2D::New(positionA, positionB, 0.f); + std::shared_ptr segment = std::make_shared(positionA, positionB, 0.f); float mass = 1.f; Nz::RigidBody2D body(&world, mass); body.SetGeom(segment, true, false); @@ -320,7 +320,7 @@ Nz::RigidBody2D CreateBody(Nz::PhysWorld2D& world) { Nz::Vector2f positionAABB(3.f, 4.f); Nz::Rectf aabb(positionAABB.x, positionAABB.y, 1.f, 2.f); - Nz::Collider2DRef box = Nz::BoxCollider2D::New(aabb); + std::shared_ptr box = std::make_shared(aabb); float mass = 1.f; Nz::RigidBody2D body(&world, mass, box); diff --git a/tests/Engine/Shader/AccessMember.cpp b/tests/Engine/Shader/AccessMember.cpp deleted file mode 100644 index 7ed92bd9c..000000000 --- a/tests/Engine/Shader/AccessMember.cpp +++ /dev/null @@ -1,145 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -std::string_view Trim(std::string_view str) -{ - while (!str.empty() && std::isspace(str.front())) - str.remove_prefix(1); - - while (!str.empty() && std::isspace(str.back())) - str.remove_suffix(1); - - return str; -} - -void ExpectingGLSL(const Nz::ShaderAst& shader, std::string_view expectedOutput) -{ - Nz::GlslWriter writer; - - std::string output = writer.Generate(shader); - std::size_t funcOffset = output.find("void main()"); - std::string_view subset = Trim(output).substr(funcOffset); - expectedOutput = Trim(expectedOutput); - - REQUIRE(subset == expectedOutput); -} - -void ExpectingSpirV(const Nz::ShaderAst& shader, std::string_view expectedOutput) -{ - Nz::SpirvWriter writer; - auto spirv = writer.Generate(shader); - - Nz::SpirvPrinter printer; - - Nz::SpirvPrinter::Settings settings; - settings.printHeader = false; - settings.printParameters = false; - - std::string output = printer.Print(spirv.data(), spirv.size(), settings); - std::size_t funcOffset = output.find("OpFunction"); - std::string_view subset = Trim(output).substr(funcOffset); - expectedOutput = Trim(expectedOutput); - - REQUIRE(subset == expectedOutput); -} - -SCENARIO("Shader generation", "[Shader]") -{ - SECTION("Nested member loading") - { - Nz::ShaderAst baseShader(Nz::ShaderStageType::Vertex); - baseShader.AddStruct("innerStruct", { - { - "field", - Nz::ShaderNodes::BasicType::Float3 - } - }); - - baseShader.AddStruct("outerStruct", { - { - "s", - "innerStruct" - } - }); - - baseShader.AddUniform("ubo", "outerStruct"); - baseShader.AddOutput("result", Nz::ShaderNodes::BasicType::Float1); - - SECTION("Nested AccessMember") - { - Nz::ShaderAst shader = baseShader; - - auto uniform = Nz::ShaderBuilder::Uniform("ubo", "outerStruct"); - auto output = Nz::ShaderBuilder::Output("result", Nz::ShaderNodes::BasicType::Float1); - - auto access = Nz::ShaderBuilder::Swizzle(Nz::ShaderBuilder::AccessMember(Nz::ShaderBuilder::AccessMember(Nz::ShaderBuilder::Identifier(uniform), 0, "innerStruct"), 0, Nz::ShaderNodes::BasicType::Float3), Nz::ShaderNodes::SwizzleComponent::Third); - auto assign = Nz::ShaderBuilder::Assign(Nz::ShaderBuilder::Identifier(output), access); - - shader.AddFunction("main", Nz::ShaderBuilder::ExprStatement(assign)); - - SECTION("Generating GLSL") - { - ExpectingGLSL(shader, R"( -void main() -{ - result = ubo.s.field.z; -} -)"); - } - SECTION("Generating Spir-V") - { - ExpectingSpirV(shader, R"( -OpFunction -OpLabel -OpAccessChain -OpAccessChain -OpLoad -OpCompositeExtract -OpStore -OpReturn -OpFunctionEnd)"); - } - } - - SECTION("AccessMember with multiples fields") - { - Nz::ShaderAst shader = baseShader; - - auto uniform = Nz::ShaderBuilder::Uniform("ubo", "outerStruct"); - auto output = Nz::ShaderBuilder::Output("result", Nz::ShaderNodes::BasicType::Float1); - - auto access = Nz::ShaderBuilder::Swizzle(Nz::ShaderBuilder::AccessMember(Nz::ShaderBuilder::Identifier(uniform), std::vector{ 0, 0 }, Nz::ShaderNodes::BasicType::Float3), Nz::ShaderNodes::SwizzleComponent::Third); - auto assign = Nz::ShaderBuilder::Assign(Nz::ShaderBuilder::Identifier(output), access); - - shader.AddFunction("main", Nz::ShaderBuilder::ExprStatement(assign)); - - SECTION("Generating GLSL") - { - ExpectingGLSL(shader, R"( -void main() -{ - result = ubo.s.field.z; -} -)"); - } - SECTION("Generating Spir-V") - { - ExpectingSpirV(shader, R"( -OpFunction -OpLabel -OpAccessChain -OpLoad -OpCompositeExtract -OpStore -OpReturn -OpFunctionEnd)"); - } - } - } -} diff --git a/tests/Engine/Shader/AccessMemberTest.cpp b/tests/Engine/Shader/AccessMemberTest.cpp new file mode 100644 index 000000000..96b7373d0 --- /dev/null +++ b/tests/Engine/Shader/AccessMemberTest.cpp @@ -0,0 +1,146 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +void ExpectingGLSL(Nz::ShaderAst::StatementPtr& shader, std::string_view expectedOutput) +{ + Nz::GlslWriter writer; + + std::string output = writer.Generate(shader); + std::size_t funcOffset = output.find("void main()"); + std::string_view subset = Nz::Trim(output).substr(funcOffset); + expectedOutput = Nz::Trim(expectedOutput); + + REQUIRE(subset == expectedOutput); +} + +void ExpectingSpirV(Nz::ShaderAst::StatementPtr& shader, std::string_view expectedOutput) +{ + Nz::SpirvWriter writer; + auto spirv = writer.Generate(shader); + + Nz::SpirvPrinter printer; + + Nz::SpirvPrinter::Settings settings; + settings.printHeader = false; + settings.printParameters = false; + + std::string output = printer.Print(spirv.data(), spirv.size(), settings); + std::size_t funcOffset = output.find("OpFunction"); + std::string_view subset = Nz::Trim(output).substr(funcOffset); + expectedOutput = Nz::Trim(expectedOutput); + + REQUIRE(subset == expectedOutput); +} + +SCENARIO("Shader generation", "[Shader]") +{ + SECTION("Nested member loading") + { + std::vector statements; + + Nz::ShaderAst::StructDescription innerStructDesc; + { + innerStructDesc.name = "innerStruct"; + auto& member = innerStructDesc.members.emplace_back(); + member.name = "field"; + member.type = Nz::ShaderAst::VectorType{ 3, Nz::ShaderAst::PrimitiveType::Float32 }; + } + statements.push_back(Nz::ShaderBuilder::DeclareStruct(std::move(innerStructDesc))); + + Nz::ShaderAst::StructDescription outerStruct; + { + outerStruct.name = "outerStruct"; + auto& member = outerStruct.members.emplace_back(); + member.name = "s"; + member.type = Nz::ShaderAst::IdentifierType{ "innerStruct" }; + } + statements.push_back(Nz::ShaderBuilder::DeclareStruct(std::move(outerStruct))); + + auto external = std::make_unique(); + external->externalVars.push_back({ + std::nullopt, + "ubo", + Nz::ShaderAst::UniformType{ Nz::ShaderAst::IdentifierType{ "outerStruct" } } + }); + statements.push_back(std::move(external)); + + SECTION("Nested AccessMember") + { + auto ubo = Nz::ShaderBuilder::Identifier("ubo"); + auto firstAccess = Nz::ShaderBuilder::AccessMember(std::move(ubo), { "s" }); + auto secondAccess = Nz::ShaderBuilder::AccessMember(std::move(firstAccess), { "field" }); + + auto swizzle = Nz::ShaderBuilder::Swizzle(std::move(secondAccess), { Nz::ShaderAst::SwizzleComponent::Third }); + auto varDecl = Nz::ShaderBuilder::DeclareVariable("result", Nz::ShaderAst::PrimitiveType::Float32, std::move(swizzle)); + + statements.push_back(Nz::ShaderBuilder::DeclareFunction("main", std::move(varDecl))); + + Nz::ShaderAst::StatementPtr shader = Nz::ShaderBuilder::MultiStatement(std::move(statements)); + + SECTION("Generating GLSL") + { + ExpectingGLSL(shader, R"( +void main() +{ + float result = ubo.s.field.z; +} +)"); + } + SECTION("Generating Spir-V") + { + ExpectingSpirV(shader, R"( +OpFunction +OpLabel +OpVariable +OpAccessChain +OpLoad +OpCompositeExtract +OpStore +OpReturn +OpFunctionEnd)"); + } + } + + SECTION("AccessMember with multiples fields") + { + auto ubo = Nz::ShaderBuilder::Identifier("ubo"); + auto access = Nz::ShaderBuilder::AccessMember(std::move(ubo), { "s", "field" }); + + auto swizzle = Nz::ShaderBuilder::Swizzle(std::move(access), { Nz::ShaderAst::SwizzleComponent::Third }); + auto varDecl = Nz::ShaderBuilder::DeclareVariable("result", Nz::ShaderAst::PrimitiveType::Float32, std::move(swizzle)); + + statements.push_back(Nz::ShaderBuilder::DeclareFunction("main", std::move(varDecl))); + + Nz::ShaderAst::StatementPtr shader = Nz::ShaderBuilder::MultiStatement(std::move(statements)); + + SECTION("Generating GLSL") + { + ExpectingGLSL(shader, R"( +void main() +{ + float result = ubo.s.field.z; +} +)"); + } + SECTION("Generating Spir-V") + { + ExpectingSpirV(shader, R"( +OpFunction +OpLabel +OpVariable +OpAccessChain +OpLoad +OpCompositeExtract +OpStore +OpReturn +OpFunctionEnd)"); + } + } + } +} diff --git a/tests/SDK/NDK/Application.cpp b/tests/SDK/NDK/Application.cpp index a7f471255..0fa2e75a0 100644 --- a/tests/SDK/NDK/Application.cpp +++ b/tests/SDK/NDK/Application.cpp @@ -1,11 +1,11 @@ -#include +#include #include SCENARIO("Application", "[NDK][APPLICATION]") { GIVEN("An application") { - Nz::Window& window = Ndk::Application::Instance()->AddWindow(); + Nz::Window& window = Ndk::ClientApplication::Instance()->AddWindow(); WHEN("We open a window") { @@ -22,4 +22,4 @@ SCENARIO("Application", "[NDK][APPLICATION]") } } } -} \ No newline at end of file +} diff --git a/tests/SDK/NDK/BaseSystem.cpp b/tests/SDK/NDK/BaseSystem.cpp index bf86a9011..e8b3dae9d 100644 --- a/tests/SDK/NDK/BaseSystem.cpp +++ b/tests/SDK/NDK/BaseSystem.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include namespace { @@ -32,7 +32,7 @@ SCENARIO("BaseSystem", "[NDK][BASESYSTEM]") { GIVEN("Our TestSystem") { - Ndk::World world(false); + Ndk::World world; Ndk::BaseSystem& system = world.AddSystem(); REQUIRE(&system.GetWorld() == &world); @@ -62,4 +62,4 @@ SCENARIO("BaseSystem", "[NDK][BASESYSTEM]") } } } -} \ No newline at end of file +} diff --git a/tests/SDK/NDK/Component.cpp b/tests/SDK/NDK/Component.cpp index 74244fda5..d9c68b26d 100644 --- a/tests/SDK/NDK/Component.cpp +++ b/tests/SDK/NDK/Component.cpp @@ -1,5 +1,5 @@ #include -#include +#include namespace { diff --git a/tests/SDK/NDK/Entity.cpp b/tests/SDK/NDK/Entity.cpp index e17b9114d..df5f8e889 100644 --- a/tests/SDK/NDK/Entity.cpp +++ b/tests/SDK/NDK/Entity.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include namespace { @@ -55,7 +55,7 @@ SCENARIO("Entity", "[NDK][ENTITY]") { GIVEN("A world & an entity") { - Ndk::World world(false); + Ndk::World world; Ndk::BaseSystem& system = world.AddSystem(); Ndk::EntityHandle entity = world.CreateEntity(); @@ -99,4 +99,4 @@ SCENARIO("Entity", "[NDK][ENTITY]") } } } -} \ No newline at end of file +} diff --git a/tests/SDK/NDK/EntityList.cpp b/tests/SDK/NDK/EntityList.cpp index 6b9c85ddf..bc5447e10 100644 --- a/tests/SDK/NDK/EntityList.cpp +++ b/tests/SDK/NDK/EntityList.cpp @@ -1,12 +1,12 @@ #include #include -#include +#include SCENARIO("EntityList", "[NDK][ENTITYLIST]") { GIVEN("A world & a set of entities") { - Ndk::World world(false); + Ndk::World world; const Ndk::EntityHandle& entity = world.CreateEntity(); Ndk::EntityList entityList; @@ -39,4 +39,4 @@ SCENARIO("EntityList", "[NDK][ENTITYLIST]") } } } -} \ No newline at end of file +} diff --git a/tests/SDK/NDK/EntityOwner.cpp b/tests/SDK/NDK/EntityOwner.cpp index 1cb6f768c..7c2f94987 100644 --- a/tests/SDK/NDK/EntityOwner.cpp +++ b/tests/SDK/NDK/EntityOwner.cpp @@ -1,12 +1,12 @@ #include #include -#include +#include SCENARIO("EntityOwner", "[NDK][ENTITYOWNER]") { GIVEN("A world & an entity") { - Ndk::World world(false); + Ndk::World world; Ndk::EntityHandle entity = world.CreateEntity(); WHEN("We set the ownership of the entity to our owner") @@ -108,7 +108,7 @@ SCENARIO("EntityOwner", "[NDK][ENTITYOWNER]") GIVEN("A vector of EntityOwner") { - Ndk::World world(false); + Ndk::World world; std::vector entityOwners; for (std::size_t i = 1; i <= 10; ++i) diff --git a/tests/SDK/NDK/StateMachine.cpp b/tests/SDK/NDK/StateMachine.cpp index 29a781e2c..0937d2b13 100644 --- a/tests/SDK/NDK/StateMachine.cpp +++ b/tests/SDK/NDK/StateMachine.cpp @@ -1,5 +1,5 @@ #include -#include +#include class TestState : public Ndk::State { diff --git a/tests/SDK/NDK/System.cpp b/tests/SDK/NDK/System.cpp index a6ef4e590..79f174a52 100644 --- a/tests/SDK/NDK/System.cpp +++ b/tests/SDK/NDK/System.cpp @@ -1,5 +1,5 @@ #include -#include +#include namespace { diff --git a/tests/SDK/NDK/Systems/PhysicsSystem2D.cpp b/tests/SDK/NDK/Systems/PhysicsSystem2D.cpp index 2081da617..49b62ac7c 100644 --- a/tests/SDK/NDK/Systems/PhysicsSystem2D.cpp +++ b/tests/SDK/NDK/Systems/PhysicsSystem2D.cpp @@ -3,7 +3,8 @@ #include #include #include -#include +#include +#include #include Ndk::EntityHandle CreateBaseEntity(Ndk::World& world, const Nz::Vector2f& position, const Nz::Rectf& AABB); @@ -13,6 +14,7 @@ SCENARIO("PhysicsSystem2D", "[NDK][PHYSICSSYSTEM2D]") GIVEN("A world and an entity") { Ndk::World world; + world.AddSystem(); Nz::Vector2f position(2.f, 3.f); Nz::Rectf movingAABB(0.f, 0.f, 16.f, 18.f); @@ -74,6 +76,7 @@ SCENARIO("PhysicsSystem2D", "[NDK][PHYSICSSYSTEM2D]") GIVEN("A world and a simple entity") { Ndk::World world; + world.AddSystem(); Nz::Vector2f position(0.f, 0.f); Nz::Rectf movingAABB(0.f, 0.f, 1.f, 2.f); @@ -96,7 +99,7 @@ SCENARIO("PhysicsSystem2D", "[NDK][PHYSICSSYSTEM2D]") CHECK(physicsComponent2D.GetAngularVelocity() == angularSpeed); CHECK(physicsComponent2D.GetAABB() == Nz::Rectf(-2.f, 0.f, 2.f, 1.f)); CHECK(physicsComponent2D.GetRotation() == Nz::RadianAnglef::FromDegrees(90.f)); - CHECK(nodeComponent.GetRotation().ToEulerAngles().roll == Approx(Nz::FromDegrees(90.f))); + CHECK(nodeComponent.GetRotation().ToEulerAngles().roll == Nz::DegreeAnglef(90.f)); } } @@ -120,6 +123,7 @@ SCENARIO("PhysicsSystem2D", "[NDK][PHYSICSSYSTEM2D]") GIVEN("A world and a simple entity not at the origin") { Ndk::World world; + world.AddSystem(); Nz::Vector2f position(3.f, 4.f); Nz::Rectf movingAABB(0.f, 0.f, 1.f, 2.f); @@ -143,7 +147,7 @@ SCENARIO("PhysicsSystem2D", "[NDK][PHYSICSSYSTEM2D]") CHECK(physicsComponent2D.GetAABB() == Nz::Rectf(1.f, 4.f, 2.f, 1.f)); CHECK(physicsComponent2D.GetRotation() == 2.f * angularSpeed); CHECK(nodeComponent.GetPosition() == position); - CHECK(nodeComponent.GetRotation().ToEulerAngles().roll == Approx(Nz::FromDegrees(90.f))); + CHECK(nodeComponent.GetRotation().ToEulerAngles().roll == Nz::DegreeAnglef(90.f)); } } } @@ -154,7 +158,7 @@ Ndk::EntityHandle CreateBaseEntity(Ndk::World& world, const Nz::Vector2f& positi Ndk::EntityHandle entity = world.CreateEntity(); Ndk::NodeComponent& nodeComponent = entity->AddComponent(); nodeComponent.SetPosition(position); - Nz::BoxCollider2DRef collisionBox = Nz::BoxCollider2D::New(AABB); + std::shared_ptr collisionBox = std::make_shared(AABB); entity->AddComponent(collisionBox); return entity; } diff --git a/tests/SDK/NDK/Systems/PhysicsSystem3D.cpp b/tests/SDK/NDK/Systems/PhysicsSystem3D.cpp index 7dc66673c..f2a539b87 100644 --- a/tests/SDK/NDK/Systems/PhysicsSystem3D.cpp +++ b/tests/SDK/NDK/Systems/PhysicsSystem3D.cpp @@ -3,13 +3,16 @@ #include #include #include -#include +#include +#include SCENARIO("PhysicsSystem3D", "[NDK][PHYSICSSYSTEM3D]") { GIVEN("A world and a static entity & a dynamic entity") { Ndk::World world; + world.AddSystem(); + const Ndk::EntityHandle& staticEntity = world.CreateEntity(); Ndk::CollisionComponent3D& collisionComponentStatic = staticEntity->AddComponent(); Ndk::NodeComponent& nodeComponentStatic = staticEntity->AddComponent(); @@ -31,4 +34,4 @@ SCENARIO("PhysicsSystem3D", "[NDK][PHYSICSSYSTEM3D]") } } } -} \ No newline at end of file +} diff --git a/tests/SDK/NDK/Systems/VelocitySystem.cpp b/tests/SDK/NDK/Systems/VelocitySystem.cpp index de77de28d..63acf6c6c 100644 --- a/tests/SDK/NDK/Systems/VelocitySystem.cpp +++ b/tests/SDK/NDK/Systems/VelocitySystem.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include SCENARIO("VelocitySystem", "[NDK][VELOCITYSYSTEM]") { @@ -13,7 +13,7 @@ SCENARIO("VelocitySystem", "[NDK][VELOCITYSYSTEM]") Ndk::VelocityComponent& velocityComponent = entity->AddComponent(); Ndk::NodeComponent& nodeComponent = entity->AddComponent(); - world.GetSystem().SetFixedUpdateRate(30.f); + world.AddSystem().SetFixedUpdateRate(30.f); WHEN("We give a speed to our entity") { @@ -27,4 +27,4 @@ SCENARIO("VelocitySystem", "[NDK][VELOCITYSYSTEM]") } } } -} \ No newline at end of file +} diff --git a/tests/SDK/NDK/World.cpp b/tests/SDK/NDK/World.cpp index 56cb49d92..6fbfcc96a 100644 --- a/tests/SDK/NDK/World.cpp +++ b/tests/SDK/NDK/World.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include namespace { @@ -55,7 +55,7 @@ SCENARIO("World", "[NDK][WORLD]") { GIVEN("A brave new world and the update system") { - Ndk::World world(false); + Ndk::World world; Ndk::BaseSystem& system = world.AddSystem(); WHEN("We had a new entity with an updatable component and a system") @@ -103,7 +103,7 @@ SCENARIO("World", "[NDK][WORLD]") GIVEN("A newly created entity") { - Ndk::World world(false); + Ndk::World world; Ndk::EntityHandle entity = world.CreateEntity(); REQUIRE(entity.IsValid()); @@ -129,7 +129,7 @@ SCENARIO("World", "[NDK][WORLD]") GIVEN("An empty world") { - Ndk::World world(false); + Ndk::World world; WHEN("We create two entities") { diff --git a/tests/main.cpp b/tests/main.cpp index 9ca2bc9b1..5df9976a5 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -1,5 +1,5 @@ #define CATCH_CONFIG_RUNNER -#include +#include #include #include diff --git a/tests/main_client.cpp b/tests/main_client.cpp new file mode 100644 index 000000000..ef92bf2d6 --- /dev/null +++ b/tests/main_client.cpp @@ -0,0 +1,18 @@ +#define CATCH_CONFIG_RUNNER +#include + +#include +#include +#include +#include +#include + +int main(int argc, char* argv[]) +{ + Nz::Modules nazaza; + Ndk::ClientApplication app(argc, argv); + + int result = Catch::Session().run(argc, argv); + + return result; +} diff --git a/tests/resources.cpp b/tests/resources.cpp new file mode 100644 index 000000000..8a71d9249 --- /dev/null +++ b/tests/resources.cpp @@ -0,0 +1,15 @@ +#include + +std::filesystem::path GetResourceDir() +{ + static std::filesystem::path resourceDir = [] + { + std::filesystem::path resourceDir = "resources"; + if (!std::filesystem::is_directory(resourceDir) && std::filesystem::is_directory(".." / resourceDir)) + return ".." / resourceDir; + else + return resourceDir; + + }(); + return resourceDir; +} diff --git a/tests/resources/Engine/Lua/LuaClass.lua b/tests/resources/Engine/Lua/LuaClass.lua deleted file mode 100644 index 3434a7d94..000000000 --- a/tests/resources/Engine/Lua/LuaClass.lua +++ /dev/null @@ -1,24 +0,0 @@ - -function test_Test() - local test = Test(1) - - local i = test:GetI() - local result = Test.StaticMethodWithArguments(i, i) - local finalTest = Test(result + test:GetDefault(), true) - - CheckTest(test) - CheckStatic(result) - CheckFinalTest(finalTest) -end - -function test_InheritTest() - local test = InheritTest() - - CheckInheritTest(test) -end - -function test_TestHandle() - local test = TestHandle() - - CheckTestHandle() -end diff --git a/tests/resources/Engine/Lua/LuaCoroutine.lua b/tests/resources/Engine/Lua/LuaCoroutine.lua deleted file mode 100644 index 4a235cbe5..000000000 --- a/tests/resources/Engine/Lua/LuaCoroutine.lua +++ /dev/null @@ -1,15 +0,0 @@ - -function even (x) - coroutine.yield(1) -end - -function odd (x) - coroutine.yield(0) -end - -function infinite (x) - for i=1,x do - if i==3 then coroutine.yield(-1) end - if i % 2 == 0 then even(i) else odd(i) end - end -end diff --git a/tests/xmake.lua b/tests/xmake.lua new file mode 100644 index 000000000..6e11c9542 --- /dev/null +++ b/tests/xmake.lua @@ -0,0 +1,33 @@ +if is_mode("asan") then + add_defines("CATCH_CONFIG_NO_WINDOWS_SEH") + add_defines("CATCH_CONFIG_NO_POSIX_SIGNALS") +end + +add_requires("catch2") + +target("NazaraClientUnitTests") + set_group("Tests") + set_kind("binary") + + add_deps("NazaraClientSDK") + add_packages("catch2") + + add_files("main_client.cpp") + add_files("resources.cpp") + add_files("Engine/**.cpp") + +target("NazaraUnitTests") + set_group("Tests") + set_kind("binary") + + add_deps("NazaraSDK") + add_packages("catch2") + + add_files("main.cpp") + add_files("resources.cpp") + add_files("Engine/**.cpp") + add_files("SDK/**.cpp") + + del_files("Engine/Audio/**") + del_files("SDK/NDK/Application.cpp") + del_files("SDK/NDK/Systems/ListenerSystem.cpp") diff --git a/thirdparty/build/chipmunk.lua b/thirdparty/build/chipmunk.lua deleted file mode 100644 index 7331be7ca..000000000 --- a/thirdparty/build/chipmunk.lua +++ /dev/null @@ -1,21 +0,0 @@ -LIBRARY.Name = "chipmunk" - -LIBRARY.Defines = { - "CP_USE_CGTYPES=0", - "DRAW_CLOSEST=0", - "DRAW_EPA=0", - "DRAW_GJK=0", - "TARGET_IPHONE_SIMULATOR=0", - "TARGET_OS_IPHONE=0", - "TARGET_OS_MAC=0", -} - -LIBRARY.Language = "C++" -LIBRARY.DisableWarnings = true -- chipmunk has many warnings we can't really fix - -LIBRARY.Files = { - "../thirdparty/include/chipmunk/*.h", - "../thirdparty/src/chipmunk/*.h", - "../thirdparty/src/chipmunk/*.c", -} - diff --git a/thirdparty/build/lua.lua b/thirdparty/build/lua.lua deleted file mode 100644 index df66e0127..000000000 --- a/thirdparty/build/lua.lua +++ /dev/null @@ -1,14 +0,0 @@ -LIBRARY.Name = "lua" - -LIBRARY.Language = "C++" -- Compile as C++ to make Lua use exceptions instead of SJLJ - -LIBRARY.Files = { - "../thirdparty/include/Lua/*.h", - "../thirdparty/include/Lua/*.hpp", - "../thirdparty/src/Lua/*.h", - "../thirdparty/src/Lua/*.cpp" -} - -LIBRARY.OsDefines.Posix = { - "LUA_USE_LINUX" -} diff --git a/thirdparty/build/lua.txt b/thirdparty/build/lua.txt deleted file mode 100644 index 972aa049f..000000000 --- a/thirdparty/build/lua.txt +++ /dev/null @@ -1,95 +0,0 @@ -Changement: -----------------------------Erreurs via exceptions----------------------------- -Remplacement de l'extension de tous les fichiers .c en .cpp - ----------------------------------Compatibilité--------------------------------- --Dans tous les fichiers: - Remplacement des lignes: - #include "lauxlib.h" - #include "lua.h" - #include "luaconf.h" - #include "lualib.h" - - Par les lignes: - #include - #include - #include - #include - ----------------------Support des commentaires longs du C++---------------------- --Fichier llex.cpp (Aux alentours de la ligne 468) -static int llex (LexState *ls, SemInfo *seminfo) { -+#if defined(LUA_CPPCOMT_LONG) -+ int last; -+#endif - luaZ_resetbuffer(ls->buff); - for (;;) { --Fichier llex.cpp (Aux alentours de la ligne 530): - case '/': { - next(ls); - if (check_next1(ls, '/')) return TK_IDIV; -+#if defined(LUA_CPPCOMT_LONG) -+ /* bn 01/2012: added C++-style comments */ -+ /* Lynix 02/2015: Fixed it for Lua 5.3.0 */ -+ else if (check_next1('*')) { -+ last = 0; -+ while (ls->current != EOZ) { -+ if (last == '*' && ls->current == '/') break; -+ last = ls->current; -+ next(ls); /* skip until closing marker (or end of file) */ -+ } -+ if (ls->current == EOZ) -+ lexerror(ls, "unfinished long comment", TK_EOS); -+ else next(ls); -+ } -+#endif /* LUA_CPPCOMT_LONG */ - else return '/'; - } - --Fichier llex.h (Aux alentours de la ligne 20): - -+/* bn 01/2012: added C++-style comments */ -+#define LUA_CPPCOMT_LONG -+/* end changes */ -+ - /* - * WARNING: if you change the order of this enumeration, - * grep "ORDER RESERVED" - ----------------------Support de la négation du C/C++ (!=)---------------------- --Fichier llex.h (Aux alentours de la ligne 15): -+#define LUA_CPPNEG - - /* - * WARNING: if you change the order of this enumeration, - * grep "ORDER RESERVED" --Fichier llex.h (Aux alentours de la ligne 37) - TK_SHL, TK_SHR, - TK_DBCOLON, TK_EOS, -+#ifdef LUA_CPPNEG -+ TK_CNE, -+#endif - TK_FLT, TK_INT, TK_NAME, TK_STRING - --Fichier llex.cpp (Aux alentours de la ligne 44) - "//", "..", "...", "==", ">=", "<=", "~=", - "<<", ">>", "::", "", -+#ifdef LUA_CPPNEG -+ "!=", -+#endif - "", "", "", "" --Fichier llex.cpp (Aux alentours de la ligne 556) - if (check_next1(ls, '/')) return TK_IDIV; - else return '/'; - } -+#ifdef LUA_CPPNEG -+ case '!': { -+ next(ls); -+ if (check_next1(ls, '=')) return TK_NE; -+ else return '!'; -+ } -+#endif - case '~': { - next(ls); - if (check_next1(ls, '=')) return TK_NE; - diff --git a/thirdparty/build/newton.lua b/thirdparty/build/newton.lua deleted file mode 100644 index 1c5bb8995..000000000 --- a/thirdparty/build/newton.lua +++ /dev/null @@ -1,42 +0,0 @@ -LIBRARY.Name = "newton" - -LIBRARY.Defines = { - "_CRT_SECURE_NO_WARNINGS", - "_NEWTON_STATIC_LIB", -} - -LIBRARY.OsDefines.Windows = { - "_WINDOWS" -} - -LIBRARY.Language = "C++" -LIBRARY.DisableWarnings = true -- Newton has many warnings we can't really fix - -LIBRARY.Files = { - "../thirdparty/include/newton/**.h", - "../thirdparty/src/newton/**.h", - "../thirdparty/src/newton/**.c", - "../thirdparty/src/newton/**.cpp", -} - -LIBRARY.Includes = { - "../thirdparty/src/newton/dgCore", - "../thirdparty/src/newton/dgMeshUtil", - "../thirdparty/src/newton/dgPhysics", - "../thirdparty/src/newton/dgNewton", - "../thirdparty/src/newton/dContainers", - "../thirdparty/src/newton/dMath" -} - -LIBRARY.Custom = function() - vectorextensions("SSE3") - - filter({"architecture:x86_64", "system:linux"}) - defines("_POSIX_VER_64") - - filter({"architecture:x86", "system:linux"}) - defines("_POSIX_VER") - - filter({"architecture:x86_64", "system:macosx"}) - defines("_MACOSX_VER") -end diff --git a/thirdparty/build/stb.lua b/thirdparty/build/stb.lua deleted file mode 100644 index c73cc6c41..000000000 --- a/thirdparty/build/stb.lua +++ /dev/null @@ -1,12 +0,0 @@ -LIBRARY.Name = "stb_image" - -LIBRARY.Defines = { - "STBI_NO_STDIO" -} - -LIBRARY.Language = "C++" -- Compile as C++ because C99 isn't widely supported - -LIBRARY.Files = { - "../thirdparty/include/stb/*.h", - "../thirdparty/src/stb/*.cpp" -} diff --git a/thirdparty/include/AL/al.h b/thirdparty/include/AL/al.h deleted file mode 100644 index 413b38331..000000000 --- a/thirdparty/include/AL/al.h +++ /dev/null @@ -1,656 +0,0 @@ -#ifndef AL_AL_H -#define AL_AL_H - -#if defined(__cplusplus) -extern "C" { -#endif - -#ifndef AL_API - #if defined(AL_LIBTYPE_STATIC) - #define AL_API - #elif defined(_WIN32) - #define AL_API __declspec(dllimport) - #else - #define AL_API extern - #endif -#endif - -#if defined(_WIN32) - #define AL_APIENTRY __cdecl -#else - #define AL_APIENTRY -#endif - - -/** Deprecated macro. */ -#define OPENAL -#define ALAPI AL_API -#define ALAPIENTRY AL_APIENTRY -#define AL_INVALID (-1) -#define AL_ILLEGAL_ENUM AL_INVALID_ENUM -#define AL_ILLEGAL_COMMAND AL_INVALID_OPERATION - -/** Supported AL version. */ -#define AL_VERSION_1_0 -#define AL_VERSION_1_1 - -/** 8-bit boolean */ -typedef char ALboolean; - -/** character */ -typedef char ALchar; - -/** signed 8-bit 2's complement integer */ -typedef signed char ALbyte; - -/** unsigned 8-bit integer */ -typedef unsigned char ALubyte; - -/** signed 16-bit 2's complement integer */ -typedef short ALshort; - -/** unsigned 16-bit integer */ -typedef unsigned short ALushort; - -/** signed 32-bit 2's complement integer */ -typedef int ALint; - -/** unsigned 32-bit integer */ -typedef unsigned int ALuint; - -/** non-negative 32-bit binary integer size */ -typedef int ALsizei; - -/** enumerated 32-bit value */ -typedef int ALenum; - -/** 32-bit IEEE754 floating-point */ -typedef float ALfloat; - -/** 64-bit IEEE754 floating-point */ -typedef double ALdouble; - -/** void type (for opaque pointers only) */ -typedef void ALvoid; - - -/* Enumerant values begin at column 50. No tabs. */ - -/** "no distance model" or "no buffer" */ -#define AL_NONE 0 - -/** Boolean False. */ -#define AL_FALSE 0 - -/** Boolean True. */ -#define AL_TRUE 1 - - -/** - * Relative source. - * Type: ALboolean - * Range: [AL_TRUE, AL_FALSE] - * Default: AL_FALSE - * - * Specifies if the Source has relative coordinates. - */ -#define AL_SOURCE_RELATIVE 0x202 - - -/** - * Inner cone angle, in degrees. - * Type: ALint, ALfloat - * Range: [0 - 360] - * Default: 360 - * - * The angle covered by the inner cone, where the source will not attenuate. - */ -#define AL_CONE_INNER_ANGLE 0x1001 - -/** - * Outer cone angle, in degrees. - * Range: [0 - 360] - * Default: 360 - * - * The angle covered by the outer cone, where the source will be fully - * attenuated. - */ -#define AL_CONE_OUTER_ANGLE 0x1002 - -/** - * Source pitch. - * Type: ALfloat - * Range: [0.5 - 2.0] - * Default: 1.0 - * - * A multiplier for the frequency (sample rate) of the source's buffer. - */ -#define AL_PITCH 0x1003 - -/** - * Source or listener position. - * Type: ALfloat[3], ALint[3] - * Default: {0, 0, 0} - * - * The source or listener location in three dimensional space. - * - * OpenAL, like OpenGL, uses a right handed coordinate system, where in a - * frontal default view X (thumb) points right, Y points up (index finger), and - * Z points towards the viewer/camera (middle finger). - * - * To switch from a left handed coordinate system, flip the sign on the Z - * coordinate. - */ -#define AL_POSITION 0x1004 - -/** - * Source direction. - * Type: ALfloat[3], ALint[3] - * Default: {0, 0, 0} - * - * Specifies the current direction in local space. - * A zero-length vector specifies an omni-directional source (cone is ignored). - */ -#define AL_DIRECTION 0x1005 - -/** - * Source or listener velocity. - * Type: ALfloat[3], ALint[3] - * Default: {0, 0, 0} - * - * Specifies the current velocity in local space. - */ -#define AL_VELOCITY 0x1006 - -/** - * Source looping. - * Type: ALboolean - * Range: [AL_TRUE, AL_FALSE] - * Default: AL_FALSE - * - * Specifies whether source is looping. - */ -#define AL_LOOPING 0x1007 - -/** - * Source buffer. - * Type: ALuint - * Range: any valid Buffer. - * - * Specifies the buffer to provide sound samples. - */ -#define AL_BUFFER 0x1009 - -/** - * Source or listener gain. - * Type: ALfloat - * Range: [0.0 - ] - * - * A value of 1.0 means unattenuated. Each division by 2 equals an attenuation - * of about -6dB. Each multiplicaton by 2 equals an amplification of about - * +6dB. - * - * A value of 0.0 is meaningless with respect to a logarithmic scale; it is - * silent. - */ -#define AL_GAIN 0x100A - -/** - * Minimum source gain. - * Type: ALfloat - * Range: [0.0 - 1.0] - * - * The minimum gain allowed for a source, after distance and cone attenation is - * applied (if applicable). - */ -#define AL_MIN_GAIN 0x100D - -/** - * Maximum source gain. - * Type: ALfloat - * Range: [0.0 - 1.0] - * - * The maximum gain allowed for a source, after distance and cone attenation is - * applied (if applicable). - */ -#define AL_MAX_GAIN 0x100E - -/** - * Listener orientation. - * Type: ALfloat[6] - * Default: {0.0, 0.0, -1.0, 0.0, 1.0, 0.0} - * - * Effectively two three dimensional vectors. The first vector is the front (or - * "at") and the second is the top (or "up"). - * - * Both vectors are in local space. - */ -#define AL_ORIENTATION 0x100F - -/** - * Source state (query only). - * Type: ALint - * Range: [AL_INITIAL, AL_PLAYING, AL_PAUSED, AL_STOPPED] - */ -#define AL_SOURCE_STATE 0x1010 - -/** Source state value. */ -#define AL_INITIAL 0x1011 -#define AL_PLAYING 0x1012 -#define AL_PAUSED 0x1013 -#define AL_STOPPED 0x1014 - -/** - * Source Buffer Queue size (query only). - * Type: ALint - * - * The number of buffers queued using alSourceQueueBuffers, minus the buffers - * removed with alSourceUnqueueBuffers. - */ -#define AL_BUFFERS_QUEUED 0x1015 - -/** - * Source Buffer Queue processed count (query only). - * Type: ALint - * - * The number of queued buffers that have been fully processed, and can be - * removed with alSourceUnqueueBuffers. - * - * Looping sources will never fully process buffers because they will be set to - * play again for when the source loops. - */ -#define AL_BUFFERS_PROCESSED 0x1016 - -/** - * Source reference distance. - * Type: ALfloat - * Range: [0.0 - ] - * Default: 1.0 - * - * The distance in units that no attenuation occurs. - * - * At 0.0, no distance attenuation ever occurs on non-linear attenuation models. - */ -#define AL_REFERENCE_DISTANCE 0x1020 - -/** - * Source rolloff factor. - * Type: ALfloat - * Range: [0.0 - ] - * Default: 1.0 - * - * Multiplier to exaggerate or diminish distance attenuation. - * - * At 0.0, no distance attenuation ever occurs. - */ -#define AL_ROLLOFF_FACTOR 0x1021 - -/** - * Outer cone gain. - * Type: ALfloat - * Range: [0.0 - 1.0] - * Default: 0.0 - * - * The gain attenuation applied when the listener is outside of the source's - * outer cone. - */ -#define AL_CONE_OUTER_GAIN 0x1022 - -/** - * Source maximum distance. - * Type: ALfloat - * Range: [0.0 - ] - * Default: +inf - * - * The distance above which the source is not attenuated any further with a - * clamped distance model, or where attenuation reaches 0.0 gain for linear - * distance models with a default rolloff factor. - */ -#define AL_MAX_DISTANCE 0x1023 - -/** Source buffer position, in seconds */ -#define AL_SEC_OFFSET 0x1024 -/** Source buffer position, in sample frames */ -#define AL_SAMPLE_OFFSET 0x1025 -/** Source buffer position, in bytes */ -#define AL_BYTE_OFFSET 0x1026 - -/** - * Source type (query only). - * Type: ALint - * Range: [AL_STATIC, AL_STREAMING, AL_UNDETERMINED] - * - * A Source is Static if a Buffer has been attached using AL_BUFFER. - * - * A Source is Streaming if one or more Buffers have been attached using - * alSourceQueueBuffers. - * - * A Source is Undetermined when it has the NULL buffer attached using - * AL_BUFFER. - */ -#define AL_SOURCE_TYPE 0x1027 - -/** Source type value. */ -#define AL_STATIC 0x1028 -#define AL_STREAMING 0x1029 -#define AL_UNDETERMINED 0x1030 - -/** Buffer format specifier. */ -#define AL_FORMAT_MONO8 0x1100 -#define AL_FORMAT_MONO16 0x1101 -#define AL_FORMAT_STEREO8 0x1102 -#define AL_FORMAT_STEREO16 0x1103 - -/** Buffer frequency (query only). */ -#define AL_FREQUENCY 0x2001 -/** Buffer bits per sample (query only). */ -#define AL_BITS 0x2002 -/** Buffer channel count (query only). */ -#define AL_CHANNELS 0x2003 -/** Buffer data size (query only). */ -#define AL_SIZE 0x2004 - -/** - * Buffer state. - * - * Not for public use. - */ -#define AL_UNUSED 0x2010 -#define AL_PENDING 0x2011 -#define AL_PROCESSED 0x2012 - - -/** No error. */ -#define AL_NO_ERROR 0 - -/** Invalid name paramater passed to AL call. */ -#define AL_INVALID_NAME 0xA001 - -/** Invalid enum parameter passed to AL call. */ -#define AL_INVALID_ENUM 0xA002 - -/** Invalid value parameter passed to AL call. */ -#define AL_INVALID_VALUE 0xA003 - -/** Illegal AL call. */ -#define AL_INVALID_OPERATION 0xA004 - -/** Not enough memory. */ -#define AL_OUT_OF_MEMORY 0xA005 - - -/** Context string: Vendor ID. */ -#define AL_VENDOR 0xB001 -/** Context string: Version. */ -#define AL_VERSION 0xB002 -/** Context string: Renderer ID. */ -#define AL_RENDERER 0xB003 -/** Context string: Space-separated extension list. */ -#define AL_EXTENSIONS 0xB004 - - -/** - * Doppler scale. - * Type: ALfloat - * Range: [0.0 - ] - * Default: 1.0 - * - * Scale for source and listener velocities. - */ -#define AL_DOPPLER_FACTOR 0xC000 -AL_API void AL_APIENTRY alDopplerFactor(ALfloat value); - -/** - * Doppler velocity (deprecated). - * - * A multiplier applied to the Speed of Sound. - */ -#define AL_DOPPLER_VELOCITY 0xC001 -AL_API void AL_APIENTRY alDopplerVelocity(ALfloat value); - -/** - * Speed of Sound, in units per second. - * Type: ALfloat - * Range: [0.0001 - ] - * Default: 343.3 - * - * The speed at which sound waves are assumed to travel, when calculating the - * doppler effect. - */ -#define AL_SPEED_OF_SOUND 0xC003 -AL_API void AL_APIENTRY alSpeedOfSound(ALfloat value); - -/** - * Distance attenuation model. - * Type: ALint - * Range: [AL_NONE, AL_INVERSE_DISTANCE, AL_INVERSE_DISTANCE_CLAMPED, - * AL_LINEAR_DISTANCE, AL_LINEAR_DISTANCE_CLAMPED, - * AL_EXPONENT_DISTANCE, AL_EXPONENT_DISTANCE_CLAMPED] - * Default: AL_INVERSE_DISTANCE_CLAMPED - * - * The model by which sources attenuate with distance. - * - * None - No distance attenuation. - * Inverse - Doubling the distance halves the source gain. - * Linear - Linear gain scaling between the reference and max distances. - * Exponent - Exponential gain dropoff. - * - * Clamped variations work like the non-clamped counterparts, except the - * distance calculated is clamped between the reference and max distances. - */ -#define AL_DISTANCE_MODEL 0xD000 -AL_API void AL_APIENTRY alDistanceModel(ALenum distanceModel); - -/** Distance model value. */ -#define AL_INVERSE_DISTANCE 0xD001 -#define AL_INVERSE_DISTANCE_CLAMPED 0xD002 -#define AL_LINEAR_DISTANCE 0xD003 -#define AL_LINEAR_DISTANCE_CLAMPED 0xD004 -#define AL_EXPONENT_DISTANCE 0xD005 -#define AL_EXPONENT_DISTANCE_CLAMPED 0xD006 - -/** Renderer State management. */ -AL_API void AL_APIENTRY alEnable(ALenum capability); -AL_API void AL_APIENTRY alDisable(ALenum capability); -AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability); - -/** State retrieval. */ -AL_API const ALchar* AL_APIENTRY alGetString(ALenum param); -AL_API void AL_APIENTRY alGetBooleanv(ALenum param, ALboolean *values); -AL_API void AL_APIENTRY alGetIntegerv(ALenum param, ALint *values); -AL_API void AL_APIENTRY alGetFloatv(ALenum param, ALfloat *values); -AL_API void AL_APIENTRY alGetDoublev(ALenum param, ALdouble *values); -AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum param); -AL_API ALint AL_APIENTRY alGetInteger(ALenum param); -AL_API ALfloat AL_APIENTRY alGetFloat(ALenum param); -AL_API ALdouble AL_APIENTRY alGetDouble(ALenum param); - -/** - * Error retrieval. - * - * Obtain the first error generated in the AL context since the last check. - */ -AL_API ALenum AL_APIENTRY alGetError(void); - -/** - * Extension support. - * - * Query for the presence of an extension, and obtain any appropriate function - * pointers and enum values. - */ -AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extname); -AL_API void* AL_APIENTRY alGetProcAddress(const ALchar *fname); -AL_API ALenum AL_APIENTRY alGetEnumValue(const ALchar *ename); - - -/** Set Listener parameters */ -AL_API void AL_APIENTRY alListenerf(ALenum param, ALfloat value); -AL_API void AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); -AL_API void AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values); -AL_API void AL_APIENTRY alListeneri(ALenum param, ALint value); -AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3); -AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values); - -/** Get Listener parameters */ -AL_API void AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value); -AL_API void AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); -AL_API void AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values); -AL_API void AL_APIENTRY alGetListeneri(ALenum param, ALint *value); -AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3); -AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint *values); - - -/** Create Source objects. */ -AL_API void AL_APIENTRY alGenSources(ALsizei n, ALuint *sources); -/** Delete Source objects. */ -AL_API void AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources); -/** Verify a handle is a valid Source. */ -AL_API ALboolean AL_APIENTRY alIsSource(ALuint source); - -/** Set Source parameters. */ -AL_API void AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value); -AL_API void AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); -AL_API void AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values); -AL_API void AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value); -AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3); -AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values); - -/** Get Source parameters. */ -AL_API void AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value); -AL_API void AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); -AL_API void AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values); -AL_API void AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value); -AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3); -AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values); - - -/** Play, replay, or resume (if paused) a list of Sources */ -AL_API void AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources); -/** Stop a list of Sources */ -AL_API void AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources); -/** Rewind a list of Sources */ -AL_API void AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources); -/** Pause a list of Sources */ -AL_API void AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources); - -/** Play, replay, or resume a Source */ -AL_API void AL_APIENTRY alSourcePlay(ALuint source); -/** Stop a Source */ -AL_API void AL_APIENTRY alSourceStop(ALuint source); -/** Rewind a Source (set playback postiton to beginning) */ -AL_API void AL_APIENTRY alSourceRewind(ALuint source); -/** Pause a Source */ -AL_API void AL_APIENTRY alSourcePause(ALuint source); - -/** Queue buffers onto a source */ -AL_API void AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers); -/** Unqueue processed buffers from a source */ -AL_API void AL_APIENTRY alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers); - - -/** Create Buffer objects */ -AL_API void AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers); -/** Delete Buffer objects */ -AL_API void AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers); -/** Verify a handle is a valid Buffer */ -AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer); - -/** Specifies the data to be copied into a buffer */ -AL_API void AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq); - -/** Set Buffer parameters, */ -AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat value); -AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); -AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values); -AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value); -AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3); -AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values); - -/** Get Buffer parameters. */ -AL_API void AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value); -AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); -AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values); -AL_API void AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value); -AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3); -AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values); - -/** Pointer-to-function type, useful for dynamically getting AL entry points. */ -typedef void (AL_APIENTRY *LPALENABLE)(ALenum capability); -typedef void (AL_APIENTRY *LPALDISABLE)(ALenum capability); -typedef ALboolean (AL_APIENTRY *LPALISENABLED)(ALenum capability); -typedef const ALchar* (AL_APIENTRY *LPALGETSTRING)(ALenum param); -typedef void (AL_APIENTRY *LPALGETBOOLEANV)(ALenum param, ALboolean *values); -typedef void (AL_APIENTRY *LPALGETINTEGERV)(ALenum param, ALint *values); -typedef void (AL_APIENTRY *LPALGETFLOATV)(ALenum param, ALfloat *values); -typedef void (AL_APIENTRY *LPALGETDOUBLEV)(ALenum param, ALdouble *values); -typedef ALboolean (AL_APIENTRY *LPALGETBOOLEAN)(ALenum param); -typedef ALint (AL_APIENTRY *LPALGETINTEGER)(ALenum param); -typedef ALfloat (AL_APIENTRY *LPALGETFLOAT)(ALenum param); -typedef ALdouble (AL_APIENTRY *LPALGETDOUBLE)(ALenum param); -typedef ALenum (AL_APIENTRY *LPALGETERROR)(void); -typedef ALboolean (AL_APIENTRY *LPALISEXTENSIONPRESENT)(const ALchar *extname); -typedef void* (AL_APIENTRY *LPALGETPROCADDRESS)(const ALchar *fname); -typedef ALenum (AL_APIENTRY *LPALGETENUMVALUE)(const ALchar *ename); -typedef void (AL_APIENTRY *LPALLISTENERF)(ALenum param, ALfloat value); -typedef void (AL_APIENTRY *LPALLISTENER3F)(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); -typedef void (AL_APIENTRY *LPALLISTENERFV)(ALenum param, const ALfloat *values); -typedef void (AL_APIENTRY *LPALLISTENERI)(ALenum param, ALint value); -typedef void (AL_APIENTRY *LPALLISTENER3I)(ALenum param, ALint value1, ALint value2, ALint value3); -typedef void (AL_APIENTRY *LPALLISTENERIV)(ALenum param, const ALint *values); -typedef void (AL_APIENTRY *LPALGETLISTENERF)(ALenum param, ALfloat *value); -typedef void (AL_APIENTRY *LPALGETLISTENER3F)(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); -typedef void (AL_APIENTRY *LPALGETLISTENERFV)(ALenum param, ALfloat *values); -typedef void (AL_APIENTRY *LPALGETLISTENERI)(ALenum param, ALint *value); -typedef void (AL_APIENTRY *LPALGETLISTENER3I)(ALenum param, ALint *value1, ALint *value2, ALint *value3); -typedef void (AL_APIENTRY *LPALGETLISTENERIV)(ALenum param, ALint *values); -typedef void (AL_APIENTRY *LPALGENSOURCES)(ALsizei n, ALuint *sources); -typedef void (AL_APIENTRY *LPALDELETESOURCES)(ALsizei n, const ALuint *sources); -typedef ALboolean (AL_APIENTRY *LPALISSOURCE)(ALuint source); -typedef void (AL_APIENTRY *LPALSOURCEF)(ALuint source, ALenum param, ALfloat value); -typedef void (AL_APIENTRY *LPALSOURCE3F)(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); -typedef void (AL_APIENTRY *LPALSOURCEFV)(ALuint source, ALenum param, const ALfloat *values); -typedef void (AL_APIENTRY *LPALSOURCEI)(ALuint source, ALenum param, ALint value); -typedef void (AL_APIENTRY *LPALSOURCE3I)(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3); -typedef void (AL_APIENTRY *LPALSOURCEIV)(ALuint source, ALenum param, const ALint *values); -typedef void (AL_APIENTRY *LPALGETSOURCEF)(ALuint source, ALenum param, ALfloat *value); -typedef void (AL_APIENTRY *LPALGETSOURCE3F)(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); -typedef void (AL_APIENTRY *LPALGETSOURCEFV)(ALuint source, ALenum param, ALfloat *values); -typedef void (AL_APIENTRY *LPALGETSOURCEI)(ALuint source, ALenum param, ALint *value); -typedef void (AL_APIENTRY *LPALGETSOURCE3I)(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3); -typedef void (AL_APIENTRY *LPALGETSOURCEIV)(ALuint source, ALenum param, ALint *values); -typedef void (AL_APIENTRY *LPALSOURCEPLAYV)(ALsizei n, const ALuint *sources); -typedef void (AL_APIENTRY *LPALSOURCESTOPV)(ALsizei n, const ALuint *sources); -typedef void (AL_APIENTRY *LPALSOURCEREWINDV)(ALsizei n, const ALuint *sources); -typedef void (AL_APIENTRY *LPALSOURCEPAUSEV)(ALsizei n, const ALuint *sources); -typedef void (AL_APIENTRY *LPALSOURCEPLAY)(ALuint source); -typedef void (AL_APIENTRY *LPALSOURCESTOP)(ALuint source); -typedef void (AL_APIENTRY *LPALSOURCEREWIND)(ALuint source); -typedef void (AL_APIENTRY *LPALSOURCEPAUSE)(ALuint source); -typedef void (AL_APIENTRY *LPALSOURCEQUEUEBUFFERS)(ALuint source, ALsizei nb, const ALuint *buffers); -typedef void (AL_APIENTRY *LPALSOURCEUNQUEUEBUFFERS)(ALuint source, ALsizei nb, ALuint *buffers); -typedef void (AL_APIENTRY *LPALGENBUFFERS)(ALsizei n, ALuint *buffers); -typedef void (AL_APIENTRY *LPALDELETEBUFFERS)(ALsizei n, const ALuint *buffers); -typedef ALboolean (AL_APIENTRY *LPALISBUFFER)(ALuint buffer); -typedef void (AL_APIENTRY *LPALBUFFERDATA)(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq); -typedef void (AL_APIENTRY *LPALBUFFERF)(ALuint buffer, ALenum param, ALfloat value); -typedef void (AL_APIENTRY *LPALBUFFER3F)(ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); -typedef void (AL_APIENTRY *LPALBUFFERFV)(ALuint buffer, ALenum param, const ALfloat *values); -typedef void (AL_APIENTRY *LPALBUFFERI)(ALuint buffer, ALenum param, ALint value); -typedef void (AL_APIENTRY *LPALBUFFER3I)(ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3); -typedef void (AL_APIENTRY *LPALBUFFERIV)(ALuint buffer, ALenum param, const ALint *values); -typedef void (AL_APIENTRY *LPALGETBUFFERF)(ALuint buffer, ALenum param, ALfloat *value); -typedef void (AL_APIENTRY *LPALGETBUFFER3F)(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); -typedef void (AL_APIENTRY *LPALGETBUFFERFV)(ALuint buffer, ALenum param, ALfloat *values); -typedef void (AL_APIENTRY *LPALGETBUFFERI)(ALuint buffer, ALenum param, ALint *value); -typedef void (AL_APIENTRY *LPALGETBUFFER3I)(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3); -typedef void (AL_APIENTRY *LPALGETBUFFERIV)(ALuint buffer, ALenum param, ALint *values); -typedef void (AL_APIENTRY *LPALDOPPLERFACTOR)(ALfloat value); -typedef void (AL_APIENTRY *LPALDOPPLERVELOCITY)(ALfloat value); -typedef void (AL_APIENTRY *LPALSPEEDOFSOUND)(ALfloat value); -typedef void (AL_APIENTRY *LPALDISTANCEMODEL)(ALenum distanceModel); - -#if defined(__cplusplus) -} /* extern "C" */ -#endif - -#endif /* AL_AL_H */ diff --git a/thirdparty/include/AL/alc.h b/thirdparty/include/AL/alc.h deleted file mode 100644 index 294e8b33c..000000000 --- a/thirdparty/include/AL/alc.h +++ /dev/null @@ -1,237 +0,0 @@ -#ifndef AL_ALC_H -#define AL_ALC_H - -#if defined(__cplusplus) -extern "C" { -#endif - -#ifndef ALC_API - #if defined(AL_LIBTYPE_STATIC) - #define ALC_API - #elif defined(_WIN32) - #define ALC_API __declspec(dllimport) - #else - #define ALC_API extern - #endif -#endif - -#if defined(_WIN32) - #define ALC_APIENTRY __cdecl -#else - #define ALC_APIENTRY -#endif - - -/** Deprecated macro. */ -#define ALCAPI ALC_API -#define ALCAPIENTRY ALC_APIENTRY -#define ALC_INVALID 0 - -/** Supported ALC version? */ -#define ALC_VERSION_0_1 1 - -/** Opaque device handle */ -typedef struct ALCdevice_struct ALCdevice; -/** Opaque context handle */ -typedef struct ALCcontext_struct ALCcontext; - -/** 8-bit boolean */ -typedef char ALCboolean; - -/** character */ -typedef char ALCchar; - -/** signed 8-bit 2's complement integer */ -typedef signed char ALCbyte; - -/** unsigned 8-bit integer */ -typedef unsigned char ALCubyte; - -/** signed 16-bit 2's complement integer */ -typedef short ALCshort; - -/** unsigned 16-bit integer */ -typedef unsigned short ALCushort; - -/** signed 32-bit 2's complement integer */ -typedef int ALCint; - -/** unsigned 32-bit integer */ -typedef unsigned int ALCuint; - -/** non-negative 32-bit binary integer size */ -typedef int ALCsizei; - -/** enumerated 32-bit value */ -typedef int ALCenum; - -/** 32-bit IEEE754 floating-point */ -typedef float ALCfloat; - -/** 64-bit IEEE754 floating-point */ -typedef double ALCdouble; - -/** void type (for opaque pointers only) */ -typedef void ALCvoid; - - -/* Enumerant values begin at column 50. No tabs. */ - -/** Boolean False. */ -#define ALC_FALSE 0 - -/** Boolean True. */ -#define ALC_TRUE 1 - -/** Context attribute: Hz. */ -#define ALC_FREQUENCY 0x1007 - -/** Context attribute: Hz. */ -#define ALC_REFRESH 0x1008 - -/** Context attribute: AL_TRUE or AL_FALSE. */ -#define ALC_SYNC 0x1009 - -/** Context attribute: requested Mono (3D) Sources. */ -#define ALC_MONO_SOURCES 0x1010 - -/** Context attribute: requested Stereo Sources. */ -#define ALC_STEREO_SOURCES 0x1011 - -/** No error. */ -#define ALC_NO_ERROR 0 - -/** Invalid device handle. */ -#define ALC_INVALID_DEVICE 0xA001 - -/** Invalid context handle. */ -#define ALC_INVALID_CONTEXT 0xA002 - -/** Invalid enum parameter passed to an ALC call. */ -#define ALC_INVALID_ENUM 0xA003 - -/** Invalid value parameter passed to an ALC call. */ -#define ALC_INVALID_VALUE 0xA004 - -/** Out of memory. */ -#define ALC_OUT_OF_MEMORY 0xA005 - - -/** Runtime ALC version. */ -#define ALC_MAJOR_VERSION 0x1000 -#define ALC_MINOR_VERSION 0x1001 - -/** Context attribute list properties. */ -#define ALC_ATTRIBUTES_SIZE 0x1002 -#define ALC_ALL_ATTRIBUTES 0x1003 - -/** String for the default device specifier. */ -#define ALC_DEFAULT_DEVICE_SPECIFIER 0x1004 -/** - * String for the given device's specifier. - * - * If device handle is NULL, it is instead a null-char separated list of - * strings of known device specifiers (list ends with an empty string). - */ -#define ALC_DEVICE_SPECIFIER 0x1005 -/** String for space-separated list of ALC extensions. */ -#define ALC_EXTENSIONS 0x1006 - - -/** Capture extension */ -#define ALC_EXT_CAPTURE 1 -/** - * String for the given capture device's specifier. - * - * If device handle is NULL, it is instead a null-char separated list of - * strings of known capture device specifiers (list ends with an empty string). - */ -#define ALC_CAPTURE_DEVICE_SPECIFIER 0x310 -/** String for the default capture device specifier. */ -#define ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER 0x311 -/** Number of sample frames available for capture. */ -#define ALC_CAPTURE_SAMPLES 0x312 - - -/** Enumerate All extension */ -#define ALC_ENUMERATE_ALL_EXT 1 -/** String for the default extended device specifier. */ -#define ALC_DEFAULT_ALL_DEVICES_SPECIFIER 0x1012 -/** - * String for the given extended device's specifier. - * - * If device handle is NULL, it is instead a null-char separated list of - * strings of known extended device specifiers (list ends with an empty string). - */ -#define ALC_ALL_DEVICES_SPECIFIER 0x1013 - - -/** Context management. */ -ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint* attrlist); -ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context); -ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context); -ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context); -ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context); -ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void); -ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context); - -/** Device management. */ -ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename); -ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device); - - -/** - * Error support. - * - * Obtain the most recent Device error. - */ -ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device); - -/** - * Extension support. - * - * Query for the presence of an extension, and obtain any appropriate - * function pointers and enum values. - */ -ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname); -ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname); -ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname); - -/** Query function. */ -ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param); -ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values); - -/** Capture function. */ -ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize); -ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device); -ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device); -ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device); -ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples); - -/** Pointer-to-function type, useful for dynamically getting ALC entry points. */ -typedef ALCcontext* (ALC_APIENTRY *LPALCCREATECONTEXT)(ALCdevice *device, const ALCint *attrlist); -typedef ALCboolean (ALC_APIENTRY *LPALCMAKECONTEXTCURRENT)(ALCcontext *context); -typedef void (ALC_APIENTRY *LPALCPROCESSCONTEXT)(ALCcontext *context); -typedef void (ALC_APIENTRY *LPALCSUSPENDCONTEXT)(ALCcontext *context); -typedef void (ALC_APIENTRY *LPALCDESTROYCONTEXT)(ALCcontext *context); -typedef ALCcontext* (ALC_APIENTRY *LPALCGETCURRENTCONTEXT)(void); -typedef ALCdevice* (ALC_APIENTRY *LPALCGETCONTEXTSDEVICE)(ALCcontext *context); -typedef ALCdevice* (ALC_APIENTRY *LPALCOPENDEVICE)(const ALCchar *devicename); -typedef ALCboolean (ALC_APIENTRY *LPALCCLOSEDEVICE)(ALCdevice *device); -typedef ALCenum (ALC_APIENTRY *LPALCGETERROR)(ALCdevice *device); -typedef ALCboolean (ALC_APIENTRY *LPALCISEXTENSIONPRESENT)(ALCdevice *device, const ALCchar *extname); -typedef void* (ALC_APIENTRY *LPALCGETPROCADDRESS)(ALCdevice *device, const ALCchar *funcname); -typedef ALCenum (ALC_APIENTRY *LPALCGETENUMVALUE)(ALCdevice *device, const ALCchar *enumname); -typedef const ALCchar* (ALC_APIENTRY *LPALCGETSTRING)(ALCdevice *device, ALCenum param); -typedef void (ALC_APIENTRY *LPALCGETINTEGERV)(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values); -typedef ALCdevice* (ALC_APIENTRY *LPALCCAPTUREOPENDEVICE)(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize); -typedef ALCboolean (ALC_APIENTRY *LPALCCAPTURECLOSEDEVICE)(ALCdevice *device); -typedef void (ALC_APIENTRY *LPALCCAPTURESTART)(ALCdevice *device); -typedef void (ALC_APIENTRY *LPALCCAPTURESTOP)(ALCdevice *device); -typedef void (ALC_APIENTRY *LPALCCAPTURESAMPLES)(ALCdevice *device, ALCvoid *buffer, ALCsizei samples); - -#if defined(__cplusplus) -} -#endif - -#endif /* AL_ALC_H */ diff --git a/thirdparty/include/AL/alext.h b/thirdparty/include/AL/alext.h deleted file mode 100644 index 7d2a95274..000000000 --- a/thirdparty/include/AL/alext.h +++ /dev/null @@ -1,400 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2008 by authors. - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#ifndef AL_ALEXT_H -#define AL_ALEXT_H - -#include -/* Define int64_t and uint64_t types */ -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -#include -#elif defined(_WIN32) && defined(__GNUC__) -#include -#elif defined(_WIN32) -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#else -/* Fallback if nothing above works */ -#include -#endif - -#include "alc.h" -#include "al.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef AL_LOKI_IMA_ADPCM_format -#define AL_LOKI_IMA_ADPCM_format 1 -#define AL_FORMAT_IMA_ADPCM_MONO16_EXT 0x10000 -#define AL_FORMAT_IMA_ADPCM_STEREO16_EXT 0x10001 -#endif - -#ifndef AL_LOKI_WAVE_format -#define AL_LOKI_WAVE_format 1 -#define AL_FORMAT_WAVE_EXT 0x10002 -#endif - -#ifndef AL_EXT_vorbis -#define AL_EXT_vorbis 1 -#define AL_FORMAT_VORBIS_EXT 0x10003 -#endif - -#ifndef AL_LOKI_quadriphonic -#define AL_LOKI_quadriphonic 1 -#define AL_FORMAT_QUAD8_LOKI 0x10004 -#define AL_FORMAT_QUAD16_LOKI 0x10005 -#endif - -#ifndef AL_EXT_float32 -#define AL_EXT_float32 1 -#define AL_FORMAT_MONO_FLOAT32 0x10010 -#define AL_FORMAT_STEREO_FLOAT32 0x10011 -#endif - -#ifndef AL_EXT_double -#define AL_EXT_double 1 -#define AL_FORMAT_MONO_DOUBLE_EXT 0x10012 -#define AL_FORMAT_STEREO_DOUBLE_EXT 0x10013 -#endif - -#ifndef AL_EXT_MULAW -#define AL_EXT_MULAW 1 -#define AL_FORMAT_MONO_MULAW_EXT 0x10014 -#define AL_FORMAT_STEREO_MULAW_EXT 0x10015 -#endif - -#ifndef AL_EXT_ALAW -#define AL_EXT_ALAW 1 -#define AL_FORMAT_MONO_ALAW_EXT 0x10016 -#define AL_FORMAT_STEREO_ALAW_EXT 0x10017 -#endif - -#ifndef ALC_LOKI_audio_channel -#define ALC_LOKI_audio_channel 1 -#define ALC_CHAN_MAIN_LOKI 0x500001 -#define ALC_CHAN_PCM_LOKI 0x500002 -#define ALC_CHAN_CD_LOKI 0x500003 -#endif - -#ifndef AL_EXT_MCFORMATS -#define AL_EXT_MCFORMATS 1 -#define AL_FORMAT_QUAD8 0x1204 -#define AL_FORMAT_QUAD16 0x1205 -#define AL_FORMAT_QUAD32 0x1206 -#define AL_FORMAT_REAR8 0x1207 -#define AL_FORMAT_REAR16 0x1208 -#define AL_FORMAT_REAR32 0x1209 -#define AL_FORMAT_51CHN8 0x120A -#define AL_FORMAT_51CHN16 0x120B -#define AL_FORMAT_51CHN32 0x120C -#define AL_FORMAT_61CHN8 0x120D -#define AL_FORMAT_61CHN16 0x120E -#define AL_FORMAT_61CHN32 0x120F -#define AL_FORMAT_71CHN8 0x1210 -#define AL_FORMAT_71CHN16 0x1211 -#define AL_FORMAT_71CHN32 0x1212 -#endif - -#ifndef AL_EXT_MULAW_MCFORMATS -#define AL_EXT_MULAW_MCFORMATS 1 -#define AL_FORMAT_MONO_MULAW 0x10014 -#define AL_FORMAT_STEREO_MULAW 0x10015 -#define AL_FORMAT_QUAD_MULAW 0x10021 -#define AL_FORMAT_REAR_MULAW 0x10022 -#define AL_FORMAT_51CHN_MULAW 0x10023 -#define AL_FORMAT_61CHN_MULAW 0x10024 -#define AL_FORMAT_71CHN_MULAW 0x10025 -#endif - -#ifndef AL_EXT_IMA4 -#define AL_EXT_IMA4 1 -#define AL_FORMAT_MONO_IMA4 0x1300 -#define AL_FORMAT_STEREO_IMA4 0x1301 -#endif - -#ifndef AL_EXT_STATIC_BUFFER -#define AL_EXT_STATIC_BUFFER 1 -typedef ALvoid (AL_APIENTRY*PFNALBUFFERDATASTATICPROC)(const ALint,ALenum,ALvoid*,ALsizei,ALsizei); -#ifdef AL_ALEXT_PROTOTYPES -AL_API ALvoid AL_APIENTRY alBufferDataStatic(const ALint buffer, ALenum format, ALvoid *data, ALsizei len, ALsizei freq); -#endif -#endif - -#ifndef ALC_EXT_EFX -#define ALC_EXT_EFX 1 -#include "efx.h" -#endif - -#ifndef ALC_EXT_disconnect -#define ALC_EXT_disconnect 1 -#define ALC_CONNECTED 0x313 -#endif - -#ifndef ALC_EXT_thread_local_context -#define ALC_EXT_thread_local_context 1 -typedef ALCboolean (ALC_APIENTRY*PFNALCSETTHREADCONTEXTPROC)(ALCcontext *context); -typedef ALCcontext* (ALC_APIENTRY*PFNALCGETTHREADCONTEXTPROC)(void); -#ifdef AL_ALEXT_PROTOTYPES -ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context); -ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void); -#endif -#endif - -#ifndef AL_EXT_source_distance_model -#define AL_EXT_source_distance_model 1 -#define AL_SOURCE_DISTANCE_MODEL 0x200 -#endif - -#ifndef AL_SOFT_buffer_sub_data -#define AL_SOFT_buffer_sub_data 1 -#define AL_BYTE_RW_OFFSETS_SOFT 0x1031 -#define AL_SAMPLE_RW_OFFSETS_SOFT 0x1032 -typedef ALvoid (AL_APIENTRY*PFNALBUFFERSUBDATASOFTPROC)(ALuint,ALenum,const ALvoid*,ALsizei,ALsizei); -#ifdef AL_ALEXT_PROTOTYPES -AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length); -#endif -#endif - -#ifndef AL_SOFT_loop_points -#define AL_SOFT_loop_points 1 -#define AL_LOOP_POINTS_SOFT 0x2015 -#endif - -#ifndef AL_EXT_FOLDBACK -#define AL_EXT_FOLDBACK 1 -#define AL_EXT_FOLDBACK_NAME "AL_EXT_FOLDBACK" -#define AL_FOLDBACK_EVENT_BLOCK 0x4112 -#define AL_FOLDBACK_EVENT_START 0x4111 -#define AL_FOLDBACK_EVENT_STOP 0x4113 -#define AL_FOLDBACK_MODE_MONO 0x4101 -#define AL_FOLDBACK_MODE_STEREO 0x4102 -typedef void (AL_APIENTRY*LPALFOLDBACKCALLBACK)(ALenum,ALsizei); -typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTART)(ALenum,ALsizei,ALsizei,ALfloat*,LPALFOLDBACKCALLBACK); -typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTOP)(void); -#ifdef AL_ALEXT_PROTOTYPES -AL_API void AL_APIENTRY alRequestFoldbackStart(ALenum mode,ALsizei count,ALsizei length,ALfloat *mem,LPALFOLDBACKCALLBACK callback); -AL_API void AL_APIENTRY alRequestFoldbackStop(void); -#endif -#endif - -#ifndef ALC_EXT_DEDICATED -#define ALC_EXT_DEDICATED 1 -#define AL_DEDICATED_GAIN 0x0001 -#define AL_EFFECT_DEDICATED_DIALOGUE 0x9001 -#define AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT 0x9000 -#endif - -#ifndef AL_SOFT_buffer_samples -#define AL_SOFT_buffer_samples 1 -/* Channel configurations */ -#define AL_MONO_SOFT 0x1500 -#define AL_STEREO_SOFT 0x1501 -#define AL_REAR_SOFT 0x1502 -#define AL_QUAD_SOFT 0x1503 -#define AL_5POINT1_SOFT 0x1504 -#define AL_6POINT1_SOFT 0x1505 -#define AL_7POINT1_SOFT 0x1506 - -/* Sample types */ -#define AL_BYTE_SOFT 0x1400 -#define AL_UNSIGNED_BYTE_SOFT 0x1401 -#define AL_SHORT_SOFT 0x1402 -#define AL_UNSIGNED_SHORT_SOFT 0x1403 -#define AL_INT_SOFT 0x1404 -#define AL_UNSIGNED_INT_SOFT 0x1405 -#define AL_FLOAT_SOFT 0x1406 -#define AL_DOUBLE_SOFT 0x1407 -#define AL_BYTE3_SOFT 0x1408 -#define AL_UNSIGNED_BYTE3_SOFT 0x1409 - -/* Storage formats */ -#define AL_MONO8_SOFT 0x1100 -#define AL_MONO16_SOFT 0x1101 -#define AL_MONO32F_SOFT 0x10010 -#define AL_STEREO8_SOFT 0x1102 -#define AL_STEREO16_SOFT 0x1103 -#define AL_STEREO32F_SOFT 0x10011 -#define AL_QUAD8_SOFT 0x1204 -#define AL_QUAD16_SOFT 0x1205 -#define AL_QUAD32F_SOFT 0x1206 -#define AL_REAR8_SOFT 0x1207 -#define AL_REAR16_SOFT 0x1208 -#define AL_REAR32F_SOFT 0x1209 -#define AL_5POINT1_8_SOFT 0x120A -#define AL_5POINT1_16_SOFT 0x120B -#define AL_5POINT1_32F_SOFT 0x120C -#define AL_6POINT1_8_SOFT 0x120D -#define AL_6POINT1_16_SOFT 0x120E -#define AL_6POINT1_32F_SOFT 0x120F -#define AL_7POINT1_8_SOFT 0x1210 -#define AL_7POINT1_16_SOFT 0x1211 -#define AL_7POINT1_32F_SOFT 0x1212 - -/* Buffer attributes */ -#define AL_INTERNAL_FORMAT_SOFT 0x2008 -#define AL_BYTE_LENGTH_SOFT 0x2009 -#define AL_SAMPLE_LENGTH_SOFT 0x200A -#define AL_SEC_LENGTH_SOFT 0x200B - -typedef void (AL_APIENTRY*LPALBUFFERSAMPLESSOFT)(ALuint,ALuint,ALenum,ALsizei,ALenum,ALenum,const ALvoid*); -typedef void (AL_APIENTRY*LPALBUFFERSUBSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,const ALvoid*); -typedef void (AL_APIENTRY*LPALGETBUFFERSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,ALvoid*); -typedef ALboolean (AL_APIENTRY*LPALISBUFFERFORMATSUPPORTEDSOFT)(ALenum); -#ifdef AL_ALEXT_PROTOTYPES -AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, ALuint samplerate, ALenum internalformat, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data); -AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data); -AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, ALvoid *data); -AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); -#endif -#endif - -#ifndef AL_SOFT_direct_channels -#define AL_SOFT_direct_channels 1 -#define AL_DIRECT_CHANNELS_SOFT 0x1033 -#endif - -#ifndef ALC_SOFT_loopback -#define ALC_SOFT_loopback 1 -#define ALC_FORMAT_CHANNELS_SOFT 0x1990 -#define ALC_FORMAT_TYPE_SOFT 0x1991 - -/* Sample types */ -#define ALC_BYTE_SOFT 0x1400 -#define ALC_UNSIGNED_BYTE_SOFT 0x1401 -#define ALC_SHORT_SOFT 0x1402 -#define ALC_UNSIGNED_SHORT_SOFT 0x1403 -#define ALC_INT_SOFT 0x1404 -#define ALC_UNSIGNED_INT_SOFT 0x1405 -#define ALC_FLOAT_SOFT 0x1406 - -/* Channel configurations */ -#define ALC_MONO_SOFT 0x1500 -#define ALC_STEREO_SOFT 0x1501 -#define ALC_QUAD_SOFT 0x1503 -#define ALC_5POINT1_SOFT 0x1504 -#define ALC_6POINT1_SOFT 0x1505 -#define ALC_7POINT1_SOFT 0x1506 - -typedef ALCdevice* (ALC_APIENTRY*LPALCLOOPBACKOPENDEVICESOFT)(const ALCchar*); -typedef ALCboolean (ALC_APIENTRY*LPALCISRENDERFORMATSUPPORTEDSOFT)(ALCdevice*,ALCsizei,ALCenum,ALCenum); -typedef void (ALC_APIENTRY*LPALCRENDERSAMPLESSOFT)(ALCdevice*,ALCvoid*,ALCsizei); -#ifdef AL_ALEXT_PROTOTYPES -ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName); -ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type); -ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples); -#endif -#endif - -#ifndef AL_EXT_STEREO_ANGLES -#define AL_EXT_STEREO_ANGLES 1 -#define AL_STEREO_ANGLES 0x1030 -#endif - -#ifndef AL_EXT_SOURCE_RADIUS -#define AL_EXT_SOURCE_RADIUS 1 -#define AL_SOURCE_RADIUS 0x1031 -#endif - -#ifndef AL_SOFT_source_latency -#define AL_SOFT_source_latency 1 -#define AL_SAMPLE_OFFSET_LATENCY_SOFT 0x1200 -#define AL_SEC_OFFSET_LATENCY_SOFT 0x1201 -typedef int64_t ALint64SOFT; -typedef uint64_t ALuint64SOFT; -typedef void (AL_APIENTRY*LPALSOURCEDSOFT)(ALuint,ALenum,ALdouble); -typedef void (AL_APIENTRY*LPALSOURCE3DSOFT)(ALuint,ALenum,ALdouble,ALdouble,ALdouble); -typedef void (AL_APIENTRY*LPALSOURCEDVSOFT)(ALuint,ALenum,const ALdouble*); -typedef void (AL_APIENTRY*LPALGETSOURCEDSOFT)(ALuint,ALenum,ALdouble*); -typedef void (AL_APIENTRY*LPALGETSOURCE3DSOFT)(ALuint,ALenum,ALdouble*,ALdouble*,ALdouble*); -typedef void (AL_APIENTRY*LPALGETSOURCEDVSOFT)(ALuint,ALenum,ALdouble*); -typedef void (AL_APIENTRY*LPALSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT); -typedef void (AL_APIENTRY*LPALSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT,ALint64SOFT,ALint64SOFT); -typedef void (AL_APIENTRY*LPALSOURCEI64VSOFT)(ALuint,ALenum,const ALint64SOFT*); -typedef void (AL_APIENTRY*LPALGETSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT*); -typedef void (AL_APIENTRY*LPALGETSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT*,ALint64SOFT*,ALint64SOFT*); -typedef void (AL_APIENTRY*LPALGETSOURCEI64VSOFT)(ALuint,ALenum,ALint64SOFT*); -#ifdef AL_ALEXT_PROTOTYPES -AL_API void AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value); -AL_API void AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3); -AL_API void AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values); -AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value); -AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3); -AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values); -AL_API void AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value); -AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3); -AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values); -AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value); -AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3); -AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values); -#endif -#endif - -#ifndef ALC_EXT_DEFAULT_FILTER_ORDER -#define ALC_EXT_DEFAULT_FILTER_ORDER 1 -#define ALC_DEFAULT_FILTER_ORDER 0x1100 -#endif - -#ifndef AL_SOFT_deferred_updates -#define AL_SOFT_deferred_updates 1 -#define AL_DEFERRED_UPDATES_SOFT 0xC002 -typedef ALvoid (AL_APIENTRY*LPALDEFERUPDATESSOFT)(void); -typedef ALvoid (AL_APIENTRY*LPALPROCESSUPDATESSOFT)(void); -#ifdef AL_ALEXT_PROTOTYPES -AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void); -AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void); -#endif -#endif - -#ifndef AL_SOFT_block_alignment -#define AL_SOFT_block_alignment 1 -#define AL_UNPACK_BLOCK_ALIGNMENT_SOFT 0x200C -#define AL_PACK_BLOCK_ALIGNMENT_SOFT 0x200D -#endif - -#ifndef AL_SOFT_MSADPCM -#define AL_SOFT_MSADPCM 1 -#define AL_FORMAT_MONO_MSADPCM_SOFT 0x1302 -#define AL_FORMAT_STEREO_MSADPCM_SOFT 0x1303 -#endif - -#ifndef AL_SOFT_source_length -#define AL_SOFT_source_length 1 -/*#define AL_BYTE_LENGTH_SOFT 0x2009*/ -/*#define AL_SAMPLE_LENGTH_SOFT 0x200A*/ -/*#define AL_SEC_LENGTH_SOFT 0x200B*/ -#endif - -#ifndef ALC_SOFT_pause_device -#define ALC_SOFT_pause_device 1 -typedef void (ALC_APIENTRY*LPALCDEVICEPAUSESOFT)(ALCdevice *device); -typedef void (ALC_APIENTRY*LPALCDEVICERESUMESOFT)(ALCdevice *device); -#ifdef AL_ALEXT_PROTOTYPES -ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device); -ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device); -#endif -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/thirdparty/include/AL/efx-creative.h b/thirdparty/include/AL/efx-creative.h deleted file mode 100644 index 0a04c982e..000000000 --- a/thirdparty/include/AL/efx-creative.h +++ /dev/null @@ -1,3 +0,0 @@ -/* The tokens that would be defined here are already defined in efx.h. This - * empty file is here to provide compatibility with Windows-based projects - * that would include it. */ diff --git a/thirdparty/include/AL/efx-presets.h b/thirdparty/include/AL/efx-presets.h deleted file mode 100644 index 86dcbda2f..000000000 --- a/thirdparty/include/AL/efx-presets.h +++ /dev/null @@ -1,402 +0,0 @@ -/* Reverb presets for EFX */ - -#ifndef EFX_PRESETS_H -#define EFX_PRESETS_H - -#ifndef EFXEAXREVERBPROPERTIES_DEFINED -#define EFXEAXREVERBPROPERTIES_DEFINED -typedef struct { - float flDensity; - float flDiffusion; - float flGain; - float flGainHF; - float flGainLF; - float flDecayTime; - float flDecayHFRatio; - float flDecayLFRatio; - float flReflectionsGain; - float flReflectionsDelay; - float flReflectionsPan[3]; - float flLateReverbGain; - float flLateReverbDelay; - float flLateReverbPan[3]; - float flEchoTime; - float flEchoDepth; - float flModulationTime; - float flModulationDepth; - float flAirAbsorptionGainHF; - float flHFReference; - float flLFReference; - float flRoomRolloffFactor; - int iDecayHFLimit; -} EFXEAXREVERBPROPERTIES, *LPEFXEAXREVERBPROPERTIES; -#endif - -/* Default Presets */ - -#define EFX_REVERB_PRESET_GENERIC \ - { 1.0000f, 1.0000f, 0.3162f, 0.8913f, 1.0000f, 1.4900f, 0.8300f, 1.0000f, 0.0500f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_PADDEDCELL \ - { 0.1715f, 1.0000f, 0.3162f, 0.0010f, 1.0000f, 0.1700f, 0.1000f, 1.0000f, 0.2500f, 0.0010f, { 0.0000f, 0.0000f, 0.0000f }, 1.2691f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_ROOM \ - { 0.4287f, 1.0000f, 0.3162f, 0.5929f, 1.0000f, 0.4000f, 0.8300f, 1.0000f, 0.1503f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 1.0629f, 0.0030f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_BATHROOM \ - { 0.1715f, 1.0000f, 0.3162f, 0.2512f, 1.0000f, 1.4900f, 0.5400f, 1.0000f, 0.6531f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 3.2734f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_LIVINGROOM \ - { 0.9766f, 1.0000f, 0.3162f, 0.0010f, 1.0000f, 0.5000f, 0.1000f, 1.0000f, 0.2051f, 0.0030f, { 0.0000f, 0.0000f, 0.0000f }, 0.2805f, 0.0040f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_STONEROOM \ - { 1.0000f, 1.0000f, 0.3162f, 0.7079f, 1.0000f, 2.3100f, 0.6400f, 1.0000f, 0.4411f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1003f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_AUDITORIUM \ - { 1.0000f, 1.0000f, 0.3162f, 0.5781f, 1.0000f, 4.3200f, 0.5900f, 1.0000f, 0.4032f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.7170f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CONCERTHALL \ - { 1.0000f, 1.0000f, 0.3162f, 0.5623f, 1.0000f, 3.9200f, 0.7000f, 1.0000f, 0.2427f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.9977f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CAVE \ - { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 1.0000f, 2.9100f, 1.3000f, 1.0000f, 0.5000f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.7063f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_ARENA \ - { 1.0000f, 1.0000f, 0.3162f, 0.4477f, 1.0000f, 7.2400f, 0.3300f, 1.0000f, 0.2612f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.0186f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_HANGAR \ - { 1.0000f, 1.0000f, 0.3162f, 0.3162f, 1.0000f, 10.0500f, 0.2300f, 1.0000f, 0.5000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2560f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CARPETEDHALLWAY \ - { 0.4287f, 1.0000f, 0.3162f, 0.0100f, 1.0000f, 0.3000f, 0.1000f, 1.0000f, 0.1215f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 0.1531f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_HALLWAY \ - { 0.3645f, 1.0000f, 0.3162f, 0.7079f, 1.0000f, 1.4900f, 0.5900f, 1.0000f, 0.2458f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.6615f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_STONECORRIDOR \ - { 1.0000f, 1.0000f, 0.3162f, 0.7612f, 1.0000f, 2.7000f, 0.7900f, 1.0000f, 0.2472f, 0.0130f, { 0.0000f, 0.0000f, 0.0000f }, 1.5758f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_ALLEY \ - { 1.0000f, 0.3000f, 0.3162f, 0.7328f, 1.0000f, 1.4900f, 0.8600f, 1.0000f, 0.2500f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.9954f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.9500f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_FOREST \ - { 1.0000f, 0.3000f, 0.3162f, 0.0224f, 1.0000f, 1.4900f, 0.5400f, 1.0000f, 0.0525f, 0.1620f, { 0.0000f, 0.0000f, 0.0000f }, 0.7682f, 0.0880f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CITY \ - { 1.0000f, 0.5000f, 0.3162f, 0.3981f, 1.0000f, 1.4900f, 0.6700f, 1.0000f, 0.0730f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.1427f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_MOUNTAINS \ - { 1.0000f, 0.2700f, 0.3162f, 0.0562f, 1.0000f, 1.4900f, 0.2100f, 1.0000f, 0.0407f, 0.3000f, { 0.0000f, 0.0000f, 0.0000f }, 0.1919f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_QUARRY \ - { 1.0000f, 1.0000f, 0.3162f, 0.3162f, 1.0000f, 1.4900f, 0.8300f, 1.0000f, 0.0000f, 0.0610f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0250f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.7000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_PLAIN \ - { 1.0000f, 0.2100f, 0.3162f, 0.1000f, 1.0000f, 1.4900f, 0.5000f, 1.0000f, 0.0585f, 0.1790f, { 0.0000f, 0.0000f, 0.0000f }, 0.1089f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_PARKINGLOT \ - { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 1.0000f, 1.6500f, 1.5000f, 1.0000f, 0.2082f, 0.0080f, { 0.0000f, 0.0000f, 0.0000f }, 0.2652f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_SEWERPIPE \ - { 0.3071f, 0.8000f, 0.3162f, 0.3162f, 1.0000f, 2.8100f, 0.1400f, 1.0000f, 1.6387f, 0.0140f, { 0.0000f, 0.0000f, 0.0000f }, 3.2471f, 0.0210f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_UNDERWATER \ - { 0.3645f, 1.0000f, 0.3162f, 0.0100f, 1.0000f, 1.4900f, 0.1000f, 1.0000f, 0.5963f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 7.0795f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 1.1800f, 0.3480f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_DRUGGED \ - { 0.4287f, 0.5000f, 0.3162f, 1.0000f, 1.0000f, 8.3900f, 1.3900f, 1.0000f, 0.8760f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 3.1081f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_DIZZY \ - { 0.3645f, 0.6000f, 0.3162f, 0.6310f, 1.0000f, 17.2300f, 0.5600f, 1.0000f, 0.1392f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.4937f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.8100f, 0.3100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_PSYCHOTIC \ - { 0.0625f, 0.5000f, 0.3162f, 0.8404f, 1.0000f, 7.5600f, 0.9100f, 1.0000f, 0.4864f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 2.4378f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 4.0000f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -/* Castle Presets */ - -#define EFX_REVERB_PRESET_CASTLE_SMALLROOM \ - { 1.0000f, 0.8900f, 0.3162f, 0.3981f, 0.1000f, 1.2200f, 0.8300f, 0.3100f, 0.8913f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CASTLE_SHORTPASSAGE \ - { 1.0000f, 0.8900f, 0.3162f, 0.3162f, 0.1000f, 2.3200f, 0.8300f, 0.3100f, 0.8913f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CASTLE_MEDIUMROOM \ - { 1.0000f, 0.9300f, 0.3162f, 0.2818f, 0.1000f, 2.0400f, 0.8300f, 0.4600f, 0.6310f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1550f, 0.0300f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CASTLE_LARGEROOM \ - { 1.0000f, 0.8200f, 0.3162f, 0.2818f, 0.1259f, 2.5300f, 0.8300f, 0.5000f, 0.4467f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1850f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CASTLE_LONGPASSAGE \ - { 1.0000f, 0.8900f, 0.3162f, 0.3981f, 0.1000f, 3.4200f, 0.8300f, 0.3100f, 0.8913f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CASTLE_HALL \ - { 1.0000f, 0.8100f, 0.3162f, 0.2818f, 0.1778f, 3.1400f, 0.7900f, 0.6200f, 0.1778f, 0.0560f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CASTLE_CUPBOARD \ - { 1.0000f, 0.8900f, 0.3162f, 0.2818f, 0.1000f, 0.6700f, 0.8700f, 0.3100f, 1.4125f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 3.5481f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CASTLE_COURTYARD \ - { 1.0000f, 0.4200f, 0.3162f, 0.4467f, 0.1995f, 2.1300f, 0.6100f, 0.2300f, 0.2239f, 0.1600f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0360f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.3700f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_CASTLE_ALCOVE \ - { 1.0000f, 0.8900f, 0.3162f, 0.5012f, 0.1000f, 1.6400f, 0.8700f, 0.3100f, 1.0000f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } - -/* Factory Presets */ - -#define EFX_REVERB_PRESET_FACTORY_SMALLROOM \ - { 0.3645f, 0.8200f, 0.3162f, 0.7943f, 0.5012f, 1.7200f, 0.6500f, 1.3100f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.1190f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_FACTORY_SHORTPASSAGE \ - { 0.3645f, 0.6400f, 0.2512f, 0.7943f, 0.5012f, 2.5300f, 0.6500f, 1.3100f, 1.0000f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.1350f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_FACTORY_MEDIUMROOM \ - { 0.4287f, 0.8200f, 0.2512f, 0.7943f, 0.5012f, 2.7600f, 0.6500f, 1.3100f, 0.2818f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1740f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_FACTORY_LARGEROOM \ - { 0.4287f, 0.7500f, 0.2512f, 0.7079f, 0.6310f, 4.2400f, 0.5100f, 1.3100f, 0.1778f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.2310f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_FACTORY_LONGPASSAGE \ - { 0.3645f, 0.6400f, 0.2512f, 0.7943f, 0.5012f, 4.0600f, 0.6500f, 1.3100f, 1.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0370f, { 0.0000f, 0.0000f, 0.0000f }, 0.1350f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_FACTORY_HALL \ - { 0.4287f, 0.7500f, 0.3162f, 0.7079f, 0.6310f, 7.4300f, 0.5100f, 1.3100f, 0.0631f, 0.0730f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_FACTORY_CUPBOARD \ - { 0.3071f, 0.6300f, 0.2512f, 0.7943f, 0.5012f, 0.4900f, 0.6500f, 1.3100f, 1.2589f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.1070f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_FACTORY_COURTYARD \ - { 0.3071f, 0.5700f, 0.3162f, 0.3162f, 0.6310f, 2.3200f, 0.2900f, 0.5600f, 0.2239f, 0.1400f, { 0.0000f, 0.0000f, 0.0000f }, 0.3981f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2900f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_FACTORY_ALCOVE \ - { 0.3645f, 0.5900f, 0.2512f, 0.7943f, 0.5012f, 3.1400f, 0.6500f, 1.3100f, 1.4125f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.1140f, 0.1000f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } - -/* Ice Palace Presets */ - -#define EFX_REVERB_PRESET_ICEPALACE_SMALLROOM \ - { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 0.2818f, 1.5100f, 1.5300f, 0.2700f, 0.8913f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1640f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_ICEPALACE_SHORTPASSAGE \ - { 1.0000f, 0.7500f, 0.3162f, 0.5623f, 0.2818f, 1.7900f, 1.4600f, 0.2800f, 0.5012f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.1770f, 0.0900f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_ICEPALACE_MEDIUMROOM \ - { 1.0000f, 0.8700f, 0.3162f, 0.5623f, 0.4467f, 2.2200f, 1.5300f, 0.3200f, 0.3981f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.1860f, 0.1200f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_ICEPALACE_LARGEROOM \ - { 1.0000f, 0.8100f, 0.3162f, 0.5623f, 0.4467f, 3.1400f, 1.5300f, 0.3200f, 0.2512f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.2140f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_ICEPALACE_LONGPASSAGE \ - { 1.0000f, 0.7700f, 0.3162f, 0.5623f, 0.3981f, 3.0100f, 1.4600f, 0.2800f, 0.7943f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0250f, { 0.0000f, 0.0000f, 0.0000f }, 0.1860f, 0.0400f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_ICEPALACE_HALL \ - { 1.0000f, 0.7600f, 0.3162f, 0.4467f, 0.5623f, 5.4900f, 1.5300f, 0.3800f, 0.1122f, 0.0540f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0520f, { 0.0000f, 0.0000f, 0.0000f }, 0.2260f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_ICEPALACE_CUPBOARD \ - { 1.0000f, 0.8300f, 0.3162f, 0.5012f, 0.2239f, 0.7600f, 1.5300f, 0.2600f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1430f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_ICEPALACE_COURTYARD \ - { 1.0000f, 0.5900f, 0.3162f, 0.2818f, 0.3162f, 2.0400f, 1.2000f, 0.3800f, 0.3162f, 0.1730f, { 0.0000f, 0.0000f, 0.0000f }, 0.3162f, 0.0430f, { 0.0000f, 0.0000f, 0.0000f }, 0.2350f, 0.4800f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_ICEPALACE_ALCOVE \ - { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 0.2818f, 2.7600f, 1.4600f, 0.2800f, 1.1220f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1610f, 0.0900f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } - -/* Space Station Presets */ - -#define EFX_REVERB_PRESET_SPACESTATION_SMALLROOM \ - { 0.2109f, 0.7000f, 0.3162f, 0.7079f, 0.8913f, 1.7200f, 0.8200f, 0.5500f, 0.7943f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0130f, { 0.0000f, 0.0000f, 0.0000f }, 0.1880f, 0.2600f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_SPACESTATION_SHORTPASSAGE \ - { 0.2109f, 0.8700f, 0.3162f, 0.6310f, 0.8913f, 3.5700f, 0.5000f, 0.5500f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1720f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_SPACESTATION_MEDIUMROOM \ - { 0.2109f, 0.7500f, 0.3162f, 0.6310f, 0.8913f, 3.0100f, 0.5000f, 0.5500f, 0.3981f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0350f, { 0.0000f, 0.0000f, 0.0000f }, 0.2090f, 0.3100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_SPACESTATION_LARGEROOM \ - { 0.3645f, 0.8100f, 0.3162f, 0.6310f, 0.8913f, 3.8900f, 0.3800f, 0.6100f, 0.3162f, 0.0560f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0350f, { 0.0000f, 0.0000f, 0.0000f }, 0.2330f, 0.2800f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_SPACESTATION_LONGPASSAGE \ - { 0.4287f, 0.8200f, 0.3162f, 0.6310f, 0.8913f, 4.6200f, 0.6200f, 0.5500f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0310f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_SPACESTATION_HALL \ - { 0.4287f, 0.8700f, 0.3162f, 0.6310f, 0.8913f, 7.1100f, 0.3800f, 0.6100f, 0.1778f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0470f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2500f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_SPACESTATION_CUPBOARD \ - { 0.1715f, 0.5600f, 0.3162f, 0.7079f, 0.8913f, 0.7900f, 0.8100f, 0.5500f, 1.4125f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0180f, { 0.0000f, 0.0000f, 0.0000f }, 0.1810f, 0.3100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_SPACESTATION_ALCOVE \ - { 0.2109f, 0.7800f, 0.3162f, 0.7079f, 0.8913f, 1.1600f, 0.8100f, 0.5500f, 1.4125f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0180f, { 0.0000f, 0.0000f, 0.0000f }, 0.1920f, 0.2100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } - -/* Wooden Galleon Presets */ - -#define EFX_REVERB_PRESET_WOODEN_SMALLROOM \ - { 1.0000f, 1.0000f, 0.3162f, 0.1122f, 0.3162f, 0.7900f, 0.3200f, 0.8700f, 1.0000f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_WOODEN_SHORTPASSAGE \ - { 1.0000f, 1.0000f, 0.3162f, 0.1259f, 0.3162f, 1.7500f, 0.5000f, 0.8700f, 0.8913f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_WOODEN_MEDIUMROOM \ - { 1.0000f, 1.0000f, 0.3162f, 0.1000f, 0.2818f, 1.4700f, 0.4200f, 0.8200f, 0.8913f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_WOODEN_LARGEROOM \ - { 1.0000f, 1.0000f, 0.3162f, 0.0891f, 0.2818f, 2.6500f, 0.3300f, 0.8200f, 0.8913f, 0.0660f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_WOODEN_LONGPASSAGE \ - { 1.0000f, 1.0000f, 0.3162f, 0.1000f, 0.3162f, 1.9900f, 0.4000f, 0.7900f, 1.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.4467f, 0.0360f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_WOODEN_HALL \ - { 1.0000f, 1.0000f, 0.3162f, 0.0794f, 0.2818f, 3.4500f, 0.3000f, 0.8200f, 0.8913f, 0.0880f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0630f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_WOODEN_CUPBOARD \ - { 1.0000f, 1.0000f, 0.3162f, 0.1413f, 0.3162f, 0.5600f, 0.4600f, 0.9100f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_WOODEN_COURTYARD \ - { 1.0000f, 0.6500f, 0.3162f, 0.0794f, 0.3162f, 1.7900f, 0.3500f, 0.7900f, 0.5623f, 0.1230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1000f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_WOODEN_ALCOVE \ - { 1.0000f, 1.0000f, 0.3162f, 0.1259f, 0.3162f, 1.2200f, 0.6200f, 0.9100f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } - -/* Sports Presets */ - -#define EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM \ - { 1.0000f, 1.0000f, 0.3162f, 0.4467f, 0.7943f, 6.2600f, 0.5100f, 1.1000f, 0.0631f, 0.1830f, { 0.0000f, 0.0000f, 0.0000f }, 0.3981f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_SPORT_SQUASHCOURT \ - { 1.0000f, 0.7500f, 0.3162f, 0.3162f, 0.7943f, 2.2200f, 0.9100f, 1.1600f, 0.4467f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1260f, 0.1900f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_SPORT_SMALLSWIMMINGPOOL \ - { 1.0000f, 0.7000f, 0.3162f, 0.7943f, 0.8913f, 2.7600f, 1.2500f, 1.1400f, 0.6310f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1790f, 0.1500f, 0.8950f, 0.1900f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_SPORT_LARGESWIMMINGPOOL \ - { 1.0000f, 0.8200f, 0.3162f, 0.7943f, 1.0000f, 5.4900f, 1.3100f, 1.1400f, 0.4467f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 0.5012f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2220f, 0.5500f, 1.1590f, 0.2100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_SPORT_GYMNASIUM \ - { 1.0000f, 0.8100f, 0.3162f, 0.4467f, 0.8913f, 3.1400f, 1.0600f, 1.3500f, 0.3981f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.5623f, 0.0450f, { 0.0000f, 0.0000f, 0.0000f }, 0.1460f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_SPORT_FULLSTADIUM \ - { 1.0000f, 1.0000f, 0.3162f, 0.0708f, 0.7943f, 5.2500f, 0.1700f, 0.8000f, 0.1000f, 0.1880f, { 0.0000f, 0.0000f, 0.0000f }, 0.2818f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_SPORT_STADIUMTANNOY \ - { 1.0000f, 0.7800f, 0.3162f, 0.5623f, 0.5012f, 2.5300f, 0.8800f, 0.6800f, 0.2818f, 0.2300f, { 0.0000f, 0.0000f, 0.0000f }, 0.5012f, 0.0630f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -/* Prefab Presets */ - -#define EFX_REVERB_PRESET_PREFAB_WORKSHOP \ - { 0.4287f, 1.0000f, 0.3162f, 0.1413f, 0.3981f, 0.7600f, 1.0000f, 1.0000f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_PREFAB_SCHOOLROOM \ - { 0.4022f, 0.6900f, 0.3162f, 0.6310f, 0.5012f, 0.9800f, 0.4500f, 0.1800f, 1.4125f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.0950f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_PREFAB_PRACTISEROOM \ - { 0.4022f, 0.8700f, 0.3162f, 0.3981f, 0.5012f, 1.1200f, 0.5600f, 0.1800f, 1.2589f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.0950f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_PREFAB_OUTHOUSE \ - { 1.0000f, 0.8200f, 0.3162f, 0.1122f, 0.1585f, 1.3800f, 0.3800f, 0.3500f, 0.8913f, 0.0240f, { 0.0000f, 0.0000f, -0.0000f }, 0.6310f, 0.0440f, { 0.0000f, 0.0000f, 0.0000f }, 0.1210f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_PREFAB_CARAVAN \ - { 1.0000f, 1.0000f, 0.3162f, 0.0891f, 0.1259f, 0.4300f, 1.5000f, 1.0000f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -/* Dome and Pipe Presets */ - -#define EFX_REVERB_PRESET_DOME_TOMB \ - { 1.0000f, 0.7900f, 0.3162f, 0.3548f, 0.2239f, 4.1800f, 0.2100f, 0.1000f, 0.3868f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 1.6788f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.1770f, 0.1900f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_PIPE_SMALL \ - { 1.0000f, 1.0000f, 0.3162f, 0.3548f, 0.2239f, 5.0400f, 0.1000f, 0.1000f, 0.5012f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 2.5119f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_DOME_SAINTPAULS \ - { 1.0000f, 0.8700f, 0.3162f, 0.3548f, 0.2239f, 10.4800f, 0.1900f, 0.1000f, 0.1778f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0420f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1200f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_PIPE_LONGTHIN \ - { 0.2560f, 0.9100f, 0.3162f, 0.4467f, 0.2818f, 9.2100f, 0.1800f, 0.1000f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_PIPE_LARGE \ - { 1.0000f, 1.0000f, 0.3162f, 0.3548f, 0.2239f, 8.4500f, 0.1000f, 0.1000f, 0.3981f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_PIPE_RESONANT \ - { 0.1373f, 0.9100f, 0.3162f, 0.4467f, 0.2818f, 6.8100f, 0.1800f, 0.1000f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 } - -/* Outdoors Presets */ - -#define EFX_REVERB_PRESET_OUTDOORS_BACKYARD \ - { 1.0000f, 0.4500f, 0.3162f, 0.2512f, 0.5012f, 1.1200f, 0.3400f, 0.4600f, 0.4467f, 0.0690f, { 0.0000f, 0.0000f, -0.0000f }, 0.7079f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.2180f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_OUTDOORS_ROLLINGPLAINS \ - { 1.0000f, 0.0000f, 0.3162f, 0.0112f, 0.6310f, 2.1300f, 0.2100f, 0.4600f, 0.1778f, 0.3000f, { 0.0000f, 0.0000f, -0.0000f }, 0.4467f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_OUTDOORS_DEEPCANYON \ - { 1.0000f, 0.7400f, 0.3162f, 0.1778f, 0.6310f, 3.8900f, 0.2100f, 0.4600f, 0.3162f, 0.2230f, { 0.0000f, 0.0000f, -0.0000f }, 0.3548f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_OUTDOORS_CREEK \ - { 1.0000f, 0.3500f, 0.3162f, 0.1778f, 0.5012f, 2.1300f, 0.2100f, 0.4600f, 0.3981f, 0.1150f, { 0.0000f, 0.0000f, -0.0000f }, 0.1995f, 0.0310f, { 0.0000f, 0.0000f, 0.0000f }, 0.2180f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_OUTDOORS_VALLEY \ - { 1.0000f, 0.2800f, 0.3162f, 0.0282f, 0.1585f, 2.8800f, 0.2600f, 0.3500f, 0.1413f, 0.2630f, { 0.0000f, 0.0000f, -0.0000f }, 0.3981f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } - -/* Mood Presets */ - -#define EFX_REVERB_PRESET_MOOD_HEAVEN \ - { 1.0000f, 0.9400f, 0.3162f, 0.7943f, 0.4467f, 5.0400f, 1.1200f, 0.5600f, 0.2427f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0800f, 2.7420f, 0.0500f, 0.9977f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_MOOD_HELL \ - { 1.0000f, 0.5700f, 0.3162f, 0.3548f, 0.4467f, 3.5700f, 0.4900f, 2.0000f, 0.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1100f, 0.0400f, 2.1090f, 0.5200f, 0.9943f, 5000.0000f, 139.5000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_MOOD_MEMORY \ - { 1.0000f, 0.8500f, 0.3162f, 0.6310f, 0.3548f, 4.0600f, 0.8200f, 0.5600f, 0.0398f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.4740f, 0.4500f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -/* Driving Presets */ - -#define EFX_REVERB_PRESET_DRIVING_COMMENTATOR \ - { 1.0000f, 0.0000f, 3.1623f, 0.5623f, 0.5012f, 2.4200f, 0.8800f, 0.6800f, 0.1995f, 0.0930f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_DRIVING_PITGARAGE \ - { 0.4287f, 0.5900f, 0.3162f, 0.7079f, 0.5623f, 1.7200f, 0.9300f, 0.8700f, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_DRIVING_INCAR_RACER \ - { 0.0832f, 0.8000f, 0.3162f, 1.0000f, 0.7943f, 0.1700f, 2.0000f, 0.4100f, 1.7783f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS \ - { 0.0832f, 0.8000f, 0.3162f, 0.6310f, 1.0000f, 0.1700f, 0.7500f, 0.4100f, 1.0000f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_DRIVING_INCAR_LUXURY \ - { 0.2560f, 1.0000f, 0.3162f, 0.1000f, 0.5012f, 0.1300f, 0.4100f, 0.4600f, 0.7943f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_DRIVING_FULLGRANDSTAND \ - { 1.0000f, 1.0000f, 0.3162f, 0.2818f, 0.6310f, 3.0100f, 1.3700f, 1.2800f, 0.3548f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 0.1778f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10420.2002f, 250.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_DRIVING_EMPTYGRANDSTAND \ - { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 0.7943f, 4.6200f, 1.7500f, 1.4000f, 0.2082f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10420.2002f, 250.0000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_DRIVING_TUNNEL \ - { 1.0000f, 0.8100f, 0.3162f, 0.3981f, 0.8913f, 3.4200f, 0.9400f, 1.3100f, 0.7079f, 0.0510f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0470f, { 0.0000f, 0.0000f, 0.0000f }, 0.2140f, 0.0500f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 155.3000f, 0.0000f, 0x1 } - -/* City Presets */ - -#define EFX_REVERB_PRESET_CITY_STREETS \ - { 1.0000f, 0.7800f, 0.3162f, 0.7079f, 0.8913f, 1.7900f, 1.1200f, 0.9100f, 0.2818f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 0.1995f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CITY_SUBWAY \ - { 1.0000f, 0.7400f, 0.3162f, 0.7079f, 0.8913f, 3.0100f, 1.2300f, 0.9100f, 0.7079f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.2100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CITY_MUSEUM \ - { 1.0000f, 0.8200f, 0.3162f, 0.1778f, 0.1778f, 3.2800f, 1.4000f, 0.5700f, 0.2512f, 0.0390f, { 0.0000f, 0.0000f, -0.0000f }, 0.8913f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 0.1300f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_CITY_LIBRARY \ - { 1.0000f, 0.8200f, 0.3162f, 0.2818f, 0.0891f, 2.7600f, 0.8900f, 0.4100f, 0.3548f, 0.0290f, { 0.0000f, 0.0000f, -0.0000f }, 0.8913f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.1300f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } - -#define EFX_REVERB_PRESET_CITY_UNDERPASS \ - { 1.0000f, 0.8200f, 0.3162f, 0.4467f, 0.8913f, 3.5700f, 1.1200f, 0.9100f, 0.3981f, 0.0590f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0370f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1400f, 0.2500f, 0.0000f, 0.9920f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CITY_ABANDONED \ - { 1.0000f, 0.6900f, 0.3162f, 0.7943f, 0.8913f, 3.2800f, 1.1700f, 0.9100f, 0.4467f, 0.0440f, { 0.0000f, 0.0000f, 0.0000f }, 0.2818f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9966f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -/* Misc. Presets */ - -#define EFX_REVERB_PRESET_DUSTYROOM \ - { 0.3645f, 0.5600f, 0.3162f, 0.7943f, 0.7079f, 1.7900f, 0.3800f, 0.2100f, 0.5012f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0060f, { 0.0000f, 0.0000f, 0.0000f }, 0.2020f, 0.0500f, 0.2500f, 0.0000f, 0.9886f, 13046.0000f, 163.3000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_CHAPEL \ - { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 1.0000f, 4.6200f, 0.6400f, 1.2300f, 0.4467f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.1100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } - -#define EFX_REVERB_PRESET_SMALLWATERROOM \ - { 1.0000f, 0.7000f, 0.3162f, 0.4477f, 1.0000f, 1.5100f, 1.2500f, 1.1400f, 0.8913f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1790f, 0.1500f, 0.8950f, 0.1900f, 0.9920f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } - -#endif /* EFX_PRESETS_H */ diff --git a/thirdparty/include/AL/efx.h b/thirdparty/include/AL/efx.h deleted file mode 100644 index 57766983f..000000000 --- a/thirdparty/include/AL/efx.h +++ /dev/null @@ -1,761 +0,0 @@ -#ifndef AL_EFX_H -#define AL_EFX_H - - -#include "alc.h" -#include "al.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define ALC_EXT_EFX_NAME "ALC_EXT_EFX" - -#define ALC_EFX_MAJOR_VERSION 0x20001 -#define ALC_EFX_MINOR_VERSION 0x20002 -#define ALC_MAX_AUXILIARY_SENDS 0x20003 - - -/* Listener properties. */ -#define AL_METERS_PER_UNIT 0x20004 - -/* Source properties. */ -#define AL_DIRECT_FILTER 0x20005 -#define AL_AUXILIARY_SEND_FILTER 0x20006 -#define AL_AIR_ABSORPTION_FACTOR 0x20007 -#define AL_ROOM_ROLLOFF_FACTOR 0x20008 -#define AL_CONE_OUTER_GAINHF 0x20009 -#define AL_DIRECT_FILTER_GAINHF_AUTO 0x2000A -#define AL_AUXILIARY_SEND_FILTER_GAIN_AUTO 0x2000B -#define AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO 0x2000C - - -/* Effect properties. */ - -/* Reverb effect parameters */ -#define AL_REVERB_DENSITY 0x0001 -#define AL_REVERB_DIFFUSION 0x0002 -#define AL_REVERB_GAIN 0x0003 -#define AL_REVERB_GAINHF 0x0004 -#define AL_REVERB_DECAY_TIME 0x0005 -#define AL_REVERB_DECAY_HFRATIO 0x0006 -#define AL_REVERB_REFLECTIONS_GAIN 0x0007 -#define AL_REVERB_REFLECTIONS_DELAY 0x0008 -#define AL_REVERB_LATE_REVERB_GAIN 0x0009 -#define AL_REVERB_LATE_REVERB_DELAY 0x000A -#define AL_REVERB_AIR_ABSORPTION_GAINHF 0x000B -#define AL_REVERB_ROOM_ROLLOFF_FACTOR 0x000C -#define AL_REVERB_DECAY_HFLIMIT 0x000D - -/* EAX Reverb effect parameters */ -#define AL_EAXREVERB_DENSITY 0x0001 -#define AL_EAXREVERB_DIFFUSION 0x0002 -#define AL_EAXREVERB_GAIN 0x0003 -#define AL_EAXREVERB_GAINHF 0x0004 -#define AL_EAXREVERB_GAINLF 0x0005 -#define AL_EAXREVERB_DECAY_TIME 0x0006 -#define AL_EAXREVERB_DECAY_HFRATIO 0x0007 -#define AL_EAXREVERB_DECAY_LFRATIO 0x0008 -#define AL_EAXREVERB_REFLECTIONS_GAIN 0x0009 -#define AL_EAXREVERB_REFLECTIONS_DELAY 0x000A -#define AL_EAXREVERB_REFLECTIONS_PAN 0x000B -#define AL_EAXREVERB_LATE_REVERB_GAIN 0x000C -#define AL_EAXREVERB_LATE_REVERB_DELAY 0x000D -#define AL_EAXREVERB_LATE_REVERB_PAN 0x000E -#define AL_EAXREVERB_ECHO_TIME 0x000F -#define AL_EAXREVERB_ECHO_DEPTH 0x0010 -#define AL_EAXREVERB_MODULATION_TIME 0x0011 -#define AL_EAXREVERB_MODULATION_DEPTH 0x0012 -#define AL_EAXREVERB_AIR_ABSORPTION_GAINHF 0x0013 -#define AL_EAXREVERB_HFREFERENCE 0x0014 -#define AL_EAXREVERB_LFREFERENCE 0x0015 -#define AL_EAXREVERB_ROOM_ROLLOFF_FACTOR 0x0016 -#define AL_EAXREVERB_DECAY_HFLIMIT 0x0017 - -/* Chorus effect parameters */ -#define AL_CHORUS_WAVEFORM 0x0001 -#define AL_CHORUS_PHASE 0x0002 -#define AL_CHORUS_RATE 0x0003 -#define AL_CHORUS_DEPTH 0x0004 -#define AL_CHORUS_FEEDBACK 0x0005 -#define AL_CHORUS_DELAY 0x0006 - -/* Distortion effect parameters */ -#define AL_DISTORTION_EDGE 0x0001 -#define AL_DISTORTION_GAIN 0x0002 -#define AL_DISTORTION_LOWPASS_CUTOFF 0x0003 -#define AL_DISTORTION_EQCENTER 0x0004 -#define AL_DISTORTION_EQBANDWIDTH 0x0005 - -/* Echo effect parameters */ -#define AL_ECHO_DELAY 0x0001 -#define AL_ECHO_LRDELAY 0x0002 -#define AL_ECHO_DAMPING 0x0003 -#define AL_ECHO_FEEDBACK 0x0004 -#define AL_ECHO_SPREAD 0x0005 - -/* Flanger effect parameters */ -#define AL_FLANGER_WAVEFORM 0x0001 -#define AL_FLANGER_PHASE 0x0002 -#define AL_FLANGER_RATE 0x0003 -#define AL_FLANGER_DEPTH 0x0004 -#define AL_FLANGER_FEEDBACK 0x0005 -#define AL_FLANGER_DELAY 0x0006 - -/* Frequency shifter effect parameters */ -#define AL_FREQUENCY_SHIFTER_FREQUENCY 0x0001 -#define AL_FREQUENCY_SHIFTER_LEFT_DIRECTION 0x0002 -#define AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION 0x0003 - -/* Vocal morpher effect parameters */ -#define AL_VOCAL_MORPHER_PHONEMEA 0x0001 -#define AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING 0x0002 -#define AL_VOCAL_MORPHER_PHONEMEB 0x0003 -#define AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING 0x0004 -#define AL_VOCAL_MORPHER_WAVEFORM 0x0005 -#define AL_VOCAL_MORPHER_RATE 0x0006 - -/* Pitchshifter effect parameters */ -#define AL_PITCH_SHIFTER_COARSE_TUNE 0x0001 -#define AL_PITCH_SHIFTER_FINE_TUNE 0x0002 - -/* Ringmodulator effect parameters */ -#define AL_RING_MODULATOR_FREQUENCY 0x0001 -#define AL_RING_MODULATOR_HIGHPASS_CUTOFF 0x0002 -#define AL_RING_MODULATOR_WAVEFORM 0x0003 - -/* Autowah effect parameters */ -#define AL_AUTOWAH_ATTACK_TIME 0x0001 -#define AL_AUTOWAH_RELEASE_TIME 0x0002 -#define AL_AUTOWAH_RESONANCE 0x0003 -#define AL_AUTOWAH_PEAK_GAIN 0x0004 - -/* Compressor effect parameters */ -#define AL_COMPRESSOR_ONOFF 0x0001 - -/* Equalizer effect parameters */ -#define AL_EQUALIZER_LOW_GAIN 0x0001 -#define AL_EQUALIZER_LOW_CUTOFF 0x0002 -#define AL_EQUALIZER_MID1_GAIN 0x0003 -#define AL_EQUALIZER_MID1_CENTER 0x0004 -#define AL_EQUALIZER_MID1_WIDTH 0x0005 -#define AL_EQUALIZER_MID2_GAIN 0x0006 -#define AL_EQUALIZER_MID2_CENTER 0x0007 -#define AL_EQUALIZER_MID2_WIDTH 0x0008 -#define AL_EQUALIZER_HIGH_GAIN 0x0009 -#define AL_EQUALIZER_HIGH_CUTOFF 0x000A - -/* Effect type */ -#define AL_EFFECT_FIRST_PARAMETER 0x0000 -#define AL_EFFECT_LAST_PARAMETER 0x8000 -#define AL_EFFECT_TYPE 0x8001 - -/* Effect types, used with the AL_EFFECT_TYPE property */ -#define AL_EFFECT_NULL 0x0000 -#define AL_EFFECT_REVERB 0x0001 -#define AL_EFFECT_CHORUS 0x0002 -#define AL_EFFECT_DISTORTION 0x0003 -#define AL_EFFECT_ECHO 0x0004 -#define AL_EFFECT_FLANGER 0x0005 -#define AL_EFFECT_FREQUENCY_SHIFTER 0x0006 -#define AL_EFFECT_VOCAL_MORPHER 0x0007 -#define AL_EFFECT_PITCH_SHIFTER 0x0008 -#define AL_EFFECT_RING_MODULATOR 0x0009 -#define AL_EFFECT_AUTOWAH 0x000A -#define AL_EFFECT_COMPRESSOR 0x000B -#define AL_EFFECT_EQUALIZER 0x000C -#define AL_EFFECT_EAXREVERB 0x8000 - -/* Auxiliary Effect Slot properties. */ -#define AL_EFFECTSLOT_EFFECT 0x0001 -#define AL_EFFECTSLOT_GAIN 0x0002 -#define AL_EFFECTSLOT_AUXILIARY_SEND_AUTO 0x0003 - -/* NULL Auxiliary Slot ID to disable a source send. */ -#define AL_EFFECTSLOT_NULL 0x0000 - - -/* Filter properties. */ - -/* Lowpass filter parameters */ -#define AL_LOWPASS_GAIN 0x0001 -#define AL_LOWPASS_GAINHF 0x0002 - -/* Highpass filter parameters */ -#define AL_HIGHPASS_GAIN 0x0001 -#define AL_HIGHPASS_GAINLF 0x0002 - -/* Bandpass filter parameters */ -#define AL_BANDPASS_GAIN 0x0001 -#define AL_BANDPASS_GAINLF 0x0002 -#define AL_BANDPASS_GAINHF 0x0003 - -/* Filter type */ -#define AL_FILTER_FIRST_PARAMETER 0x0000 -#define AL_FILTER_LAST_PARAMETER 0x8000 -#define AL_FILTER_TYPE 0x8001 - -/* Filter types, used with the AL_FILTER_TYPE property */ -#define AL_FILTER_NULL 0x0000 -#define AL_FILTER_LOWPASS 0x0001 -#define AL_FILTER_HIGHPASS 0x0002 -#define AL_FILTER_BANDPASS 0x0003 - - -/* Effect object function types. */ -typedef void (AL_APIENTRY *LPALGENEFFECTS)(ALsizei, ALuint*); -typedef void (AL_APIENTRY *LPALDELETEEFFECTS)(ALsizei, const ALuint*); -typedef ALboolean (AL_APIENTRY *LPALISEFFECT)(ALuint); -typedef void (AL_APIENTRY *LPALEFFECTI)(ALuint, ALenum, ALint); -typedef void (AL_APIENTRY *LPALEFFECTIV)(ALuint, ALenum, const ALint*); -typedef void (AL_APIENTRY *LPALEFFECTF)(ALuint, ALenum, ALfloat); -typedef void (AL_APIENTRY *LPALEFFECTFV)(ALuint, ALenum, const ALfloat*); -typedef void (AL_APIENTRY *LPALGETEFFECTI)(ALuint, ALenum, ALint*); -typedef void (AL_APIENTRY *LPALGETEFFECTIV)(ALuint, ALenum, ALint*); -typedef void (AL_APIENTRY *LPALGETEFFECTF)(ALuint, ALenum, ALfloat*); -typedef void (AL_APIENTRY *LPALGETEFFECTFV)(ALuint, ALenum, ALfloat*); - -/* Filter object function types. */ -typedef void (AL_APIENTRY *LPALGENFILTERS)(ALsizei, ALuint*); -typedef void (AL_APIENTRY *LPALDELETEFILTERS)(ALsizei, const ALuint*); -typedef ALboolean (AL_APIENTRY *LPALISFILTER)(ALuint); -typedef void (AL_APIENTRY *LPALFILTERI)(ALuint, ALenum, ALint); -typedef void (AL_APIENTRY *LPALFILTERIV)(ALuint, ALenum, const ALint*); -typedef void (AL_APIENTRY *LPALFILTERF)(ALuint, ALenum, ALfloat); -typedef void (AL_APIENTRY *LPALFILTERFV)(ALuint, ALenum, const ALfloat*); -typedef void (AL_APIENTRY *LPALGETFILTERI)(ALuint, ALenum, ALint*); -typedef void (AL_APIENTRY *LPALGETFILTERIV)(ALuint, ALenum, ALint*); -typedef void (AL_APIENTRY *LPALGETFILTERF)(ALuint, ALenum, ALfloat*); -typedef void (AL_APIENTRY *LPALGETFILTERFV)(ALuint, ALenum, ALfloat*); - -/* Auxiliary Effect Slot object function types. */ -typedef void (AL_APIENTRY *LPALGENAUXILIARYEFFECTSLOTS)(ALsizei, ALuint*); -typedef void (AL_APIENTRY *LPALDELETEAUXILIARYEFFECTSLOTS)(ALsizei, const ALuint*); -typedef ALboolean (AL_APIENTRY *LPALISAUXILIARYEFFECTSLOT)(ALuint); -typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint); -typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, const ALint*); -typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat); -typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, const ALfloat*); -typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint*); -typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, ALint*); -typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat*); -typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, ALfloat*); - -#ifdef AL_ALEXT_PROTOTYPES -AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects); -AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects); -AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect); -AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue); -AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *piValues); -AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue); -AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *pflValues); -AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue); -AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues); -AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue); -AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues); - -AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters); -AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters); -AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter); -AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue); -AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *piValues); -AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue); -AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *pflValues); -AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue); -AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues); -AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue); -AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues); - -AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots); -AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots); -AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot); -AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue); -AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *piValues); -AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue); -AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *pflValues); -AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue); -AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues); -AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue); -AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues); -#endif - -/* Filter ranges and defaults. */ - -/* Lowpass filter */ -#define AL_LOWPASS_MIN_GAIN (0.0f) -#define AL_LOWPASS_MAX_GAIN (1.0f) -#define AL_LOWPASS_DEFAULT_GAIN (1.0f) - -#define AL_LOWPASS_MIN_GAINHF (0.0f) -#define AL_LOWPASS_MAX_GAINHF (1.0f) -#define AL_LOWPASS_DEFAULT_GAINHF (1.0f) - -/* Highpass filter */ -#define AL_HIGHPASS_MIN_GAIN (0.0f) -#define AL_HIGHPASS_MAX_GAIN (1.0f) -#define AL_HIGHPASS_DEFAULT_GAIN (1.0f) - -#define AL_HIGHPASS_MIN_GAINLF (0.0f) -#define AL_HIGHPASS_MAX_GAINLF (1.0f) -#define AL_HIGHPASS_DEFAULT_GAINLF (1.0f) - -/* Bandpass filter */ -#define AL_BANDPASS_MIN_GAIN (0.0f) -#define AL_BANDPASS_MAX_GAIN (1.0f) -#define AL_BANDPASS_DEFAULT_GAIN (1.0f) - -#define AL_BANDPASS_MIN_GAINHF (0.0f) -#define AL_BANDPASS_MAX_GAINHF (1.0f) -#define AL_BANDPASS_DEFAULT_GAINHF (1.0f) - -#define AL_BANDPASS_MIN_GAINLF (0.0f) -#define AL_BANDPASS_MAX_GAINLF (1.0f) -#define AL_BANDPASS_DEFAULT_GAINLF (1.0f) - - -/* Effect parameter ranges and defaults. */ - -/* Standard reverb effect */ -#define AL_REVERB_MIN_DENSITY (0.0f) -#define AL_REVERB_MAX_DENSITY (1.0f) -#define AL_REVERB_DEFAULT_DENSITY (1.0f) - -#define AL_REVERB_MIN_DIFFUSION (0.0f) -#define AL_REVERB_MAX_DIFFUSION (1.0f) -#define AL_REVERB_DEFAULT_DIFFUSION (1.0f) - -#define AL_REVERB_MIN_GAIN (0.0f) -#define AL_REVERB_MAX_GAIN (1.0f) -#define AL_REVERB_DEFAULT_GAIN (0.32f) - -#define AL_REVERB_MIN_GAINHF (0.0f) -#define AL_REVERB_MAX_GAINHF (1.0f) -#define AL_REVERB_DEFAULT_GAINHF (0.89f) - -#define AL_REVERB_MIN_DECAY_TIME (0.1f) -#define AL_REVERB_MAX_DECAY_TIME (20.0f) -#define AL_REVERB_DEFAULT_DECAY_TIME (1.49f) - -#define AL_REVERB_MIN_DECAY_HFRATIO (0.1f) -#define AL_REVERB_MAX_DECAY_HFRATIO (2.0f) -#define AL_REVERB_DEFAULT_DECAY_HFRATIO (0.83f) - -#define AL_REVERB_MIN_REFLECTIONS_GAIN (0.0f) -#define AL_REVERB_MAX_REFLECTIONS_GAIN (3.16f) -#define AL_REVERB_DEFAULT_REFLECTIONS_GAIN (0.05f) - -#define AL_REVERB_MIN_REFLECTIONS_DELAY (0.0f) -#define AL_REVERB_MAX_REFLECTIONS_DELAY (0.3f) -#define AL_REVERB_DEFAULT_REFLECTIONS_DELAY (0.007f) - -#define AL_REVERB_MIN_LATE_REVERB_GAIN (0.0f) -#define AL_REVERB_MAX_LATE_REVERB_GAIN (10.0f) -#define AL_REVERB_DEFAULT_LATE_REVERB_GAIN (1.26f) - -#define AL_REVERB_MIN_LATE_REVERB_DELAY (0.0f) -#define AL_REVERB_MAX_LATE_REVERB_DELAY (0.1f) -#define AL_REVERB_DEFAULT_LATE_REVERB_DELAY (0.011f) - -#define AL_REVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f) -#define AL_REVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f) -#define AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f) - -#define AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f) -#define AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f) -#define AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) - -#define AL_REVERB_MIN_DECAY_HFLIMIT AL_FALSE -#define AL_REVERB_MAX_DECAY_HFLIMIT AL_TRUE -#define AL_REVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE - -/* EAX reverb effect */ -#define AL_EAXREVERB_MIN_DENSITY (0.0f) -#define AL_EAXREVERB_MAX_DENSITY (1.0f) -#define AL_EAXREVERB_DEFAULT_DENSITY (1.0f) - -#define AL_EAXREVERB_MIN_DIFFUSION (0.0f) -#define AL_EAXREVERB_MAX_DIFFUSION (1.0f) -#define AL_EAXREVERB_DEFAULT_DIFFUSION (1.0f) - -#define AL_EAXREVERB_MIN_GAIN (0.0f) -#define AL_EAXREVERB_MAX_GAIN (1.0f) -#define AL_EAXREVERB_DEFAULT_GAIN (0.32f) - -#define AL_EAXREVERB_MIN_GAINHF (0.0f) -#define AL_EAXREVERB_MAX_GAINHF (1.0f) -#define AL_EAXREVERB_DEFAULT_GAINHF (0.89f) - -#define AL_EAXREVERB_MIN_GAINLF (0.0f) -#define AL_EAXREVERB_MAX_GAINLF (1.0f) -#define AL_EAXREVERB_DEFAULT_GAINLF (1.0f) - -#define AL_EAXREVERB_MIN_DECAY_TIME (0.1f) -#define AL_EAXREVERB_MAX_DECAY_TIME (20.0f) -#define AL_EAXREVERB_DEFAULT_DECAY_TIME (1.49f) - -#define AL_EAXREVERB_MIN_DECAY_HFRATIO (0.1f) -#define AL_EAXREVERB_MAX_DECAY_HFRATIO (2.0f) -#define AL_EAXREVERB_DEFAULT_DECAY_HFRATIO (0.83f) - -#define AL_EAXREVERB_MIN_DECAY_LFRATIO (0.1f) -#define AL_EAXREVERB_MAX_DECAY_LFRATIO (2.0f) -#define AL_EAXREVERB_DEFAULT_DECAY_LFRATIO (1.0f) - -#define AL_EAXREVERB_MIN_REFLECTIONS_GAIN (0.0f) -#define AL_EAXREVERB_MAX_REFLECTIONS_GAIN (3.16f) -#define AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN (0.05f) - -#define AL_EAXREVERB_MIN_REFLECTIONS_DELAY (0.0f) -#define AL_EAXREVERB_MAX_REFLECTIONS_DELAY (0.3f) -#define AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY (0.007f) - -#define AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ (0.0f) - -#define AL_EAXREVERB_MIN_LATE_REVERB_GAIN (0.0f) -#define AL_EAXREVERB_MAX_LATE_REVERB_GAIN (10.0f) -#define AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN (1.26f) - -#define AL_EAXREVERB_MIN_LATE_REVERB_DELAY (0.0f) -#define AL_EAXREVERB_MAX_LATE_REVERB_DELAY (0.1f) -#define AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY (0.011f) - -#define AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ (0.0f) - -#define AL_EAXREVERB_MIN_ECHO_TIME (0.075f) -#define AL_EAXREVERB_MAX_ECHO_TIME (0.25f) -#define AL_EAXREVERB_DEFAULT_ECHO_TIME (0.25f) - -#define AL_EAXREVERB_MIN_ECHO_DEPTH (0.0f) -#define AL_EAXREVERB_MAX_ECHO_DEPTH (1.0f) -#define AL_EAXREVERB_DEFAULT_ECHO_DEPTH (0.0f) - -#define AL_EAXREVERB_MIN_MODULATION_TIME (0.04f) -#define AL_EAXREVERB_MAX_MODULATION_TIME (4.0f) -#define AL_EAXREVERB_DEFAULT_MODULATION_TIME (0.25f) - -#define AL_EAXREVERB_MIN_MODULATION_DEPTH (0.0f) -#define AL_EAXREVERB_MAX_MODULATION_DEPTH (1.0f) -#define AL_EAXREVERB_DEFAULT_MODULATION_DEPTH (0.0f) - -#define AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f) -#define AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f) -#define AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f) - -#define AL_EAXREVERB_MIN_HFREFERENCE (1000.0f) -#define AL_EAXREVERB_MAX_HFREFERENCE (20000.0f) -#define AL_EAXREVERB_DEFAULT_HFREFERENCE (5000.0f) - -#define AL_EAXREVERB_MIN_LFREFERENCE (20.0f) -#define AL_EAXREVERB_MAX_LFREFERENCE (1000.0f) -#define AL_EAXREVERB_DEFAULT_LFREFERENCE (250.0f) - -#define AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f) -#define AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f) -#define AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) - -#define AL_EAXREVERB_MIN_DECAY_HFLIMIT AL_FALSE -#define AL_EAXREVERB_MAX_DECAY_HFLIMIT AL_TRUE -#define AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE - -/* Chorus effect */ -#define AL_CHORUS_WAVEFORM_SINUSOID (0) -#define AL_CHORUS_WAVEFORM_TRIANGLE (1) - -#define AL_CHORUS_MIN_WAVEFORM (0) -#define AL_CHORUS_MAX_WAVEFORM (1) -#define AL_CHORUS_DEFAULT_WAVEFORM (1) - -#define AL_CHORUS_MIN_PHASE (-180) -#define AL_CHORUS_MAX_PHASE (180) -#define AL_CHORUS_DEFAULT_PHASE (90) - -#define AL_CHORUS_MIN_RATE (0.0f) -#define AL_CHORUS_MAX_RATE (10.0f) -#define AL_CHORUS_DEFAULT_RATE (1.1f) - -#define AL_CHORUS_MIN_DEPTH (0.0f) -#define AL_CHORUS_MAX_DEPTH (1.0f) -#define AL_CHORUS_DEFAULT_DEPTH (0.1f) - -#define AL_CHORUS_MIN_FEEDBACK (-1.0f) -#define AL_CHORUS_MAX_FEEDBACK (1.0f) -#define AL_CHORUS_DEFAULT_FEEDBACK (0.25f) - -#define AL_CHORUS_MIN_DELAY (0.0f) -#define AL_CHORUS_MAX_DELAY (0.016f) -#define AL_CHORUS_DEFAULT_DELAY (0.016f) - -/* Distortion effect */ -#define AL_DISTORTION_MIN_EDGE (0.0f) -#define AL_DISTORTION_MAX_EDGE (1.0f) -#define AL_DISTORTION_DEFAULT_EDGE (0.2f) - -#define AL_DISTORTION_MIN_GAIN (0.01f) -#define AL_DISTORTION_MAX_GAIN (1.0f) -#define AL_DISTORTION_DEFAULT_GAIN (0.05f) - -#define AL_DISTORTION_MIN_LOWPASS_CUTOFF (80.0f) -#define AL_DISTORTION_MAX_LOWPASS_CUTOFF (24000.0f) -#define AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF (8000.0f) - -#define AL_DISTORTION_MIN_EQCENTER (80.0f) -#define AL_DISTORTION_MAX_EQCENTER (24000.0f) -#define AL_DISTORTION_DEFAULT_EQCENTER (3600.0f) - -#define AL_DISTORTION_MIN_EQBANDWIDTH (80.0f) -#define AL_DISTORTION_MAX_EQBANDWIDTH (24000.0f) -#define AL_DISTORTION_DEFAULT_EQBANDWIDTH (3600.0f) - -/* Echo effect */ -#define AL_ECHO_MIN_DELAY (0.0f) -#define AL_ECHO_MAX_DELAY (0.207f) -#define AL_ECHO_DEFAULT_DELAY (0.1f) - -#define AL_ECHO_MIN_LRDELAY (0.0f) -#define AL_ECHO_MAX_LRDELAY (0.404f) -#define AL_ECHO_DEFAULT_LRDELAY (0.1f) - -#define AL_ECHO_MIN_DAMPING (0.0f) -#define AL_ECHO_MAX_DAMPING (0.99f) -#define AL_ECHO_DEFAULT_DAMPING (0.5f) - -#define AL_ECHO_MIN_FEEDBACK (0.0f) -#define AL_ECHO_MAX_FEEDBACK (1.0f) -#define AL_ECHO_DEFAULT_FEEDBACK (0.5f) - -#define AL_ECHO_MIN_SPREAD (-1.0f) -#define AL_ECHO_MAX_SPREAD (1.0f) -#define AL_ECHO_DEFAULT_SPREAD (-1.0f) - -/* Flanger effect */ -#define AL_FLANGER_WAVEFORM_SINUSOID (0) -#define AL_FLANGER_WAVEFORM_TRIANGLE (1) - -#define AL_FLANGER_MIN_WAVEFORM (0) -#define AL_FLANGER_MAX_WAVEFORM (1) -#define AL_FLANGER_DEFAULT_WAVEFORM (1) - -#define AL_FLANGER_MIN_PHASE (-180) -#define AL_FLANGER_MAX_PHASE (180) -#define AL_FLANGER_DEFAULT_PHASE (0) - -#define AL_FLANGER_MIN_RATE (0.0f) -#define AL_FLANGER_MAX_RATE (10.0f) -#define AL_FLANGER_DEFAULT_RATE (0.27f) - -#define AL_FLANGER_MIN_DEPTH (0.0f) -#define AL_FLANGER_MAX_DEPTH (1.0f) -#define AL_FLANGER_DEFAULT_DEPTH (1.0f) - -#define AL_FLANGER_MIN_FEEDBACK (-1.0f) -#define AL_FLANGER_MAX_FEEDBACK (1.0f) -#define AL_FLANGER_DEFAULT_FEEDBACK (-0.5f) - -#define AL_FLANGER_MIN_DELAY (0.0f) -#define AL_FLANGER_MAX_DELAY (0.004f) -#define AL_FLANGER_DEFAULT_DELAY (0.002f) - -/* Frequency shifter effect */ -#define AL_FREQUENCY_SHIFTER_MIN_FREQUENCY (0.0f) -#define AL_FREQUENCY_SHIFTER_MAX_FREQUENCY (24000.0f) -#define AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY (0.0f) - -#define AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION (0) -#define AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION (2) -#define AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION (0) - -#define AL_FREQUENCY_SHIFTER_DIRECTION_DOWN (0) -#define AL_FREQUENCY_SHIFTER_DIRECTION_UP (1) -#define AL_FREQUENCY_SHIFTER_DIRECTION_OFF (2) - -#define AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION (0) -#define AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION (2) -#define AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION (0) - -/* Vocal morpher effect */ -#define AL_VOCAL_MORPHER_MIN_PHONEMEA (0) -#define AL_VOCAL_MORPHER_MAX_PHONEMEA (29) -#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA (0) - -#define AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING (-24) -#define AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING (24) -#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING (0) - -#define AL_VOCAL_MORPHER_MIN_PHONEMEB (0) -#define AL_VOCAL_MORPHER_MAX_PHONEMEB (29) -#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB (10) - -#define AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING (-24) -#define AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING (24) -#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING (0) - -#define AL_VOCAL_MORPHER_PHONEME_A (0) -#define AL_VOCAL_MORPHER_PHONEME_E (1) -#define AL_VOCAL_MORPHER_PHONEME_I (2) -#define AL_VOCAL_MORPHER_PHONEME_O (3) -#define AL_VOCAL_MORPHER_PHONEME_U (4) -#define AL_VOCAL_MORPHER_PHONEME_AA (5) -#define AL_VOCAL_MORPHER_PHONEME_AE (6) -#define AL_VOCAL_MORPHER_PHONEME_AH (7) -#define AL_VOCAL_MORPHER_PHONEME_AO (8) -#define AL_VOCAL_MORPHER_PHONEME_EH (9) -#define AL_VOCAL_MORPHER_PHONEME_ER (10) -#define AL_VOCAL_MORPHER_PHONEME_IH (11) -#define AL_VOCAL_MORPHER_PHONEME_IY (12) -#define AL_VOCAL_MORPHER_PHONEME_UH (13) -#define AL_VOCAL_MORPHER_PHONEME_UW (14) -#define AL_VOCAL_MORPHER_PHONEME_B (15) -#define AL_VOCAL_MORPHER_PHONEME_D (16) -#define AL_VOCAL_MORPHER_PHONEME_F (17) -#define AL_VOCAL_MORPHER_PHONEME_G (18) -#define AL_VOCAL_MORPHER_PHONEME_J (19) -#define AL_VOCAL_MORPHER_PHONEME_K (20) -#define AL_VOCAL_MORPHER_PHONEME_L (21) -#define AL_VOCAL_MORPHER_PHONEME_M (22) -#define AL_VOCAL_MORPHER_PHONEME_N (23) -#define AL_VOCAL_MORPHER_PHONEME_P (24) -#define AL_VOCAL_MORPHER_PHONEME_R (25) -#define AL_VOCAL_MORPHER_PHONEME_S (26) -#define AL_VOCAL_MORPHER_PHONEME_T (27) -#define AL_VOCAL_MORPHER_PHONEME_V (28) -#define AL_VOCAL_MORPHER_PHONEME_Z (29) - -#define AL_VOCAL_MORPHER_WAVEFORM_SINUSOID (0) -#define AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE (1) -#define AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH (2) - -#define AL_VOCAL_MORPHER_MIN_WAVEFORM (0) -#define AL_VOCAL_MORPHER_MAX_WAVEFORM (2) -#define AL_VOCAL_MORPHER_DEFAULT_WAVEFORM (0) - -#define AL_VOCAL_MORPHER_MIN_RATE (0.0f) -#define AL_VOCAL_MORPHER_MAX_RATE (10.0f) -#define AL_VOCAL_MORPHER_DEFAULT_RATE (1.41f) - -/* Pitch shifter effect */ -#define AL_PITCH_SHIFTER_MIN_COARSE_TUNE (-12) -#define AL_PITCH_SHIFTER_MAX_COARSE_TUNE (12) -#define AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE (12) - -#define AL_PITCH_SHIFTER_MIN_FINE_TUNE (-50) -#define AL_PITCH_SHIFTER_MAX_FINE_TUNE (50) -#define AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE (0) - -/* Ring modulator effect */ -#define AL_RING_MODULATOR_MIN_FREQUENCY (0.0f) -#define AL_RING_MODULATOR_MAX_FREQUENCY (8000.0f) -#define AL_RING_MODULATOR_DEFAULT_FREQUENCY (440.0f) - -#define AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF (0.0f) -#define AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF (24000.0f) -#define AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF (800.0f) - -#define AL_RING_MODULATOR_SINUSOID (0) -#define AL_RING_MODULATOR_SAWTOOTH (1) -#define AL_RING_MODULATOR_SQUARE (2) - -#define AL_RING_MODULATOR_MIN_WAVEFORM (0) -#define AL_RING_MODULATOR_MAX_WAVEFORM (2) -#define AL_RING_MODULATOR_DEFAULT_WAVEFORM (0) - -/* Autowah effect */ -#define AL_AUTOWAH_MIN_ATTACK_TIME (0.0001f) -#define AL_AUTOWAH_MAX_ATTACK_TIME (1.0f) -#define AL_AUTOWAH_DEFAULT_ATTACK_TIME (0.06f) - -#define AL_AUTOWAH_MIN_RELEASE_TIME (0.0001f) -#define AL_AUTOWAH_MAX_RELEASE_TIME (1.0f) -#define AL_AUTOWAH_DEFAULT_RELEASE_TIME (0.06f) - -#define AL_AUTOWAH_MIN_RESONANCE (2.0f) -#define AL_AUTOWAH_MAX_RESONANCE (1000.0f) -#define AL_AUTOWAH_DEFAULT_RESONANCE (1000.0f) - -#define AL_AUTOWAH_MIN_PEAK_GAIN (0.00003f) -#define AL_AUTOWAH_MAX_PEAK_GAIN (31621.0f) -#define AL_AUTOWAH_DEFAULT_PEAK_GAIN (11.22f) - -/* Compressor effect */ -#define AL_COMPRESSOR_MIN_ONOFF (0) -#define AL_COMPRESSOR_MAX_ONOFF (1) -#define AL_COMPRESSOR_DEFAULT_ONOFF (1) - -/* Equalizer effect */ -#define AL_EQUALIZER_MIN_LOW_GAIN (0.126f) -#define AL_EQUALIZER_MAX_LOW_GAIN (7.943f) -#define AL_EQUALIZER_DEFAULT_LOW_GAIN (1.0f) - -#define AL_EQUALIZER_MIN_LOW_CUTOFF (50.0f) -#define AL_EQUALIZER_MAX_LOW_CUTOFF (800.0f) -#define AL_EQUALIZER_DEFAULT_LOW_CUTOFF (200.0f) - -#define AL_EQUALIZER_MIN_MID1_GAIN (0.126f) -#define AL_EQUALIZER_MAX_MID1_GAIN (7.943f) -#define AL_EQUALIZER_DEFAULT_MID1_GAIN (1.0f) - -#define AL_EQUALIZER_MIN_MID1_CENTER (200.0f) -#define AL_EQUALIZER_MAX_MID1_CENTER (3000.0f) -#define AL_EQUALIZER_DEFAULT_MID1_CENTER (500.0f) - -#define AL_EQUALIZER_MIN_MID1_WIDTH (0.01f) -#define AL_EQUALIZER_MAX_MID1_WIDTH (1.0f) -#define AL_EQUALIZER_DEFAULT_MID1_WIDTH (1.0f) - -#define AL_EQUALIZER_MIN_MID2_GAIN (0.126f) -#define AL_EQUALIZER_MAX_MID2_GAIN (7.943f) -#define AL_EQUALIZER_DEFAULT_MID2_GAIN (1.0f) - -#define AL_EQUALIZER_MIN_MID2_CENTER (1000.0f) -#define AL_EQUALIZER_MAX_MID2_CENTER (8000.0f) -#define AL_EQUALIZER_DEFAULT_MID2_CENTER (3000.0f) - -#define AL_EQUALIZER_MIN_MID2_WIDTH (0.01f) -#define AL_EQUALIZER_MAX_MID2_WIDTH (1.0f) -#define AL_EQUALIZER_DEFAULT_MID2_WIDTH (1.0f) - -#define AL_EQUALIZER_MIN_HIGH_GAIN (0.126f) -#define AL_EQUALIZER_MAX_HIGH_GAIN (7.943f) -#define AL_EQUALIZER_DEFAULT_HIGH_GAIN (1.0f) - -#define AL_EQUALIZER_MIN_HIGH_CUTOFF (4000.0f) -#define AL_EQUALIZER_MAX_HIGH_CUTOFF (16000.0f) -#define AL_EQUALIZER_DEFAULT_HIGH_CUTOFF (6000.0f) - - -/* Source parameter value ranges and defaults. */ -#define AL_MIN_AIR_ABSORPTION_FACTOR (0.0f) -#define AL_MAX_AIR_ABSORPTION_FACTOR (10.0f) -#define AL_DEFAULT_AIR_ABSORPTION_FACTOR (0.0f) - -#define AL_MIN_ROOM_ROLLOFF_FACTOR (0.0f) -#define AL_MAX_ROOM_ROLLOFF_FACTOR (10.0f) -#define AL_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) - -#define AL_MIN_CONE_OUTER_GAINHF (0.0f) -#define AL_MAX_CONE_OUTER_GAINHF (1.0f) -#define AL_DEFAULT_CONE_OUTER_GAINHF (1.0f) - -#define AL_MIN_DIRECT_FILTER_GAINHF_AUTO AL_FALSE -#define AL_MAX_DIRECT_FILTER_GAINHF_AUTO AL_TRUE -#define AL_DEFAULT_DIRECT_FILTER_GAINHF_AUTO AL_TRUE - -#define AL_MIN_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_FALSE -#define AL_MAX_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE -#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE - -#define AL_MIN_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_FALSE -#define AL_MAX_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE -#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE - - -/* Listener parameter value ranges and defaults. */ -#define AL_MIN_METERS_PER_UNIT FLT_MIN -#define AL_MAX_METERS_PER_UNIT FLT_MAX -#define AL_DEFAULT_METERS_PER_UNIT (1.0f) - - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* AL_EFX_H */ diff --git a/thirdparty/include/Catch/catch.hpp b/thirdparty/include/Catch/catch.hpp deleted file mode 100644 index cf1fae15a..000000000 --- a/thirdparty/include/Catch/catch.hpp +++ /dev/null @@ -1,17799 +0,0 @@ -/* - * Catch v2.13.0 - * Generated: 2020-07-12 20:07:49.015950 - * ---------------------------------------------------------- - * This file has been merged from multiple headers. Please don't edit it directly - * Copyright (c) 2020 Two Blue Cubes Ltd. All rights reserved. - * - * Distributed under the Boost Software License, Version 1.0. (See accompanying - * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ -#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED -#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED -// start catch.hpp - - -#define CATCH_VERSION_MAJOR 2 -#define CATCH_VERSION_MINOR 13 -#define CATCH_VERSION_PATCH 0 - -#ifdef __clang__ -# pragma clang system_header -#elif defined __GNUC__ -# pragma GCC system_header -#endif - -// start catch_suppress_warnings.h - -#ifdef __clang__ -# ifdef __ICC // icpc defines the __clang__ macro -# pragma warning(push) -# pragma warning(disable: 161 1682) -# else // __ICC -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wpadded" -# pragma clang diagnostic ignored "-Wswitch-enum" -# pragma clang diagnostic ignored "-Wcovered-switch-default" -# endif -#elif defined __GNUC__ - // Because REQUIREs trigger GCC's -Wparentheses, and because still - // supported version of g++ have only buggy support for _Pragmas, - // Wparentheses have to be suppressed globally. -# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details - -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wunused-variable" -# pragma GCC diagnostic ignored "-Wpadded" -#endif -// end catch_suppress_warnings.h -#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) -# define CATCH_IMPL -# define CATCH_CONFIG_ALL_PARTS -#endif - -// In the impl file, we want to have access to all parts of the headers -// Can also be used to sanely support PCHs -#if defined(CATCH_CONFIG_ALL_PARTS) -# define CATCH_CONFIG_EXTERNAL_INTERFACES -# if defined(CATCH_CONFIG_DISABLE_MATCHERS) -# undef CATCH_CONFIG_DISABLE_MATCHERS -# endif -# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) -# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER -# endif -#endif - -#if !defined(CATCH_CONFIG_IMPL_ONLY) -// start catch_platform.h - -#ifdef __APPLE__ -# include -# if TARGET_OS_OSX == 1 -# define CATCH_PLATFORM_MAC -# elif TARGET_OS_IPHONE == 1 -# define CATCH_PLATFORM_IPHONE -# endif - -#elif defined(linux) || defined(__linux) || defined(__linux__) -# define CATCH_PLATFORM_LINUX - -#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) -# define CATCH_PLATFORM_WINDOWS -#endif - -// end catch_platform.h - -#ifdef CATCH_IMPL -# ifndef CLARA_CONFIG_MAIN -# define CLARA_CONFIG_MAIN_NOT_DEFINED -# define CLARA_CONFIG_MAIN -# endif -#endif - -// start catch_user_interfaces.h - -namespace Catch { - unsigned int rngSeed(); -} - -// end catch_user_interfaces.h -// start catch_tag_alias_autoregistrar.h - -// start catch_common.h - -// start catch_compiler_capabilities.h - -// Detect a number of compiler features - by compiler -// The following features are defined: -// -// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? -// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? -// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? -// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? -// **************** -// Note to maintainers: if new toggles are added please document them -// in configuration.md, too -// **************** - -// In general each macro has a _NO_ form -// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. -// Many features, at point of detection, define an _INTERNAL_ macro, so they -// can be combined, en-mass, with the _NO_ forms later. - -#ifdef __cplusplus - -# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) -# define CATCH_CPP14_OR_GREATER -# endif - -# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) -# define CATCH_CPP17_OR_GREATER -# endif - -#endif - -#if defined(__cpp_lib_uncaught_exceptions) -# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS -#endif - -// We have to avoid both ICC and Clang, because they try to mask themselves -// as gcc, and we want only GCC in this block -#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) - -# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) - -#endif - -#if defined(__clang__) - -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) - -// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug -// which results in calls to destructors being emitted for each temporary, -// without a matching initialization. In practice, this can result in something -// like `std::string::~string` being called on an uninitialized value. -// -// For example, this code will likely segfault under IBM XL: -// ``` -// REQUIRE(std::string("12") + "34" == "1234") -// ``` -// -// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. -# if !defined(__ibmxl__) -# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ -# endif - -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ - _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") - -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) - -# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) - -# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) - -# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) - -#endif // __clang__ - -//////////////////////////////////////////////////////////////////////////////// -// Assume that non-Windows platforms support posix signals by default -#if !defined(CATCH_PLATFORM_WINDOWS) - #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS -#endif - -//////////////////////////////////////////////////////////////////////////////// -// We know some environments not to support full POSIX signals -#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) - #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS -#endif - -#ifdef __OS400__ -# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS -# define CATCH_CONFIG_COLOUR_NONE -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Android somehow still does not support std::to_string -#if defined(__ANDROID__) -# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING -# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Not all Windows environments support SEH properly -#if defined(__MINGW32__) -# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH -#endif - -//////////////////////////////////////////////////////////////////////////////// -// PS4 -#if defined(__ORBIS__) -# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Cygwin -#ifdef __CYGWIN__ - -// Required for some versions of Cygwin to declare gettimeofday -// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin -# define _BSD_SOURCE -// some versions of cygwin (most) do not support std::to_string. Use the libstd check. -// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 -# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ - && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) - -# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING - -# endif -#endif // __CYGWIN__ - -//////////////////////////////////////////////////////////////////////////////// -// Visual C++ -#if defined(_MSC_VER) - -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) - -# if _MSC_VER >= 1900 // Visual Studio 2015 or newer -# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS -# endif - -// Universal Windows platform does not support SEH -// Or console colours (or console at all...) -# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) -# define CATCH_CONFIG_COLOUR_NONE -# else -# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH -# endif - -// MSVC traditional preprocessor needs some workaround for __VA_ARGS__ -// _MSVC_TRADITIONAL == 0 means new conformant preprocessor -// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor -# if !defined(__clang__) // Handle Clang masquerading for msvc -# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) -# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -# endif // MSVC_TRADITIONAL -# endif // __clang__ - -#endif // _MSC_VER - -#if defined(_REENTRANT) || defined(_MSC_VER) -// Enable async processing, as -pthread is specified or no additional linking is required -# define CATCH_INTERNAL_CONFIG_USE_ASYNC -#endif // _MSC_VER - -//////////////////////////////////////////////////////////////////////////////// -// Check if we are compiled with -fno-exceptions or equivalent -#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) -# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED -#endif - -//////////////////////////////////////////////////////////////////////////////// -// DJGPP -#ifdef __DJGPP__ -# define CATCH_INTERNAL_CONFIG_NO_WCHAR -#endif // __DJGPP__ - -//////////////////////////////////////////////////////////////////////////////// -// Embarcadero C++Build -#if defined(__BORLANDC__) - #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN -#endif - -//////////////////////////////////////////////////////////////////////////////// - -// Use of __COUNTER__ is suppressed during code analysis in -// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly -// handled by it. -// Otherwise all supported compilers support COUNTER macro, -// but user still might want to turn it off -#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) - #define CATCH_INTERNAL_CONFIG_COUNTER -#endif - -//////////////////////////////////////////////////////////////////////////////// - -// RTX is a special version of Windows that is real time. -// This means that it is detected as Windows, but does not provide -// the same set of capabilities as real Windows does. -#if defined(UNDER_RTSS) || defined(RTX64_BUILD) - #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH - #define CATCH_INTERNAL_CONFIG_NO_ASYNC - #define CATCH_CONFIG_COLOUR_NONE -#endif - -#if !defined(_GLIBCXX_USE_C99_MATH_TR1) -#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER -#endif - -// Various stdlib support checks that require __has_include -#if defined(__has_include) - // Check if string_view is available and usable - #if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW - #endif - - // Check if optional is available and usable - # if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL - # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) - - // Check if byte is available and usable - # if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # define CATCH_INTERNAL_CONFIG_CPP17_BYTE - # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) - - // Check if variant is available and usable - # if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # if defined(__clang__) && (__clang_major__ < 8) - // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 - // fix should be in clang 8, workaround in libstdc++ 8.2 - # include - # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) - # define CATCH_CONFIG_NO_CPP17_VARIANT - # else - # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT - # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) - # else - # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT - # endif // defined(__clang__) && (__clang_major__ < 8) - # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) -#endif // defined(__has_include) - -#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) -# define CATCH_CONFIG_COUNTER -#endif -#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) -# define CATCH_CONFIG_WINDOWS_SEH -#endif -// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. -#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) -# define CATCH_CONFIG_POSIX_SIGNALS -#endif -// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. -#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) -# define CATCH_CONFIG_WCHAR -#endif - -#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) -# define CATCH_CONFIG_CPP11_TO_STRING -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) -# define CATCH_CONFIG_CPP17_OPTIONAL -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) -# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) -# define CATCH_CONFIG_CPP17_STRING_VIEW -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) -# define CATCH_CONFIG_CPP17_VARIANT -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) -# define CATCH_CONFIG_CPP17_BYTE -#endif - -#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) -# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE -#endif - -#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) -# define CATCH_CONFIG_NEW_CAPTURE -#endif - -#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) -# define CATCH_CONFIG_DISABLE_EXCEPTIONS -#endif - -#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) -# define CATCH_CONFIG_POLYFILL_ISNAN -#endif - -#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) -# define CATCH_CONFIG_USE_ASYNC -#endif - -#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) -# define CATCH_CONFIG_ANDROID_LOGWRITE -#endif - -#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) -# define CATCH_CONFIG_GLOBAL_NEXTAFTER -#endif - -// Even if we do not think the compiler has that warning, we still have -// to provide a macro that can be used by the code. -#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION -#endif -#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS -#endif - -// The goal of this macro is to avoid evaluation of the arguments, but -// still have the compiler warn on problems inside... -#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN) -# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) -#endif - -#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) -# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS -#elif defined(__clang__) && (__clang_major__ < 5) -# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS -#endif - -#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS -#endif - -#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) -#define CATCH_TRY if ((true)) -#define CATCH_CATCH_ALL if ((false)) -#define CATCH_CATCH_ANON(type) if ((false)) -#else -#define CATCH_TRY try -#define CATCH_CATCH_ALL catch (...) -#define CATCH_CATCH_ANON(type) catch (type) -#endif - -#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) -#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#endif - -// end catch_compiler_capabilities.h -#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line -#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) -#ifdef CATCH_CONFIG_COUNTER -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) -#else -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) -#endif - -#include -#include -#include - -// We need a dummy global operator<< so we can bring it into Catch namespace later -struct Catch_global_namespace_dummy {}; -std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); - -namespace Catch { - - struct CaseSensitive { enum Choice { - Yes, - No - }; }; - - class NonCopyable { - NonCopyable( NonCopyable const& ) = delete; - NonCopyable( NonCopyable && ) = delete; - NonCopyable& operator = ( NonCopyable const& ) = delete; - NonCopyable& operator = ( NonCopyable && ) = delete; - - protected: - NonCopyable(); - virtual ~NonCopyable(); - }; - - struct SourceLineInfo { - - SourceLineInfo() = delete; - SourceLineInfo( char const* _file, std::size_t _line ) noexcept - : file( _file ), - line( _line ) - {} - - SourceLineInfo( SourceLineInfo const& other ) = default; - SourceLineInfo& operator = ( SourceLineInfo const& ) = default; - SourceLineInfo( SourceLineInfo&& ) noexcept = default; - SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; - - bool empty() const noexcept { return file[0] == '\0'; } - bool operator == ( SourceLineInfo const& other ) const noexcept; - bool operator < ( SourceLineInfo const& other ) const noexcept; - - char const* file; - std::size_t line; - }; - - std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); - - // Bring in operator<< from global namespace into Catch namespace - // This is necessary because the overload of operator<< above makes - // lookup stop at namespace Catch - using ::operator<<; - - // Use this in variadic streaming macros to allow - // >> +StreamEndStop - // as well as - // >> stuff +StreamEndStop - struct StreamEndStop { - std::string operator+() const; - }; - template - T const& operator + ( T const& value, StreamEndStop ) { - return value; - } -} - -#define CATCH_INTERNAL_LINEINFO \ - ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) - -// end catch_common.h -namespace Catch { - - struct RegistrarForTagAliases { - RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); - }; - -} // end namespace Catch - -#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION - -// end catch_tag_alias_autoregistrar.h -// start catch_test_registry.h - -// start catch_interfaces_testcase.h - -#include - -namespace Catch { - - class TestSpec; - - struct ITestInvoker { - virtual void invoke () const = 0; - virtual ~ITestInvoker(); - }; - - class TestCase; - struct IConfig; - - struct ITestCaseRegistry { - virtual ~ITestCaseRegistry(); - virtual std::vector const& getAllTests() const = 0; - virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; - }; - - bool isThrowSafe( TestCase const& testCase, IConfig const& config ); - bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); - std::vector const& getAllTestCasesSorted( IConfig const& config ); - -} - -// end catch_interfaces_testcase.h -// start catch_stringref.h - -#include -#include -#include -#include - -namespace Catch { - - /// A non-owning string class (similar to the forthcoming std::string_view) - /// Note that, because a StringRef may be a substring of another string, - /// it may not be null terminated. - class StringRef { - public: - using size_type = std::size_t; - using const_iterator = const char*; - - private: - static constexpr char const* const s_empty = ""; - - char const* m_start = s_empty; - size_type m_size = 0; - - public: // construction - constexpr StringRef() noexcept = default; - - StringRef( char const* rawChars ) noexcept; - - constexpr StringRef( char const* rawChars, size_type size ) noexcept - : m_start( rawChars ), - m_size( size ) - {} - - StringRef( std::string const& stdString ) noexcept - : m_start( stdString.c_str() ), - m_size( stdString.size() ) - {} - - explicit operator std::string() const { - return std::string(m_start, m_size); - } - - public: // operators - auto operator == ( StringRef const& other ) const noexcept -> bool; - auto operator != (StringRef const& other) const noexcept -> bool { - return !(*this == other); - } - - auto operator[] ( size_type index ) const noexcept -> char { - assert(index < m_size); - return m_start[index]; - } - - public: // named queries - constexpr auto empty() const noexcept -> bool { - return m_size == 0; - } - constexpr auto size() const noexcept -> size_type { - return m_size; - } - - // Returns the current start pointer. If the StringRef is not - // null-terminated, throws std::domain_exception - auto c_str() const -> char const*; - - public: // substrings and searches - // Returns a substring of [start, start + length). - // If start + length > size(), then the substring is [start, size()). - // If start > size(), then the substring is empty. - auto substr( size_type start, size_type length ) const noexcept -> StringRef; - - // Returns the current start pointer. May not be null-terminated. - auto data() const noexcept -> char const*; - - constexpr auto isNullTerminated() const noexcept -> bool { - return m_start[m_size] == '\0'; - } - - public: // iterators - constexpr const_iterator begin() const { return m_start; } - constexpr const_iterator end() const { return m_start + m_size; } - }; - - auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; - auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; - - constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { - return StringRef( rawChars, size ); - } -} // namespace Catch - -constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { - return Catch::StringRef( rawChars, size ); -} - -// end catch_stringref.h -// start catch_preprocessor.hpp - - -#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ -#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) -#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) -#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) -#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) -#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) - -#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ -// MSVC needs more evaluations -#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) -#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) -#else -#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) -#endif - -#define CATCH_REC_END(...) -#define CATCH_REC_OUT - -#define CATCH_EMPTY() -#define CATCH_DEFER(id) id CATCH_EMPTY() - -#define CATCH_REC_GET_END2() 0, CATCH_REC_END -#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 -#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 -#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT -#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) -#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) - -#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) - -#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) - -// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, -// and passes userdata as the first parameter to each invocation, -// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) -#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) - -#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) - -#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) -#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ -#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ -#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF -#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) -#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ -#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) -#else -// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF -#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) -#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ -#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) -#endif - -#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ -#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) - -#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) - -#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper()) -#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) -#else -#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper())) -#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) -#endif - -#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ - CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) - -#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) -#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) -#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) -#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) -#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) -#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) -#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6) -#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) -#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) -#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) -#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) - -#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N - -#define INTERNAL_CATCH_TYPE_GEN\ - template struct TypeList {};\ - template\ - constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ - template class...> struct TemplateTypeList{};\ - template class...Cs>\ - constexpr auto get_wrapper() noexcept -> TemplateTypeList { return {}; }\ - template\ - struct append;\ - template\ - struct rewrap;\ - template class, typename...>\ - struct create;\ - template class, typename>\ - struct convert;\ - \ - template \ - struct append { using type = T; };\ - template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ - struct append, L2, Rest...> { using type = typename append, Rest...>::type; };\ - template< template class L1, typename...E1, typename...Rest>\ - struct append, TypeList, Rest...> { using type = L1; };\ - \ - template< template class Container, template class List, typename...elems>\ - struct rewrap, List> { using type = TypeList>; };\ - template< template class Container, template class List, class...Elems, typename...Elements>\ - struct rewrap, List, Elements...> { using type = typename append>, typename rewrap, Elements...>::type>::type; };\ - \ - template