diff --git a/.vscode/settings.json b/.vscode/settings.json index 5e4ff75f..a77dade8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "cmake.parallelJobs": 8 + "cmake.parallelJobs": 8, } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index aa626307..86dbf16f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,10 +27,14 @@ add_executable(blocks WIN32 src/rand.c src/save.c src/shader.c + src/sky.c + src/sort.c src/voxel.c + src/worker.c src/world.c ) set_target_properties(blocks PROPERTIES C_STANDARD 11) +target_compile_definitions(blocks PRIVATE SDL_ASSERT_LEVEL=$,3,0>) target_include_directories(blocks PUBLIC lib/jsmn) target_include_directories(blocks PUBLIC lib/sqlite3) target_include_directories(blocks PUBLIC lib/stb) @@ -86,19 +90,13 @@ function(add_shader FILE) endif() package(${JSON}) endfunction() -add_shader(blur.comp shaders/shader.hlsl src/voxel.inc) -add_shader(composite.comp shaders/shader.hlsl src/voxel.inc) -add_shader(depth.frag shaders/shader.hlsl src/voxel.inc) -add_shader(depth.vert shaders/shader.hlsl src/voxel.inc) +add_shader(hud.frag) +add_shader(hud.vert) add_shader(opaque.frag shaders/shader.hlsl src/voxel.inc) add_shader(opaque.vert shaders/shader.hlsl src/voxel.inc) add_shader(raycast.frag shaders/shader.hlsl src/voxel.inc) add_shader(raycast.vert shaders/shader.hlsl src/voxel.inc) -add_shader(shadow.frag shaders/shader.hlsl src/voxel.inc) -add_shader(shadow.vert shaders/shader.hlsl src/voxel.inc) add_shader(sky.frag shaders/shader.hlsl src/voxel.inc) add_shader(sky.vert shaders/shader.hlsl src/voxel.inc) -add_shader(ssao.comp shaders/shader.hlsl src/voxel.inc) add_shader(transparent.frag shaders/shader.hlsl src/voxel.inc) add_shader(transparent.vert shaders/shader.hlsl src/voxel.inc) -add_shader(ui.comp shaders/shader.hlsl src/voxel.inc) diff --git a/README.md b/README.md index 7e7baaf8..76b996fb 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Blocks -![](image.png) +![](doc/image1.png) +![](doc/image2.png) Tiny Minecraft clone in C and HLSL using the new SDL3 GPU API @@ -10,9 +11,9 @@ Tiny Minecraft clone in C and HLSL using the new SDL3 GPU API - Asynchronous chunk loading - Persistent worlds - Physics -- Directional shadows -- Clustered dynamic lighting - Blocks and sprites +- Basic lighting +- Day and night cycle ### Building @@ -59,16 +60,4 @@ To build locally, add [SDL_shadercross](https://github.com/libsdl-org/SDL_shader - `Scroll` to change blocks - `F11` to toggle fullscreen - `LControl` to sprint - -### Passes - -1. Render opaques to depth texture (for shadows) -2. Render sky to G-buffer -3. Render opaques to G-buffer -4. Calculate SSAO -5. Blur SSAO -6. Composite G-buffer -7. Render transparents to depth teture (for predepth) -8. Render transparents and composite -9. Render raycast -10. Render UI +- `T` to reset the time of day diff --git a/doc/image1.png b/doc/image1.png new file mode 100644 index 00000000..1c180496 Binary files /dev/null and b/doc/image1.png differ diff --git a/doc/image2.png b/doc/image2.png new file mode 100644 index 00000000..29659daa Binary files /dev/null and b/doc/image2.png differ diff --git a/image.png b/image.png deleted file mode 100644 index 71fe42c1..00000000 Binary files a/image.png and /dev/null differ diff --git a/lib/SDL b/lib/SDL index 34b620c3..f00052ff 160000 --- a/lib/SDL +++ b/lib/SDL @@ -1 +1 @@ -Subproject commit 34b620c3f86cb2b5adf11440cdf79a3cec216269 +Subproject commit f00052ffe24b8540a6b27b93ab9197278c80d157 diff --git a/shaders/bin/blur.comp.json b/shaders/bin/blur.comp.json deleted file mode 100644 index 893a14df..00000000 --- a/shaders/bin/blur.comp.json +++ /dev/null @@ -1 +0,0 @@ -{ "samplers": 0, "readonly_storage_textures": 1, "readonly_storage_buffers": 0, "readwrite_storage_textures": 1, "readwrite_storage_buffers": 0, "uniform_buffers": 0, "threadcount_x": 8, "threadcount_y": 8, "threadcount_z": 1 } diff --git a/shaders/bin/blur.comp.msl b/shaders/bin/blur.comp.msl deleted file mode 100644 index fc385b5b..00000000 --- a/shaders/bin/blur.comp.msl +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include - -using namespace metal; - -kernel void main0(texture2d inputTexture [[texture(0)]], texture2d outputTexture [[texture(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) -{ - do - { - uint2 _35 = uint2(outputTexture.get_width(), outputTexture.get_height()); - uint _36 = _35.x; - uint _37 = _35.y; - bool _46; - if (gl_GlobalInvocationID.x < _36) - { - _46 = gl_GlobalInvocationID.y >= _37; - } - else - { - _46 = true; - } - if (_46) - { - break; - } - float _50; - _50 = 0.0; - float _51; - for (int _53 = -2; _53 <= 2; _50 = _51, _53++) - { - uint _63 = clamp(gl_GlobalInvocationID.y + uint(_53), 0u, _37 - 1u); - _51 = _50; - for (int _67 = -2; _67 <= 2; ) - { - _51 += inputTexture.read(uint2(uint2(clamp(gl_GlobalInvocationID.x + uint(_67), 0u, _36 - 1u), _63)), 0u).x; - _67++; - continue; - } - } - outputTexture.write(float4(_50 * 0.039999999105930328369140625), uint2(gl_GlobalInvocationID.xy)); - break; - } while(false); -} - diff --git a/shaders/bin/blur.comp.spv b/shaders/bin/blur.comp.spv deleted file mode 100644 index 4d18b1bb..00000000 Binary files a/shaders/bin/blur.comp.spv and /dev/null differ diff --git a/shaders/bin/composite.comp.json b/shaders/bin/composite.comp.json deleted file mode 100644 index 7dedc6ba..00000000 --- a/shaders/bin/composite.comp.json +++ /dev/null @@ -1 +0,0 @@ -{ "samplers": 1, "readonly_storage_textures": 5, "readonly_storage_buffers": 0, "readwrite_storage_textures": 1, "readwrite_storage_buffers": 0, "uniform_buffers": 2, "threadcount_x": 8, "threadcount_y": 8, "threadcount_z": 1 } diff --git a/shaders/bin/composite.comp.msl b/shaders/bin/composite.comp.msl deleted file mode 100644 index c9c855e2..00000000 --- a/shaders/bin/composite.comp.msl +++ /dev/null @@ -1,193 +0,0 @@ -#pragma clang diagnostic ignored "-Wmissing-prototypes" -#pragma clang diagnostic ignored "-Wmissing-braces" - -#include -#include - -using namespace metal; - -template -struct spvUnsafeArray -{ - T elements[Num ? Num : 1]; - - thread T& operator [] (size_t pos) thread - { - return elements[pos]; - } - constexpr const thread T& operator [] (size_t pos) const thread - { - return elements[pos]; - } - - device T& operator [] (size_t pos) device - { - return elements[pos]; - } - constexpr const device T& operator [] (size_t pos) const device - { - return elements[pos]; - } - - constexpr const constant T& operator [] (size_t pos) const constant - { - return elements[pos]; - } - - threadgroup T& operator [] (size_t pos) threadgroup - { - return elements[pos]; - } - constexpr const threadgroup T& operator [] (size_t pos) const threadgroup - { - return elements[pos]; - } -}; - -struct type_UniformBuffer -{ - float4x4 ShadowTransform; -}; - -struct type_UniformBuffer_1 -{ - float3 PlayerPosition; -}; - -constant spvUnsafeArray _79 = spvUnsafeArray({ float3(0.0, 0.0, 1.0), float3(0.0, 0.0, -1.0), float3(1.0, 0.0, 0.0), float3(-1.0, 0.0, 0.0), float3(0.0, 1.0, 0.0), float3(0.0, -1.0, 0.0), float3(0.0, 1.0, 0.0), float3(0.0, 1.0, 0.0), float3(0.0, 1.0, 0.0), float3(0.0, 1.0, 0.0) }); - -kernel void main0(constant type_UniformBuffer& UniformBuffer [[buffer(0)]], constant type_UniformBuffer_1& UniformBuffer_1 [[buffer(1)]], texture2d shadowTexture [[texture(0)]], texture2d colorTexture [[texture(1)]], texture2d lightTexture [[texture(2)]], texture2d ssaoTexture [[texture(3)]], texture2d voxelTexture [[texture(4)]], texture2d positionTexture [[texture(5)]], texture2d compositeTexture [[texture(6)]], sampler shadowSampler [[sampler(0)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) -{ - do - { - uint2 _93 = uint2(colorTexture.get_width(), colorTexture.get_height()); - bool _104; - if (gl_GlobalInvocationID.x < _93.x) - { - _104 = gl_GlobalInvocationID.y >= _93.y; - } - else - { - _104 = true; - } - if (_104) - { - break; - } - float3 _110 = colorTexture.read(uint2(gl_GlobalInvocationID.xy), 0u).xyz; - uint4 _112 = voxelTexture.read(uint2(gl_GlobalInvocationID.xy), 0u); - uint _113 = _112.x; - float4 _115 = positionTexture.read(uint2(gl_GlobalInvocationID.xy), 0u); - float3 _124 = lightTexture.read(uint2(gl_GlobalInvocationID.xy), 0u).xyz; - float _186; - do - { - float4 _135 = UniformBuffer.ShadowTransform * float4(_115.xyz, 1.0); - float3 _139 = _135.xyz / float3(_135.w); - float2 _142 = (_139.xy * 0.5) + float2(0.5); - float _144 = 1.0 - _142.y; - float2 _145 = _142; - _145.y = _144; - float _146 = _142.x; - bool _151; - if ((isunordered(_146, 0.0) || _146 >= 0.0)) - { - _151 = _146 > 1.0; - } - else - { - _151 = true; - } - bool _156; - if (!_151) - { - _156 = _144 < 0.0; - } - else - { - _156 = true; - } - bool _161; - if (!_156) - { - _161 = _144 > 1.0; - } - else - { - _161 = true; - } - if (_161) - { - _186 = 0.4000000059604644775390625; - break; - } - float _175; - if ((_113 & 1u) != 0u) - { - float _171 = dot(_79[((_113 >> 1u) & 15u) - 1u], fast::normalize(float4(UniformBuffer.ShadowTransform[0][2], UniformBuffer.ShadowTransform[1][2], UniformBuffer.ShadowTransform[2][2], UniformBuffer.ShadowTransform[3][2]).xyz)); - if (_171 > 0.0) - { - _186 = 0.0; - break; - } - _175 = _171; - } - else - { - _175 = -0.7070000171661376953125; - } - if (_139.z < (shadowTexture.sample(shadowSampler, _145, level(0.0)).x + 0.001000000047497451305389404296875)) - { - _186 = _175 * (-0.4000000059604644775390625); - break; - } - else - { - _186 = 0.0; - break; - } - break; // unreachable workaround - } while(false); - float3 _216; - if ((_113 & 1u) != 0u) - { - _216 = _110 * (((_124 + float3(0.5)) + float3(_186)) - float3(ssaoTexture.read(uint2(gl_GlobalInvocationID.xy), 0u).x * 2.0)); - } - else - { - float _196 = length(_110); - bool _201; - if ((isunordered(_196, 0.999000012874603271484375) || _196 <= 0.999000012874603271484375)) - { - _201 = _113 == 0u; - } - else - { - _201 = true; - } - float3 _209; - if (_201) - { - _209 = _110; - } - else - { - _209 = _110 * ((_124 + float3(0.5)) + float3(_186)); - } - _216 = _209; - } - float3 _241; - if (_113 != 0u) - { - float3 _222 = _115.xyz - UniformBuffer_1.PlayerPosition; - _241 = mix(_216, mix(float3(0.2199999988079071044921875, 0.3490000069141387939453125, 0.70200002193450927734375), float3(0.21199999749660491943359375, 0.7730000019073486328125, 0.9570000171661376953125), float3((precise::atan2(_222.y, length(float2(_222.xz))) + 1.57079637050628662109375) * 0.3183098733425140380859375)), float3(precise::min(powr(distance(_115.xz, UniformBuffer_1.PlayerPosition.xz) * 0.0040000001899898052215576171875, 2.5), 1.0))); - } - else - { - _241 = _216; - } - compositeTexture.write(float4(_241, 1.0), uint2(gl_GlobalInvocationID.xy)); - break; - } while(false); -} - diff --git a/shaders/bin/composite.comp.spv b/shaders/bin/composite.comp.spv deleted file mode 100644 index 4d619834..00000000 Binary files a/shaders/bin/composite.comp.spv and /dev/null differ diff --git a/shaders/bin/depth.frag.json b/shaders/bin/depth.frag.json deleted file mode 100644 index 5da52262..00000000 --- a/shaders/bin/depth.frag.json +++ /dev/null @@ -1 +0,0 @@ -{ "samplers": 0, "storage_textures": 0, "storage_buffers": 0, "uniform_buffers": 0, "inputs": [], "outputs": [] } diff --git a/shaders/bin/depth.frag.msl b/shaders/bin/depth.frag.msl deleted file mode 100644 index 92ac1d9f..00000000 --- a/shaders/bin/depth.frag.msl +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include - -using namespace metal; - -fragment void main0() -{ -} - diff --git a/shaders/bin/depth.frag.spv b/shaders/bin/depth.frag.spv deleted file mode 100644 index b893138e..00000000 Binary files a/shaders/bin/depth.frag.spv and /dev/null differ diff --git a/shaders/bin/depth.vert.json b/shaders/bin/depth.vert.json deleted file mode 100644 index e6fb9331..00000000 --- a/shaders/bin/depth.vert.json +++ /dev/null @@ -1 +0,0 @@ -{ "samplers": 0, "storage_textures": 0, "storage_buffers": 0, "uniform_buffers": 3, "inputs": [{ "name": "in.var.TEXCOORD0", "type": "uint", "location": 0 }], "outputs": [] } diff --git a/shaders/bin/depth.vert.msl b/shaders/bin/depth.vert.msl deleted file mode 100644 index f7e93d19..00000000 --- a/shaders/bin/depth.vert.msl +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include - -using namespace metal; - -struct type_UniformBuffer -{ - float4x4 Proj; -}; - -struct type_UniformBuffer_1 -{ - float4x4 View; -}; - -struct type_UniformBuffer_2 -{ - int2 ChunkPosition; -}; - -struct main0_out -{ - float4 gl_Position [[position]]; -}; - -struct main0_in -{ - uint in_var_TEXCOORD0 [[attribute(0)]]; -}; - -vertex main0_out main0(main0_in in [[stage_in]], constant type_UniformBuffer& UniformBuffer [[buffer(0)]], constant type_UniformBuffer_1& UniformBuffer_1 [[buffer(1)]], constant type_UniformBuffer_2& UniformBuffer_2 [[buffer(2)]]) -{ - main0_out out = {}; - out.gl_Position = UniformBuffer.Proj * (UniformBuffer_1.View * float4(float3(float((in.in_var_TEXCOORD0 >> 6u) & 31u), float((in.in_var_TEXCOORD0 >> 11u) & 255u), float((in.in_var_TEXCOORD0 >> 19u) & 31u)) + float3(int3(float3(float(UniformBuffer_2.ChunkPosition.x), 0.0, float(UniformBuffer_2.ChunkPosition.y)))), 1.0)); - return out; -} - diff --git a/shaders/bin/depth.vert.spv b/shaders/bin/depth.vert.spv deleted file mode 100644 index 2116b299..00000000 Binary files a/shaders/bin/depth.vert.spv and /dev/null differ diff --git a/shaders/bin/hud.frag.json b/shaders/bin/hud.frag.json new file mode 100644 index 00000000..bd643723 --- /dev/null +++ b/shaders/bin/hud.frag.json @@ -0,0 +1 @@ +{ "samplers": 1, "storage_textures": 0, "storage_buffers": 0, "uniform_buffers": 1, "inputs": [{ "name": "in.var.TEXCOORD0", "type": "float2", "location": 0 }, { "name": "in.var.TEXCOORD1", "type": "uint", "location": 1 }], "outputs": [{ "name": "out.var.SV_Target0", "type": "float4", "location": 0 }] } diff --git a/shaders/bin/hud.frag.msl b/shaders/bin/hud.frag.msl new file mode 100644 index 00000000..16409d29 --- /dev/null +++ b/shaders/bin/hud.frag.msl @@ -0,0 +1,45 @@ +#include +#include + +using namespace metal; + +struct type_UniformBuffer +{ + uint Block; +}; + +struct main0_out +{ + float4 out_var_SV_Target0 [[color(0)]]; +}; + +struct main0_in +{ + float2 in_var_TEXCOORD0 [[user(locn0)]]; + uint in_var_TEXCOORD1 [[user(locn1)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], constant type_UniformBuffer& UniformBuffer [[buffer(0)]], texture2d_array atlasTexture [[texture(0)]], sampler atlasSampler [[sampler(0)]]) +{ + main0_out out = {}; + float4 _55; + do + { + if (in.in_var_TEXCOORD1 == 0u) + { + _55 = float4(1.0); + break; + } + float3 _48 = float3(in.in_var_TEXCOORD0, float(UniformBuffer.Block)); + float4 _50 = atlasTexture.sample(atlasSampler, _48.xy, uint(rint(_48.z))); + if (_50.w <= 0.001000000047497451305389404296875) + { + discard_fragment(); + } + _55 = _50; + break; + } while(false); + out.out_var_SV_Target0 = _55; + return out; +} + diff --git a/shaders/bin/hud.frag.spv b/shaders/bin/hud.frag.spv new file mode 100644 index 00000000..a2e7154b Binary files /dev/null and b/shaders/bin/hud.frag.spv differ diff --git a/shaders/bin/hud.vert.json b/shaders/bin/hud.vert.json new file mode 100644 index 00000000..b6927f2d --- /dev/null +++ b/shaders/bin/hud.vert.json @@ -0,0 +1 @@ +{ "samplers": 0, "storage_textures": 0, "storage_buffers": 0, "uniform_buffers": 1, "inputs": [], "outputs": [{ "name": "out.var.TEXCOORD0", "type": "float2", "location": 0 }, { "name": "out.var.TEXCOORD1", "type": "uint", "location": 1 }] } diff --git a/shaders/bin/hud.vert.msl b/shaders/bin/hud.vert.msl new file mode 100644 index 00000000..243a4715 --- /dev/null +++ b/shaders/bin/hud.vert.msl @@ -0,0 +1,88 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_UniformBuffer +{ + int2 Viewport; +}; + +constant spvUnsafeArray _48 = spvUnsafeArray({ float2(0.0), float2(1.0, 0.0), float2(0.0, 1.0), float2(0.0, 1.0), float2(1.0, 0.0), float2(1.0) }); + +struct main0_out +{ + float2 out_var_TEXCOORD0 [[user(locn0)]]; + uint out_var_TEXCOORD1 [[user(locn1)]]; + float4 gl_Position [[position]]; +}; + +vertex main0_out main0(constant type_UniformBuffer& UniformBuffer [[buffer(0)]], uint gl_VertexIndex [[vertex_id]], uint gl_InstanceIndex [[instance_id]]) +{ + main0_out out = {}; + float2 _59 = float2(UniformBuffer.Viewport); + float2 _60 = _59 * float2(0.0007812500116415321826934814453125, 0.001388888922519981861114501953125); + float _63 = precise::max(_60.x, _60.y); + uint _65 = uint(gl_InstanceIndex == 0u); + float2 _81; + float2 _82; + if (_65 != 0u) + { + float2 _70 = float2(10.0) * _63; + _81 = _70 + float2(50.0 * _63); + _82 = _70; + } + else + { + float2 _74 = _59 * 0.5; + float2 _78 = select(float2(2.0, 8.0), float2(8.0, 2.0), bool2(gl_InstanceIndex == 1u)) * _63; + _81 = _74 + _78; + _82 = _74 - _78; + } + out.gl_Position = float4(((mix(_82, _81, _48[gl_VertexIndex]) / _59) * 2.0) - float2(1.0), 0.0, 1.0); + out.out_var_TEXCOORD0 = float2(_48[gl_VertexIndex].x, 1.0 - _48[gl_VertexIndex].y); + out.out_var_TEXCOORD1 = _65; + return out; +} + diff --git a/shaders/bin/hud.vert.spv b/shaders/bin/hud.vert.spv new file mode 100644 index 00000000..e267aff1 Binary files /dev/null and b/shaders/bin/hud.vert.spv differ diff --git a/shaders/bin/opaque.frag.json b/shaders/bin/opaque.frag.json index 334605ca..e790c135 100644 --- a/shaders/bin/opaque.frag.json +++ b/shaders/bin/opaque.frag.json @@ -1 +1 @@ -{ "samplers": 1, "storage_textures": 0, "storage_buffers": 1, "uniform_buffers": 1, "inputs": [{ "name": "in.var.TEXCOORD0", "type": "float4", "location": 0 }, { "name": "in.var.TEXCOORD1", "type": "float3", "location": 1 }, { "name": "in.var.TEXCOORD2", "type": "float3", "location": 2 }, { "name": "in.var.TEXCOORD3", "type": "uint", "location": 3 }], "outputs": [{ "name": "out.var.SV_Target0", "type": "float4", "location": 0 }, { "name": "out.var.SV_Target1", "type": "float4", "location": 1 }, { "name": "out.var.SV_Target2", "type": "float4", "location": 2 }, { "name": "out.var.SV_Target3", "type": "uint", "location": 3 }] } +{ "samplers": 1, "storage_textures": 0, "storage_buffers": 2, "uniform_buffers": 3, "inputs": [{ "name": "in.var.TEXCOORD0", "type": "float4", "location": 0 }, { "name": "in.var.TEXCOORD1", "type": "float2", "location": 1 }, { "name": "in.var.TEXCOORD2", "type": "uint", "location": 2 }, { "name": "in.var.TEXCOORD3", "type": "float", "location": 3 }], "outputs": [{ "name": "out.var.SV_Target0", "type": "float4", "location": 0 }, { "name": "out.var.SV_Target1", "type": "float4", "location": 1 }] } diff --git a/shaders/bin/opaque.frag.msl b/shaders/bin/opaque.frag.msl index 2cc09c33..1e5a6b16 100644 --- a/shaders/bin/opaque.frag.msl +++ b/shaders/bin/opaque.frag.msl @@ -1,14 +1,70 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct Light { + packed_int3 Position; uint Color; - int X; - int Y; - int Z; +}; + +struct Block +{ + Light _Light; + uint IsOpaque; + uint IsSolid; + uint IsSprite; + uint UseAO; + uint UseSunNormal; + float SunIntensity; + uint Indices[6]; +}; + +struct type_StructuredBuffer_Block +{ + Block _m0[1]; }; struct type_StructuredBuffer_Light @@ -21,67 +77,99 @@ struct type_UniformBuffer int LightCount; }; +struct type_UniformBuffer_1 +{ + float3 PlayerPosition; +}; + +struct type_UniformBuffer_2 +{ + float4 Sun; + float4 SkyTop; + float4 SkyHorizon; + float4 Ambient; +}; + +constant spvUnsafeArray _90 = spvUnsafeArray({ float3(0.0, 0.0, 1.0), float3(0.0, 0.0, -1.0), float3(1.0, 0.0, 0.0), float3(-1.0, 0.0, 0.0), float3(0.0, 1.0, 0.0), float3(0.0, -1.0, 0.0) }); + struct main0_out { float4 out_var_SV_Target0 [[color(0)]]; float4 out_var_SV_Target1 [[color(1)]]; - float4 out_var_SV_Target2 [[color(2)]]; - uint out_var_SV_Target3 [[color(3)]]; }; struct main0_in { float4 in_var_TEXCOORD0 [[user(locn0)]]; - float3 in_var_TEXCOORD1 [[user(locn1), flat]]; - float3 in_var_TEXCOORD2 [[user(locn2)]]; - uint in_var_TEXCOORD3 [[user(locn3)]]; + float2 in_var_TEXCOORD1 [[user(locn1)]]; + uint in_var_TEXCOORD2 [[user(locn2)]]; + float in_var_TEXCOORD3 [[user(locn3)]]; }; -fragment main0_out main0(main0_in in [[stage_in]], constant type_UniformBuffer& UniformBuffer [[buffer(0)]], const device type_StructuredBuffer_Light& lightBuffer [[buffer(1)]], texture2d_array atlasTexture [[texture(0)]], sampler atlasSampler [[sampler(0)]]) +fragment main0_out main0(main0_in in [[stage_in]], constant type_UniformBuffer& UniformBuffer [[buffer(0)]], constant type_UniformBuffer_1& UniformBuffer_1 [[buffer(1)]], constant type_UniformBuffer_2& UniformBuffer_2 [[buffer(2)]], const device type_StructuredBuffer_Block& blockBuffer [[buffer(3)]], const device type_StructuredBuffer_Light& lightBuffer [[buffer(4)]], texture2d_array atlasTexture [[texture(0)]], sampler atlasSampler [[sampler(0)]]) { main0_out out = {}; - float4 _71 = atlasTexture.sample(atlasSampler, in.in_var_TEXCOORD2.xy, uint(rint(in.in_var_TEXCOORD2.z))); - if (_71.w < 0.001000000047497451305389404296875) + uint _105 = (in.in_var_TEXCOORD2 >> 3u) & 31u; + uint _112 = in.in_var_TEXCOORD2 & 7u; + float3 _118 = float3(in.in_var_TEXCOORD1, float(blockBuffer._m0[_105].Indices[_112])); + float4 _122 = atlasTexture.sample(atlasSampler, _118.xy, uint(rint(_118.z))); + if (_122.w < 0.001000000047497451305389404296875) { discard_fragment(); } - uint _81 = uint(UniformBuffer.LightCount); - float3 _83; - _83 = float3(0.0); - float3 _84; - for (uint _86 = 0u; _86 < _81; _83 = _84, _86++) + uint _132 = uint(UniformBuffer.LightCount); + float3 _135; + _135 = float3(0.0); + float3 _136; + for (uint _138 = 0u; _138 < _132; _135 = _136, _138++) { - float _99 = float((lightBuffer._m0[_86].Color & 4278190080u) >> 24u); - float3 _106 = (float3(float(lightBuffer._m0[_86].X), float(lightBuffer._m0[_86].Y), float(lightBuffer._m0[_86].Z)) + float3(0.5, 0.75, 0.5)) - in.in_var_TEXCOORD0.xyz; - float _107 = length(_106); - bool _112; - if ((isunordered(_107, _99) || _107 < _99)) + float _149 = float((lightBuffer._m0[_138].Color & 4278190080u) >> 24u); + float3 _152 = (float3(int3(lightBuffer._m0[_138].Position)) + float3(0.5, 0.75, 0.5)) - in.in_var_TEXCOORD0.xyz; + float _153 = length(_152); + if (_153 >= _149) { - _112 = _99 <= 0.0; + _136 = _135; + continue; } - else + float _164; + if (blockBuffer._m0[_105].IsSprite == 0u) { - _112 = true; + _164 = fast::clamp(dot(_90[_112], _152 / float3(_153)), 0.0, 1.0); } - if (_112) + else { - _84 = _83; - continue; + _164 = 1.0; } - float _118 = fast::clamp(dot(in.in_var_TEXCOORD1, _106 / float3(_107)), 0.0, 1.0); - if (_118 <= 0.0) + if (_164 <= 0.0) { - _84 = _83; + _136 = _135; continue; } - float _124 = fast::clamp(1.0 - (_107 / _99), 0.0, 1.0); - _84 = _83 + ((float3(float(lightBuffer._m0[_86].Color & 255u) * 0.0039215688593685626983642578125, float((lightBuffer._m0[_86].Color & 65280u) >> 8u) * 0.0039215688593685626983642578125, float((lightBuffer._m0[_86].Color & 16711680u) >> 16u) * 0.0039215688593685626983642578125) * _118) * (_124 * _124)); + _136 = _135 + ((float3(float(lightBuffer._m0[_138].Color & 255u) * 0.0039215688593685626983642578125, float((lightBuffer._m0[_138].Color & 65280u) >> 8u) * 0.0039215688593685626983642578125, float((lightBuffer._m0[_138].Color & 16711680u) >> 16u) * 0.0039215688593685626983642578125) * _164) * (1.0 - smoothstep(0.0, 1.0, fast::clamp(_153 / _149, 0.0, 1.0)))); } - float3 _141 = _83 * 2.0; - out.out_var_SV_Target0 = _71; + float _209; + do + { + if (UniformBuffer_2.Sun.w <= 0.0) + { + _209 = 0.0; + break; + } + float _206; + if (blockBuffer._m0[_105].UseSunNormal != 0u) + { + _206 = fast::clamp(-dot(_90[_112], UniformBuffer_2.Sun.xyz), 0.0, 1.0); + } + else + { + _206 = 1.0; + } + _209 = (blockBuffer._m0[_105].SunIntensity * UniformBuffer_2.Sun.w) * _206; + break; + } while(false); + float3 _212 = in.in_var_TEXCOORD0.xyz - UniformBuffer_1.PlayerPosition; + out.out_var_SV_Target0 = float4(mix(_122.xyz * ((_135 + (UniformBuffer_2.Ambient.xyz * in.in_var_TEXCOORD3)) + float3(_209)), mix(UniformBuffer_2.SkyHorizon.xyz, UniformBuffer_2.SkyTop.xyz, float3((precise::atan2(_212.y, length(_212.xz)) + 1.57079637050628662109375) * 0.3183098733425140380859375)), float3(precise::min(powr(distance(in.in_var_TEXCOORD0.xz, UniformBuffer_1.PlayerPosition.xz) * 0.0040000001899898052215576171875, 2.5), 1.0))), 1.0); out.out_var_SV_Target1 = in.in_var_TEXCOORD0; - out.out_var_SV_Target2 = float4(_141.x, _141.y, _141.z, float4(0.0).w); - out.out_var_SV_Target3 = (in.in_var_TEXCOORD3 & 1u) | (in.in_var_TEXCOORD3 & 30u); return out; } diff --git a/shaders/bin/opaque.frag.spv b/shaders/bin/opaque.frag.spv index cd6738c4..6a250b73 100644 Binary files a/shaders/bin/opaque.frag.spv and b/shaders/bin/opaque.frag.spv differ diff --git a/shaders/bin/opaque.vert.json b/shaders/bin/opaque.vert.json index 9e57c165..a692367b 100644 --- a/shaders/bin/opaque.vert.json +++ b/shaders/bin/opaque.vert.json @@ -1 +1 @@ -{ "samplers": 0, "storage_textures": 0, "storage_buffers": 0, "uniform_buffers": 3, "inputs": [{ "name": "in.var.TEXCOORD0", "type": "uint", "location": 0 }], "outputs": [{ "name": "out.var.TEXCOORD0", "type": "float4", "location": 0 }, { "name": "out.var.TEXCOORD1", "type": "float3", "location": 1 }, { "name": "out.var.TEXCOORD2", "type": "float3", "location": 2 }, { "name": "out.var.TEXCOORD3", "type": "uint", "location": 3 }] } +{ "samplers": 0, "storage_textures": 0, "storage_buffers": 0, "uniform_buffers": 3, "inputs": [{ "name": "in.var.TEXCOORD0", "type": "uint", "location": 0 }], "outputs": [{ "name": "out.var.TEXCOORD0", "type": "float4", "location": 0 }, { "name": "out.var.TEXCOORD1", "type": "float2", "location": 1 }, { "name": "out.var.TEXCOORD2", "type": "uint", "location": 2 }, { "name": "out.var.TEXCOORD3", "type": "float", "location": 3 }] } diff --git a/shaders/bin/opaque.vert.msl b/shaders/bin/opaque.vert.msl index f6a85953..e93f78d7 100644 --- a/shaders/bin/opaque.vert.msl +++ b/shaders/bin/opaque.vert.msl @@ -59,16 +59,16 @@ struct type_UniformBuffer_2 int2 ChunkPosition; }; -constant float4 _61 = {}; +constant float4 _57 = {}; -constant spvUnsafeArray _60 = spvUnsafeArray({ float3(0.0, 0.0, 1.0), float3(0.0, 0.0, -1.0), float3(1.0, 0.0, 0.0), float3(-1.0, 0.0, 0.0), float3(0.0, 1.0, 0.0), float3(0.0, -1.0, 0.0), float3(0.0, 1.0, 0.0), float3(0.0, 1.0, 0.0), float3(0.0, 1.0, 0.0), float3(0.0, 1.0, 0.0) }); +constant spvUnsafeArray _56 = spvUnsafeArray({ 0.4000000059604644775390625, 0.60000002384185791015625, 0.800000011920928955078125, 1.0 }); struct main0_out { float4 out_var_TEXCOORD0 [[user(locn0)]]; - float3 out_var_TEXCOORD1 [[user(locn1)]]; - float3 out_var_TEXCOORD2 [[user(locn2)]]; - uint out_var_TEXCOORD3 [[user(locn3)]]; + float2 out_var_TEXCOORD1 [[user(locn1)]]; + uint out_var_TEXCOORD2 [[user(locn2)]]; + float out_var_TEXCOORD3 [[user(locn3)]]; float4 gl_Position [[position]]; }; @@ -80,15 +80,15 @@ struct main0_in vertex main0_out main0(main0_in in [[stage_in]], constant type_UniformBuffer& UniformBuffer [[buffer(0)]], constant type_UniformBuffer_1& UniformBuffer_1 [[buffer(1)]], constant type_UniformBuffer_2& UniformBuffer_2 [[buffer(2)]]) { main0_out out = {}; - float3 _83 = float3(float((in.in_var_TEXCOORD0 >> 6u) & 31u), float((in.in_var_TEXCOORD0 >> 11u) & 255u), float((in.in_var_TEXCOORD0 >> 19u) & 31u)) + float3(int3(float3(float(UniformBuffer_2.ChunkPosition.x), 0.0, float(UniformBuffer_2.ChunkPosition.y)))); - float4 _84 = float4(_83.x, _83.y, _83.z, _61.w); - float4 _96 = UniformBuffer_1.View * float4(_83, 1.0); - _84.w = _96.z; - out.gl_Position = UniformBuffer.Proj * _96; - out.out_var_TEXCOORD0 = _84; - out.out_var_TEXCOORD1 = _60[((in.in_var_TEXCOORD0 >> 1u) & 15u) - 1u]; - out.out_var_TEXCOORD2 = float3(float((in.in_var_TEXCOORD0 >> 24u) & 1u), float((in.in_var_TEXCOORD0 >> 25u) & 1u), float((in.in_var_TEXCOORD0 >> 26u) & 63u)); - out.out_var_TEXCOORD3 = in.in_var_TEXCOORD0; + float3 _76 = float3(float((in.in_var_TEXCOORD0 >> 10u) & 31u), float((in.in_var_TEXCOORD0 >> 15u) & 255u), float((in.in_var_TEXCOORD0 >> 23u) & 31u)) + float3(int3(UniformBuffer_2.ChunkPosition.x, 0, UniformBuffer_2.ChunkPosition.y)); + float4 _77 = float4(_76.x, _76.y, _76.z, _57.w); + float4 _84 = UniformBuffer_1.View * float4(_76, 1.0); + _77.w = _84.z; + out.gl_Position = UniformBuffer.Proj * _84; + out.out_var_TEXCOORD0 = _77; + out.out_var_TEXCOORD1 = float2(float((in.in_var_TEXCOORD0 >> 28u) & 1u), float((in.in_var_TEXCOORD0 >> 29u) & 1u)); + out.out_var_TEXCOORD2 = in.in_var_TEXCOORD0; + out.out_var_TEXCOORD3 = _56[(in.in_var_TEXCOORD0 >> 8u) & 3u]; return out; } diff --git a/shaders/bin/opaque.vert.spv b/shaders/bin/opaque.vert.spv index d7dd1131..b08194c5 100644 Binary files a/shaders/bin/opaque.vert.spv and b/shaders/bin/opaque.vert.spv differ diff --git a/shaders/bin/raycast.vert.msl b/shaders/bin/raycast.vert.msl index a39bc63c..b21010bd 100644 --- a/shaders/bin/raycast.vert.msl +++ b/shaders/bin/raycast.vert.msl @@ -65,9 +65,7 @@ struct main0_out vertex main0_out main0(constant type_UniformBuffer& UniformBuffer [[buffer(0)]], constant type_UniformBuffer_1& UniformBuffer_1 [[buffer(1)]], uint gl_VertexIndex [[vertex_id]]) { main0_out out = {}; - float4 _73 = UniformBuffer.Transform * float4(_54[_55[gl_VertexIndex]] + (float3(UniformBuffer_1.BlockPosition) + float3(0.5)), 1.0); - _73.z = 0.100000001490116119384765625; - out.gl_Position = _73; + out.gl_Position = UniformBuffer.Transform * float4((_54[_55[gl_VertexIndex]] * 1.019999980926513671875) + (float3(UniformBuffer_1.BlockPosition) + float3(0.5)), 1.0); return out; } diff --git a/shaders/bin/raycast.vert.spv b/shaders/bin/raycast.vert.spv index 43cafc9e..82f0b535 100644 Binary files a/shaders/bin/raycast.vert.spv and b/shaders/bin/raycast.vert.spv differ diff --git a/shaders/bin/shadow.frag.json b/shaders/bin/shadow.frag.json deleted file mode 100644 index 5da52262..00000000 --- a/shaders/bin/shadow.frag.json +++ /dev/null @@ -1 +0,0 @@ -{ "samplers": 0, "storage_textures": 0, "storage_buffers": 0, "uniform_buffers": 0, "inputs": [], "outputs": [] } diff --git a/shaders/bin/shadow.frag.msl b/shaders/bin/shadow.frag.msl deleted file mode 100644 index 92ac1d9f..00000000 --- a/shaders/bin/shadow.frag.msl +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include - -using namespace metal; - -fragment void main0() -{ -} - diff --git a/shaders/bin/shadow.frag.spv b/shaders/bin/shadow.frag.spv deleted file mode 100644 index b893138e..00000000 Binary files a/shaders/bin/shadow.frag.spv and /dev/null differ diff --git a/shaders/bin/shadow.vert.json b/shaders/bin/shadow.vert.json deleted file mode 100644 index e6fb9331..00000000 --- a/shaders/bin/shadow.vert.json +++ /dev/null @@ -1 +0,0 @@ -{ "samplers": 0, "storage_textures": 0, "storage_buffers": 0, "uniform_buffers": 3, "inputs": [{ "name": "in.var.TEXCOORD0", "type": "uint", "location": 0 }], "outputs": [] } diff --git a/shaders/bin/shadow.vert.msl b/shaders/bin/shadow.vert.msl deleted file mode 100644 index b3abae06..00000000 --- a/shaders/bin/shadow.vert.msl +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include - -using namespace metal; - -struct type_UniformBuffer -{ - float4x4 Proj; -}; - -struct type_UniformBuffer_1 -{ - float4x4 View; -}; - -struct type_UniformBuffer_2 -{ - int2 ChunkPosition; -}; - -struct main0_out -{ - float4 gl_Position [[position]]; - float gl_ClipDistance [[clip_distance]] [1]; - float gl_ClipDistance_0 [[user(clip0)]]; -}; - -struct main0_in -{ - uint in_var_TEXCOORD0 [[attribute(0)]]; -}; - -vertex main0_out main0(main0_in in [[stage_in]], constant type_UniformBuffer& UniformBuffer [[buffer(0)]], constant type_UniformBuffer_1& UniformBuffer_1 [[buffer(1)]], constant type_UniformBuffer_2& UniformBuffer_2 [[buffer(2)]]) -{ - main0_out out = {}; - out.gl_Position = UniformBuffer.Proj * (UniformBuffer_1.View * float4(float3(float((in.in_var_TEXCOORD0 >> 6u) & 31u), float((in.in_var_TEXCOORD0 >> 11u) & 255u), float((in.in_var_TEXCOORD0 >> 19u) & 31u)) + float3(int3(float3(float(UniformBuffer_2.ChunkPosition.x), 0.0, float(UniformBuffer_2.ChunkPosition.y)))), 1.0)); - out.gl_ClipDistance[0u] = (((in.in_var_TEXCOORD0 >> 5u) & 1u) != 0u) ? 1.0 : (-1.0); - out.gl_ClipDistance_0 = out.gl_ClipDistance[0]; - return out; -} - diff --git a/shaders/bin/shadow.vert.spv b/shaders/bin/shadow.vert.spv deleted file mode 100644 index 6cbc88c0..00000000 Binary files a/shaders/bin/shadow.vert.spv and /dev/null differ diff --git a/shaders/bin/sky.frag.json b/shaders/bin/sky.frag.json index 538fe1a6..67f0a885 100644 --- a/shaders/bin/sky.frag.json +++ b/shaders/bin/sky.frag.json @@ -1 +1 @@ -{ "samplers": 0, "storage_textures": 0, "storage_buffers": 0, "uniform_buffers": 0, "inputs": [{ "name": "in.var.TEXCOORD0", "type": "float3", "location": 0 }], "outputs": [{ "name": "out.var.SV_Target0", "type": "float4", "location": 0 }, { "name": "out.var.SV_Target3", "type": "uint", "location": 3 }] } +{ "samplers": 0, "storage_textures": 0, "storage_buffers": 0, "uniform_buffers": 1, "inputs": [{ "name": "in.var.TEXCOORD0", "type": "float3", "location": 0 }], "outputs": [{ "name": "out.var.SV_Target0", "type": "float4", "location": 0 }, { "name": "out.var.SV_Target1", "type": "float4", "location": 1 }] } diff --git a/shaders/bin/sky.frag.msl b/shaders/bin/sky.frag.msl index 9dc88e31..701aa4ee 100644 --- a/shaders/bin/sky.frag.msl +++ b/shaders/bin/sky.frag.msl @@ -3,10 +3,18 @@ using namespace metal; +struct type_UniformBuffer +{ + float4 Sun; + float4 SkyTop; + float4 SkyHorizon; + float4 Ambient; +}; + struct main0_out { float4 out_var_SV_Target0 [[color(0)]]; - uint out_var_SV_Target3 [[color(3)]]; + float4 out_var_SV_Target1 [[color(1)]]; }; struct main0_in @@ -14,11 +22,11 @@ struct main0_in float3 in_var_TEXCOORD0 [[user(locn0)]]; }; -fragment main0_out main0(main0_in in [[stage_in]]) +fragment main0_out main0(main0_in in [[stage_in]], constant type_UniformBuffer& UniformBuffer [[buffer(0)]]) { main0_out out = {}; - out.out_var_SV_Target0 = float4(mix(float3(0.2199999988079071044921875, 0.3490000069141387939453125, 0.70200002193450927734375), float3(0.21199999749660491943359375, 0.7730000019073486328125, 0.9570000171661376953125), float3((precise::atan2(in.in_var_TEXCOORD0.y, length(float2(in.in_var_TEXCOORD0.x, in.in_var_TEXCOORD0.z))) + 1.57079637050628662109375) * 0.3183098733425140380859375)), 1.0); - out.out_var_SV_Target3 = 0u; + out.out_var_SV_Target0 = float4(mix(UniformBuffer.SkyHorizon.xyz, UniformBuffer.SkyTop.xyz, float3((precise::atan2(in.in_var_TEXCOORD0.y, length(in.in_var_TEXCOORD0.xz)) + 1.57079637050628662109375) * 0.3183098733425140380859375)), 1.0); + out.out_var_SV_Target1 = float4(0.0); return out; } diff --git a/shaders/bin/sky.frag.spv b/shaders/bin/sky.frag.spv index db6e0840..8bf16fd2 100644 Binary files a/shaders/bin/sky.frag.spv and b/shaders/bin/sky.frag.spv differ diff --git a/shaders/bin/sky.vert.spv b/shaders/bin/sky.vert.spv index 171aca98..27904abc 100644 Binary files a/shaders/bin/sky.vert.spv and b/shaders/bin/sky.vert.spv differ diff --git a/shaders/bin/ssao.comp.json b/shaders/bin/ssao.comp.json deleted file mode 100644 index 3831f975..00000000 --- a/shaders/bin/ssao.comp.json +++ /dev/null @@ -1 +0,0 @@ -{ "samplers": 0, "readonly_storage_textures": 2, "readonly_storage_buffers": 0, "readwrite_storage_textures": 1, "readwrite_storage_buffers": 0, "uniform_buffers": 0, "threadcount_x": 8, "threadcount_y": 8, "threadcount_z": 1 } diff --git a/shaders/bin/ssao.comp.msl b/shaders/bin/ssao.comp.msl deleted file mode 100644 index 8c57461f..00000000 --- a/shaders/bin/ssao.comp.msl +++ /dev/null @@ -1,156 +0,0 @@ -#pragma clang diagnostic ignored "-Wmissing-prototypes" -#pragma clang diagnostic ignored "-Wmissing-braces" - -#include -#include - -using namespace metal; - -template -struct spvUnsafeArray -{ - T elements[Num ? Num : 1]; - - thread T& operator [] (size_t pos) thread - { - return elements[pos]; - } - constexpr const thread T& operator [] (size_t pos) const thread - { - return elements[pos]; - } - - device T& operator [] (size_t pos) device - { - return elements[pos]; - } - constexpr const device T& operator [] (size_t pos) const device - { - return elements[pos]; - } - - constexpr const constant T& operator [] (size_t pos) const constant - { - return elements[pos]; - } - - threadgroup T& operator [] (size_t pos) threadgroup - { - return elements[pos]; - } - constexpr const threadgroup T& operator [] (size_t pos) const threadgroup - { - return elements[pos]; - } -}; - -kernel void main0(texture2d voxelTexture [[texture(0)]], texture2d positionTexture [[texture(1)]], texture2d ssaoTexture [[texture(2)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) -{ - do - { - uint2 _62 = uint2(ssaoTexture.get_width(), ssaoTexture.get_height()); - uint _63 = _62.x; - uint _64 = _62.y; - bool _73; - if (gl_GlobalInvocationID.x < _63) - { - _73 = gl_GlobalInvocationID.y >= _64; - } - else - { - _73 = true; - } - if (_73) - { - break; - } - ssaoTexture.write(float4(0.0), uint2(gl_GlobalInvocationID.xy)); - uint4 _79 = voxelTexture.read(uint2(gl_GlobalInvocationID.xy), 0u); - uint _80 = _79.x; - if ((_80 & 1u) == 0u) - { - break; - } - float2 _85 = float2(gl_GlobalInvocationID.xy); - float2 _88 = float2(float(_63), float(_64)); - float2 _89 = _85 / _88; - uint _92 = ((_80 >> 1u) & 15u) - 1u; - float4 _94 = positionTexture.read(uint2(gl_GlobalInvocationID.xy), 0u); - float _97 = precise::max(abs(_94.w), 1.0); - float2 _100 = (float2(75.0) / _88) / float2(_97); - float _102; - _102 = 0.0; - spvUnsafeArray _57; - float _103; - for (int _105 = -2; _105 <= 2; _102 = _103, _105++) - { - _103 = _102; - float _111; - for (int _113 = -2; _113 <= 2; _103 = _111, _113++) - { - float2 _122 = _89 + (float2(float(_105), float(_113)) * _100); - uint2 _136 = uint2((_122 + (((fract(float2(sin(dot(_122, float2(127.09999847412109375, 311.70001220703125))) * 43758.546875, sin(dot(_122, float2(269.5, 183.3000030517578125))) * 43758.546875)) * 2.0) - float2(1.0)) * _100)) * _88); - bool _141; - if (_105 != 0) - { - _141 = _113 == 0; - } - else - { - _141 = true; - } - bool _149; - if (!_141) - { - _149 = _136.x >= _63; - } - else - { - _149 = true; - } - bool _155; - if (!_149) - { - _155 = _136.y >= _64; - } - else - { - _155 = true; - } - if (_155) - { - _111 = _103; - continue; - } - bool _193; - do - { - if ((voxelTexture.read(uint2(_136), 0u).x & 1u) == 0u) - { - _193 = false; - break; - } - float4 _171 = positionTexture.read(uint2(_136), 0u); - float _172 = _171.z; - float _173 = _94.z; - _57[0] = _172 - _173; - _57[1] = _173 - _172; - float _178 = _171.x; - float _179 = _94.x; - _57[2] = _178 - _179; - _57[3] = _179 - _178; - float _184 = _171.y; - float _185 = _94.y; - _57[4] = _184 - _185; - _57[5] = _185 - _184; - _193 = _57[_92] > 0.0500000007450580596923828125; - break; - } while(false); - _111 = _103 + (float(_193) / precise::max(distance(_85, float2(_136)), 1.0)); - } - } - ssaoTexture.write(float4(_102 / _97), uint2(gl_GlobalInvocationID.xy)); - break; - } while(false); -} - diff --git a/shaders/bin/ssao.comp.spv b/shaders/bin/ssao.comp.spv deleted file mode 100644 index c02ba665..00000000 Binary files a/shaders/bin/ssao.comp.spv and /dev/null differ diff --git a/shaders/bin/transparent.frag.json b/shaders/bin/transparent.frag.json index 70f10ee9..40ebfefa 100644 --- a/shaders/bin/transparent.frag.json +++ b/shaders/bin/transparent.frag.json @@ -1 +1 @@ -{ "samplers": 3, "storage_textures": 0, "storage_buffers": 1, "uniform_buffers": 3, "inputs": [{ "name": "in.var.TEXCOORD0", "type": "float4", "location": 0 }, { "name": "in.var.TEXCOORD1", "type": "float3", "location": 1 }, { "name": "in.var.TEXCOORD2", "type": "float3", "location": 2 }, { "name": "in.var.TEXCOORD3", "type": "uint", "location": 3 }, { "name": "in.var.TEXCOORD4", "type": "float2", "location": 4 }], "outputs": [{ "name": "out.var.SV_Target0", "type": "float4", "location": 0 }] } +{ "samplers": 2, "storage_textures": 0, "storage_buffers": 2, "uniform_buffers": 3, "inputs": [{ "name": "in.var.TEXCOORD0", "type": "float4", "location": 0 }, { "name": "in.var.TEXCOORD1", "type": "float2", "location": 1 }, { "name": "in.var.TEXCOORD2", "type": "uint", "location": 2 }, { "name": "in.var.TEXCOORD3", "type": "float2", "location": 3 }], "outputs": [{ "name": "out.var.SV_Target0", "type": "float4", "location": 0 }] } diff --git a/shaders/bin/transparent.frag.msl b/shaders/bin/transparent.frag.msl index 773a2de2..67e29e84 100644 --- a/shaders/bin/transparent.frag.msl +++ b/shaders/bin/transparent.frag.msl @@ -1,14 +1,70 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct Light { + packed_int3 Position; uint Color; - int X; - int Y; - int Z; +}; + +struct Block +{ + Light _Light; + uint IsOpaque; + uint IsSolid; + uint IsSprite; + uint UseAO; + uint UseSunNormal; + float SunIntensity; + uint Indices[6]; +}; + +struct type_StructuredBuffer_Block +{ + Block _m0[1]; }; struct type_StructuredBuffer_Light @@ -23,14 +79,19 @@ struct type_UniformBuffer struct type_UniformBuffer_1 { - float4x4 ShadowTransform; + float3 PlayerPosition; }; struct type_UniformBuffer_2 { - float3 PlayerPosition; + float4 Sun; + float4 SkyTop; + float4 SkyHorizon; + float4 Ambient; }; +constant spvUnsafeArray _92 = spvUnsafeArray({ float3(0.0, 0.0, 1.0), float3(0.0, 0.0, -1.0), float3(1.0, 0.0, 0.0), float3(-1.0, 0.0, 0.0), float3(0.0, 1.0, 0.0), float3(0.0, -1.0, 0.0) }); + struct main0_out { float4 out_var_SV_Target0 [[color(0)]]; @@ -39,129 +100,80 @@ struct main0_out struct main0_in { float4 in_var_TEXCOORD0 [[user(locn0)]]; - float3 in_var_TEXCOORD1 [[user(locn1), flat]]; - float3 in_var_TEXCOORD2 [[user(locn2)]]; - uint in_var_TEXCOORD3 [[user(locn3)]]; - float2 in_var_TEXCOORD4 [[user(locn4)]]; + float2 in_var_TEXCOORD1 [[user(locn1)]]; + uint in_var_TEXCOORD2 [[user(locn2)]]; + float2 in_var_TEXCOORD3 [[user(locn3), center_no_perspective]]; }; -fragment main0_out main0(main0_in in [[stage_in]], constant type_UniformBuffer& UniformBuffer [[buffer(0)]], constant type_UniformBuffer_1& UniformBuffer_1 [[buffer(1)]], constant type_UniformBuffer_2& UniformBuffer_2 [[buffer(2)]], const device type_StructuredBuffer_Light& lightBuffer [[buffer(3)]], texture2d_array atlasTexture [[texture(0)]], texture2d shadowTexture [[texture(1)]], texture2d positionTexture [[texture(2)]], sampler atlasSampler [[sampler(0)]], sampler shadowSampler [[sampler(1)]], sampler positionSampler [[sampler(2)]]) +fragment main0_out main0(main0_in in [[stage_in]], constant type_UniformBuffer& UniformBuffer [[buffer(0)]], constant type_UniformBuffer_1& UniformBuffer_1 [[buffer(1)]], constant type_UniformBuffer_2& UniformBuffer_2 [[buffer(2)]], const device type_StructuredBuffer_Block& blockBuffer [[buffer(3)]], const device type_StructuredBuffer_Light& lightBuffer [[buffer(4)]], texture2d_array atlasTexture [[texture(0)]], texture2d positionTexture [[texture(1)]], sampler atlasSampler [[sampler(0)]], sampler positionSampler [[sampler(1)]]) { main0_out out = {}; - float4 _108 = atlasTexture.sample(atlasSampler, in.in_var_TEXCOORD2.xy, uint(rint(in.in_var_TEXCOORD2.z))); - float _110 = _108.w; - uint _113 = uint(UniformBuffer.LightCount); - float3 _115; - _115 = float3(0.0); - float3 _116; - for (uint _118 = 0u; _118 < _113; _115 = _116, _118++) + uint _109 = (in.in_var_TEXCOORD2 >> 3u) & 31u; + uint _116 = in.in_var_TEXCOORD2 & 7u; + float3 _124 = float3(in.in_var_TEXCOORD1, float(blockBuffer._m0[_109].Indices[_116])); + float4 _128 = atlasTexture.sample(atlasSampler, _124.xy, uint(rint(_124.z))); + float _130 = _128.w; + uint _133 = uint(UniformBuffer.LightCount); + float3 _136; + _136 = float3(0.0); + float3 _137; + for (uint _139 = 0u; _139 < _133; _136 = _137, _139++) { - float _131 = float((lightBuffer._m0[_118].Color & 4278190080u) >> 24u); - float3 _138 = (float3(float(lightBuffer._m0[_118].X), float(lightBuffer._m0[_118].Y), float(lightBuffer._m0[_118].Z)) + float3(0.5, 0.75, 0.5)) - in.in_var_TEXCOORD0.xyz; - float _139 = length(_138); - bool _144; - if ((isunordered(_139, _131) || _139 < _131)) + float _150 = float((lightBuffer._m0[_139].Color & 4278190080u) >> 24u); + float3 _153 = (float3(int3(lightBuffer._m0[_139].Position)) + float3(0.5, 0.75, 0.5)) - in.in_var_TEXCOORD0.xyz; + float _154 = length(_153); + if (_154 >= _150) { - _144 = _131 <= 0.0; + _137 = _136; + continue; } - else + float _165; + if (blockBuffer._m0[_109].IsSprite == 0u) { - _144 = true; + _165 = fast::clamp(dot(_92[_116], _153 / float3(_154)), 0.0, 1.0); } - if (_144) + else { - _116 = _115; - continue; + _165 = 1.0; } - float _150 = fast::clamp(dot(in.in_var_TEXCOORD1, _138 / float3(_139)), 0.0, 1.0); - if (_150 <= 0.0) + if (_165 <= 0.0) { - _116 = _115; + _137 = _136; continue; } - float _156 = fast::clamp(1.0 - (_139 / _131), 0.0, 1.0); - _116 = _115 + ((float3(float(lightBuffer._m0[_118].Color & 255u) * 0.0039215688593685626983642578125, float((lightBuffer._m0[_118].Color & 65280u) >> 8u) * 0.0039215688593685626983642578125, float((lightBuffer._m0[_118].Color & 16711680u) >> 16u) * 0.0039215688593685626983642578125) * _150) * (_156 * _156)); + _137 = _136 + ((float3(float(lightBuffer._m0[_139].Color & 255u) * 0.0039215688593685626983642578125, float((lightBuffer._m0[_139].Color & 65280u) >> 8u) * 0.0039215688593685626983642578125, float((lightBuffer._m0[_139].Color & 16711680u) >> 16u) * 0.0039215688593685626983642578125) * _165) * (1.0 - smoothstep(0.0, 1.0, fast::clamp(_154 / _150, 0.0, 1.0)))); } - float _235; + float _210; do { - float4 _184 = UniformBuffer_1.ShadowTransform * float4(in.in_var_TEXCOORD0.xyz, 1.0); - float3 _188 = _184.xyz / float3(_184.w); - float2 _191 = (_188.xy * 0.5) + float2(0.5); - float _193 = 1.0 - _191.y; - float2 _194 = _191; - _194.y = _193; - float _195 = _191.x; - bool _200; - if ((isunordered(_195, 0.0) || _195 >= 0.0)) - { - _200 = _195 > 1.0; - } - else - { - _200 = true; - } - bool _205; - if (!_200) - { - _205 = _193 < 0.0; - } - else - { - _205 = true; - } - bool _210; - if (!_205) - { - _210 = _193 > 1.0; - } - else + if (UniformBuffer_2.Sun.w <= 0.0) { - _210 = true; - } - if (_210) - { - _235 = 0.4000000059604644775390625; + _210 = 0.0; break; } - float _224; - if ((in.in_var_TEXCOORD3 & 1u) != 0u) + float _207; + if (blockBuffer._m0[_109].UseSunNormal != 0u) { - float _220 = dot(in.in_var_TEXCOORD1, fast::normalize(float4(UniformBuffer_1.ShadowTransform[0][2], UniformBuffer_1.ShadowTransform[1][2], UniformBuffer_1.ShadowTransform[2][2], UniformBuffer_1.ShadowTransform[3][2]).xyz)); - if (_220 > 0.0) - { - _235 = 0.0; - break; - } - _224 = _220; + _207 = fast::clamp(-dot(_92[_116], UniformBuffer_2.Sun.xyz), 0.0, 1.0); } else { - _224 = -0.7070000171661376953125; - } - if (_188.z < (shadowTexture.sample(shadowSampler, _194, level(0.0)).x + 0.001000000047497451305389404296875)) - { - _235 = _224 * (-0.4000000059604644775390625); - break; - } - else - { - _235 = 0.0; - break; + _207 = 1.0; } - break; // unreachable workaround + _210 = (blockBuffer._m0[_109].SunIntensity * UniformBuffer_2.Sun.w) * _207; + break; } while(false); - float3 _239 = in.in_var_TEXCOORD0.xyz - UniformBuffer_2.PlayerPosition; - float _271; - if (((in.in_var_TEXCOORD3 >> 26u) & 63u) == 16u) + float3 _213 = in.in_var_TEXCOORD0.xyz - UniformBuffer_1.PlayerPosition; + float _247; + if (blockBuffer._m0[_109].Indices[_116] == 16u) { - _271 = _110 + ((in.in_var_TEXCOORD0.y - positionTexture.sample(positionSampler, in.in_var_TEXCOORD4).y) * 0.100000001490116119384765625); + _247 = _130 + ((in.in_var_TEXCOORD0.y - positionTexture.sample(positionSampler, in.in_var_TEXCOORD3).y) * 0.100000001490116119384765625); } else { - _271 = _110; + _247 = _130; } - out.out_var_SV_Target0 = float4(mix(_108.xyz * (((_115 * 2.0) + float3(0.5)) + float3(_235)), mix(float3(0.2199999988079071044921875, 0.3490000069141387939453125, 0.70200002193450927734375), float3(0.21199999749660491943359375, 0.7730000019073486328125, 0.9570000171661376953125), float3((precise::atan2(_239.y, length(float2(_239.xz))) + 1.57079637050628662109375) * 0.3183098733425140380859375)), float3(precise::min(powr(distance(in.in_var_TEXCOORD0.xz, UniformBuffer_2.PlayerPosition.xz) * 0.0040000001899898052215576171875, 2.5), 1.0))), _271); + out.out_var_SV_Target0 = float4(mix(_128.xyz * ((_136 + UniformBuffer_2.Ambient.xyz) + float3(_210)), mix(UniformBuffer_2.SkyHorizon.xyz, UniformBuffer_2.SkyTop.xyz, float3((precise::atan2(_213.y, length(_213.xz)) + 1.57079637050628662109375) * 0.3183098733425140380859375)), float3(precise::min(powr(distance(in.in_var_TEXCOORD0.xz, UniformBuffer_1.PlayerPosition.xz) * 0.0040000001899898052215576171875, 2.5), 1.0))), _247); return out; } diff --git a/shaders/bin/transparent.frag.spv b/shaders/bin/transparent.frag.spv index 075d2f7f..336757f5 100644 Binary files a/shaders/bin/transparent.frag.spv and b/shaders/bin/transparent.frag.spv differ diff --git a/shaders/bin/transparent.vert.json b/shaders/bin/transparent.vert.json index 0199b496..d4a413d8 100644 --- a/shaders/bin/transparent.vert.json +++ b/shaders/bin/transparent.vert.json @@ -1 +1 @@ -{ "samplers": 0, "storage_textures": 0, "storage_buffers": 0, "uniform_buffers": 3, "inputs": [{ "name": "in.var.TEXCOORD0", "type": "uint", "location": 0 }], "outputs": [{ "name": "out.var.TEXCOORD0", "type": "float4", "location": 0 }, { "name": "out.var.TEXCOORD1", "type": "float3", "location": 1 }, { "name": "out.var.TEXCOORD2", "type": "float3", "location": 2 }, { "name": "out.var.TEXCOORD3", "type": "uint", "location": 3 }, { "name": "out.var.TEXCOORD4", "type": "float2", "location": 4 }] } +{ "samplers": 0, "storage_textures": 0, "storage_buffers": 0, "uniform_buffers": 3, "inputs": [{ "name": "in.var.TEXCOORD0", "type": "uint", "location": 0 }], "outputs": [{ "name": "out.var.TEXCOORD0", "type": "float4", "location": 0 }, { "name": "out.var.TEXCOORD1", "type": "float2", "location": 1 }, { "name": "out.var.TEXCOORD2", "type": "uint", "location": 2 }, { "name": "out.var.TEXCOORD3", "type": "float2", "location": 3 }] } diff --git a/shaders/bin/transparent.vert.msl b/shaders/bin/transparent.vert.msl index a23f8222..5a3cec1e 100644 --- a/shaders/bin/transparent.vert.msl +++ b/shaders/bin/transparent.vert.msl @@ -1,49 +1,8 @@ -#pragma clang diagnostic ignored "-Wmissing-prototypes" -#pragma clang diagnostic ignored "-Wmissing-braces" - #include #include using namespace metal; -template -struct spvUnsafeArray -{ - T elements[Num ? Num : 1]; - - thread T& operator [] (size_t pos) thread - { - return elements[pos]; - } - constexpr const thread T& operator [] (size_t pos) const thread - { - return elements[pos]; - } - - device T& operator [] (size_t pos) device - { - return elements[pos]; - } - constexpr const device T& operator [] (size_t pos) const device - { - return elements[pos]; - } - - constexpr const constant T& operator [] (size_t pos) const constant - { - return elements[pos]; - } - - threadgroup T& operator [] (size_t pos) threadgroup - { - return elements[pos]; - } - constexpr const threadgroup T& operator [] (size_t pos) const threadgroup - { - return elements[pos]; - } -}; - struct type_UniformBuffer { float4x4 Proj; @@ -59,17 +18,14 @@ struct type_UniformBuffer_2 int2 ChunkPosition; }; -constant float4 _66 = {}; - -constant spvUnsafeArray _65 = spvUnsafeArray({ float3(0.0, 0.0, 1.0), float3(0.0, 0.0, -1.0), float3(1.0, 0.0, 0.0), float3(-1.0, 0.0, 0.0), float3(0.0, 1.0, 0.0), float3(0.0, -1.0, 0.0), float3(0.0, 1.0, 0.0), float3(0.0, 1.0, 0.0), float3(0.0, 1.0, 0.0), float3(0.0, 1.0, 0.0) }); +constant float4 _47 = {}; struct main0_out { float4 out_var_TEXCOORD0 [[user(locn0)]]; - float3 out_var_TEXCOORD1 [[user(locn1)]]; - float3 out_var_TEXCOORD2 [[user(locn2)]]; - uint out_var_TEXCOORD3 [[user(locn3)]]; - float2 out_var_TEXCOORD4 [[user(locn4)]]; + float2 out_var_TEXCOORD1 [[user(locn1)]]; + uint out_var_TEXCOORD2 [[user(locn2)]]; + float2 out_var_TEXCOORD3 [[user(locn3)]]; float4 gl_Position [[position]]; }; @@ -81,19 +37,18 @@ struct main0_in vertex main0_out main0(main0_in in [[stage_in]], constant type_UniformBuffer& UniformBuffer [[buffer(0)]], constant type_UniformBuffer_1& UniformBuffer_1 [[buffer(1)]], constant type_UniformBuffer_2& UniformBuffer_2 [[buffer(2)]]) { main0_out out = {}; - float3 _88 = float3(float((in.in_var_TEXCOORD0 >> 6u) & 31u), float((in.in_var_TEXCOORD0 >> 11u) & 255u), float((in.in_var_TEXCOORD0 >> 19u) & 31u)) + float3(int3(float3(float(UniformBuffer_2.ChunkPosition.x), 0.0, float(UniformBuffer_2.ChunkPosition.y)))); - float4 _89 = float4(_88.x, _88.y, _88.z, _66.w); - float4 _101 = UniformBuffer_1.View * float4(_88, 1.0); - _89.w = _101.z; - float4 _106 = UniformBuffer.Proj * _101; - float2 _122 = ((_106.xy / float2(_106.w)) * 0.5) + float2(0.5); - _122.y = 1.0 - _122.y; - out.gl_Position = _106; - out.out_var_TEXCOORD0 = _89; - out.out_var_TEXCOORD1 = _65[((in.in_var_TEXCOORD0 >> 1u) & 15u) - 1u]; - out.out_var_TEXCOORD2 = float3(float((in.in_var_TEXCOORD0 >> 24u) & 1u), float((in.in_var_TEXCOORD0 >> 25u) & 1u), float((in.in_var_TEXCOORD0 >> 26u) & 63u)); - out.out_var_TEXCOORD3 = in.in_var_TEXCOORD0; - out.out_var_TEXCOORD4 = _122; + float3 _66 = float3(float((in.in_var_TEXCOORD0 >> 10u) & 31u), float((in.in_var_TEXCOORD0 >> 15u) & 255u), float((in.in_var_TEXCOORD0 >> 23u) & 31u)) + float3(int3(UniformBuffer_2.ChunkPosition.x, 0, UniformBuffer_2.ChunkPosition.y)); + float4 _67 = float4(_66.x, _66.y, _66.z, _47.w); + float4 _74 = UniformBuffer_1.View * float4(_66, 1.0); + _67.w = _74.z; + float4 _79 = UniformBuffer.Proj * _74; + float2 _92 = ((_79.xy / float2(_79.w)) * 0.5) + float2(0.5); + _92.y = 1.0 - _92.y; + out.gl_Position = _79; + out.out_var_TEXCOORD0 = _67; + out.out_var_TEXCOORD1 = float2(float((in.in_var_TEXCOORD0 >> 28u) & 1u), float((in.in_var_TEXCOORD0 >> 29u) & 1u)); + out.out_var_TEXCOORD2 = in.in_var_TEXCOORD0; + out.out_var_TEXCOORD3 = _92; return out; } diff --git a/shaders/bin/transparent.vert.spv b/shaders/bin/transparent.vert.spv index ed61eae9..f9ca59a2 100644 Binary files a/shaders/bin/transparent.vert.spv and b/shaders/bin/transparent.vert.spv differ diff --git a/shaders/bin/ui.comp.json b/shaders/bin/ui.comp.json deleted file mode 100644 index 71e95b64..00000000 --- a/shaders/bin/ui.comp.json +++ /dev/null @@ -1 +0,0 @@ -{ "samplers": 1, "readonly_storage_textures": 0, "readonly_storage_buffers": 0, "readwrite_storage_textures": 1, "readwrite_storage_buffers": 0, "uniform_buffers": 2, "threadcount_x": 8, "threadcount_y": 8, "threadcount_z": 1 } diff --git a/shaders/bin/ui.comp.msl b/shaders/bin/ui.comp.msl deleted file mode 100644 index 29daf19e..00000000 --- a/shaders/bin/ui.comp.msl +++ /dev/null @@ -1,169 +0,0 @@ -#pragma clang diagnostic ignored "-Wmissing-prototypes" - -#include -#include - -using namespace metal; - -template -void spvImageFence(ImageT img) { img.fence(); } - -struct type_UniformBuffer -{ - int2 Viewport; -}; - -struct type_UniformBuffer_1 -{ - uint Index; -}; - -kernel void main0(constant type_UniformBuffer& UniformBuffer [[buffer(0)]], constant type_UniformBuffer_1& UniformBuffer_1 [[buffer(1)]], texture2d_array atlasTexture [[texture(0)]], texture2d colorTexture [[texture(1)]], sampler atlasSampler [[sampler(0)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) -{ - do - { - uint2 _59 = uint2(colorTexture.get_width(), colorTexture.get_height()); - bool _70; - if (gl_GlobalInvocationID.x < _59.x) - { - _70 = gl_GlobalInvocationID.y >= _59.y; - } - else - { - _70 = true; - } - if (_70) - { - break; - } - float2 _75 = float2(UniformBuffer.Viewport); - float2 _76 = _75 * float2(0.0007812500116415321826934814453125, 0.001388888922519981861114501953125); - float _79 = precise::max(_76.x, _76.y); - float _80 = 50.0 * _79; - float _81 = 10.0 * _79; - float2 _84 = float2(_81) + float2(_80); - float _85 = float(gl_GlobalInvocationID.x); - float _92 = float(uint(UniformBuffer.Viewport.y) - gl_GlobalInvocationID.y); - bool _98; - if (_85 > _81) - { - _98 = _85 < _84.x; - } - else - { - _98 = false; - } - bool _102; - if (_98) - { - _102 = _92 > _81; - } - else - { - _102 = false; - } - bool _107; - if (_102) - { - _107 = _92 < _84.y; - } - else - { - _107 = false; - } - if (_107) - { - float3 _120 = float3((_85 - _81) / _80, 1.0 - ((_92 - _81) / _80), float(UniformBuffer_1.Index)); - float4 _122 = atlasTexture.sample(atlasSampler, _120.xy, uint(rint(_120.z)), level(0.0)); - float _123 = _122.w; - if (_123 > 0.001000000047497451305389404296875) - { - spvImageFence(colorTexture); - float4 _129 = colorTexture.read(uint2(gl_GlobalInvocationID.xy)); - float _130 = fast::clamp(_123, 0.0, 1.0); - float _135 = 1.0 - _130; - colorTexture.write(float4((_122.xyz * _130) + (_129.xyz * _135), _130 + (_129.w * _135)), uint2(gl_GlobalInvocationID.xy)); - break; - } - } - float _145 = 8.0 * _79; - float _146 = 2.0 * _79; - float2 _147 = _75 * 0.5; - float2 _148 = float2(_145, _146); - float2 _149 = _147 - _148; - float2 _150 = _147 + _148; - float2 _151 = float2(_146, _145); - float2 _152 = _147 - _151; - float2 _153 = _147 + _151; - bool _160; - if (_85 > _149.x) - { - _160 = _92 > _149.y; - } - else - { - _160 = false; - } - bool _165; - if (_160) - { - _165 = _85 < _150.x; - } - else - { - _165 = false; - } - bool _170; - if (_165) - { - _170 = _92 < _150.y; - } - else - { - _170 = false; - } - bool _191; - if (!_170) - { - bool _180; - if (_85 > _152.x) - { - _180 = _92 > _152.y; - } - else - { - _180 = false; - } - bool _185; - if (_180) - { - _185 = _85 < _153.x; - } - else - { - _185 = false; - } - bool _190; - if (_185) - { - _190 = _92 < _153.y; - } - else - { - _190 = false; - } - _191 = _190; - } - else - { - _191 = true; - } - if (_191) - { - colorTexture.write(float4(1.0), uint2(gl_GlobalInvocationID.xy)); - break; - } - break; - } while(false); -} - diff --git a/shaders/bin/ui.comp.spv b/shaders/bin/ui.comp.spv deleted file mode 100644 index 2f331a87..00000000 Binary files a/shaders/bin/ui.comp.spv and /dev/null differ diff --git a/shaders/blur.comp b/shaders/blur.comp deleted file mode 100644 index a3a589d5..00000000 --- a/shaders/blur.comp +++ /dev/null @@ -1,31 +0,0 @@ -Texture2D inputTexture : register(t0, space0); -[[vk::image_format("r8")]] -RWTexture2D outputTexture : register(u0, space1); - -static const int kKernel = 2; - -[numthreads(8, 8, 1)] -void main(uint3 threadID : SV_DispatchThreadID) -{ - uint width; - uint height; - outputTexture.GetDimensions(width, height); - if (threadID.x >= width || threadID.y >= height) - { - return; - } - int kernel = kKernel; - float value = 0.0f; - for (int y = -kernel; y <= kernel; y++) - { - int yy = clamp(threadID.y + y, 0, height - 1); - for (int x = -kernel; x <= kernel; x++) - { - int xx = clamp(threadID.x + x, 0, width - 1); - value += inputTexture[uint2(xx, yy)]; - } - } - kernel = kKernel * 2 + 1; - kernel *= kernel; - outputTexture[threadID.xy] = value / kernel; -} diff --git a/shaders/composite.comp b/shaders/composite.comp deleted file mode 100644 index 5beba308..00000000 --- a/shaders/composite.comp +++ /dev/null @@ -1,63 +0,0 @@ -#include "shader.hlsl" - -Texture2D shadowTexture : register(t0, space0); -SamplerState shadowSampler : register(s0, space0); -Texture2D colorTexture : register(t1, space0); -Texture2D lightTexture : register(t2, space0); -Texture2D ssaoTexture : register(t3, space0); -Texture2D voxelTexture : register(t4, space0); -Texture2D positionTexture : register(t5, space0); -[[vk::image_format("rgba8")]] -RWTexture2D compositeTexture : register(u0, space1); - -cbuffer UniformBuffer : register(b0, space2) -{ - float4x4 ShadowTransform; -}; - -cbuffer UniformBuffer : register(b1, space2) -{ - float3 PlayerPosition; -}; - -static const float kSSAO = 2.0f; - -[numthreads(8, 8, 1)] -void main(uint3 threadID : SV_DispatchThreadID) -{ - uint width; - uint height; - colorTexture.GetDimensions(width, height); - if (threadID.x >= width || threadID.y >= height) - { - return; - } - float3 albedo = colorTexture[threadID.xy].rgb; - uint voxel = voxelTexture[threadID.xy].x; - float3 position = positionTexture[threadID.xy].xyz; - float3 normal = GetNormal(voxel); - float3 diffuse = lightTexture[threadID.xy].rgb; - float3 ambient = GetAmbientLight(); - float sun = GetSunLight(shadowTexture, shadowSampler, ShadowTransform, position, normal, voxel); - float ssao = ssaoTexture[threadID.xy] * kSSAO; - float3 color; - if (GetOcclusion(voxel)) - { - color = albedo * (diffuse + ambient + sun - ssao); - } - else if (IsCloud(albedo) || IsSky(voxel)) - { - color = albedo; - } - else - { - color = albedo * (diffuse + ambient + sun); - } - if (!IsSky(voxel)) - { - float3 sky = GetSkyColor(position - PlayerPosition); - float fog = GetFog(distance(position.xz, PlayerPosition.xz)); - color = lerp(color, sky, fog); - } - compositeTexture[threadID.xy] = float4(color, 1.0f); -} diff --git a/shaders/depth.frag b/shaders/depth.frag deleted file mode 100644 index 91981030..00000000 --- a/shaders/depth.frag +++ /dev/null @@ -1,3 +0,0 @@ -void main() -{ -} diff --git a/shaders/depth.vert b/shaders/depth.vert deleted file mode 100644 index a1e1fb30..00000000 --- a/shaders/depth.vert +++ /dev/null @@ -1,35 +0,0 @@ -#include "shader.hlsl" - -cbuffer UniformBuffer : register(b0, space1) -{ - float4x4 Proj; -}; - -cbuffer UniformBuffer : register(b1, space1) -{ - float4x4 View; -}; - -cbuffer UniformBuffer : register(b2, space1) -{ - int2 ChunkPosition; -}; - -struct Input -{ - uint Voxel : TEXCOORD0; -}; - -struct Output -{ - float4 Position : SV_Position; -}; - -Output main(Input input) -{ - Output output; - int3 chunkPosition = float3(ChunkPosition.x, 0.0f, ChunkPosition.y); - float3 position = GetPosition(input.Voxel) + chunkPosition; - output.Position = mul(Proj, mul(View, float4(position, 1.0f))); - return output; -} diff --git a/shaders/hud.frag b/shaders/hud.frag new file mode 100644 index 00000000..1dde66f2 --- /dev/null +++ b/shaders/hud.frag @@ -0,0 +1,29 @@ +Texture2DArray atlasTexture : register(t0, space2); +SamplerState atlasSampler : register(s0, space2); + +cbuffer UniformBuffer : register(b0, space3) +{ + uint Block; +}; + +struct Input +{ + float2 Texcoord : TEXCOORD0; + nointerpolation uint IsBlock : TEXCOORD1; +}; + +static const float kEpsilon = 0.001f; + +float4 main(Input input) : SV_Target0 +{ + if (!input.IsBlock) + { + return float4(1.0f, 1.0f, 1.0f, 1.0f); + } + float4 color = atlasTexture.Sample(atlasSampler, float3(input.Texcoord, Block)); + if (color.a <= kEpsilon) + { + discard; + } + return color; +} diff --git a/shaders/hud.vert b/shaders/hud.vert new file mode 100644 index 00000000..c31bc041 --- /dev/null +++ b/shaders/hud.vert @@ -0,0 +1,56 @@ +cbuffer UniformBuffer : register(b0, space1) +{ + int2 Viewport; +}; + +struct Input +{ + uint VertexID : SV_VertexID; + uint InstanceID : SV_InstanceID; +}; + +struct Output +{ + float4 Position : SV_Position; + float2 Texcoord : TEXCOORD0; + nointerpolation uint IsBlock : TEXCOORD1; +}; + +static const float2 kCrosshair = float2(8.0f, 2.0f); +static const float2 kSize = float2(1280.0f, 720.0f); +static const float2 kPositions[6] = +{ + float2(0.0f, 0.0f), + float2(1.0f, 0.0f), + float2(0.0f, 1.0f), + float2(0.0f, 1.0f), + float2(1.0f, 0.0f), + float2(1.0f, 1.0f), +}; + +Output main(Input input) +{ + float2 ratio = float2(Viewport) / kSize; + float scale = max(ratio.x, ratio.y); + float2 minimum; + float2 maximum; + Output output; + output.IsBlock = input.InstanceID == 0; + if (output.IsBlock) + { + minimum = float2(10.0f, 10.0f) * scale; + maximum = minimum + 50.0f * scale; + } + else + { + float2 center = float2(Viewport) * 0.5f; + float2 size = input.InstanceID == 1 ? kCrosshair.xy : kCrosshair.yx; + minimum = center - size * scale; + maximum = center + size * scale; + } + float2 position = lerp(minimum, maximum, kPositions[input.VertexID]); + position = position / float2(Viewport) * 2.0f - 1.0f; + output.Position = float4(position, 0.0f, 1.0f); + output.Texcoord = float2(kPositions[input.VertexID].x, 1.0f - kPositions[input.VertexID].y); + return output; +} diff --git a/shaders/opaque.frag b/shaders/opaque.frag index 6fb4c753..394753cc 100644 --- a/shaders/opaque.frag +++ b/shaders/opaque.frag @@ -2,43 +2,60 @@ Texture2DArray atlasTexture : register(t0, space2); SamplerState atlasSampler : register(s0, space2); -StructuredBuffer lightBuffer : register(t1, space2); +StructuredBuffer blockBuffer : register(t1, space2); +StructuredBuffer lightBuffer : register(t2, space2); cbuffer UniformBuffer : register(b0, space3) { int LightCount : packoffset(c0); }; +cbuffer UniformBuffer : register(b1, space3) +{ + float3 PlayerPosition : packoffset(c0); +}; + +cbuffer UniformBuffer : register(b2, space3) +{ + float4 Sun : packoffset(c0); + float4 SkyTop : packoffset(c1); + float4 SkyHorizon : packoffset(c2); + float4 Ambient : packoffset(c3); +}; + struct Input { float4 WorldPosition : TEXCOORD0; - nointerpolation float3 Normal : TEXCOORD1; - float3 Texcoord : TEXCOORD2; - nointerpolation uint Voxel : TEXCOORD3; + float2 Texcoord : TEXCOORD1; + nointerpolation uint Voxel : TEXCOORD2; + float AO : TEXCOORD3; }; struct Output { float4 Color : SV_Target0; float4 Position : SV_Target1; - float4 Light : SV_Target2; - uint Voxel : SV_Target3; }; Output main(Input input) { Output output; - output.Color = atlasTexture.Sample(atlasSampler, input.Texcoord); + Block block = blockBuffer[GetBlockIndex(input.Voxel)]; + float3 texcoord = float3(input.Texcoord, GetAtlasIndex(input.Voxel, block)); + float4 color = atlasTexture.Sample(atlasSampler, texcoord); output.Position = input.WorldPosition; - output.Light = float4(0.0f, 0.0f, 0.0f, 0.0f); - output.Voxel = 0; - if (output.Color.a < kEpsilon) + if (color.a < kEpsilon) { discard; return output; } - output.Voxel |= input.Voxel & (OCCLUSION_MASK << OCCLUSION_OFFSET); - output.Voxel |= input.Voxel & (DIRECTION_MASK << DIRECTION_OFFSET); - output.Light.rgb = GetDiffuseLight(lightBuffer, LightCount, input.WorldPosition, input.Normal); + float3 albedo = color.rgb; + float3 normal = GetNormal(input.Voxel); + float3 light = GetLight(lightBuffer, LightCount, input.WorldPosition.xyz, normal, block); + float3 ambient = Ambient.xyz; + float sunlight = GetSunlight(Sun.xyz, Sun.w, normal, block); + float3 sky = GetSkyColor(input.WorldPosition.xyz - PlayerPosition, SkyTop.xyz, SkyHorizon.xyz); + float fog = GetFogValue(distance(input.WorldPosition.xz, PlayerPosition.xz)); + output.Color = float4(lerp(albedo * (light + ambient * input.AO + sunlight), sky, fog), 1.0f); return output; } diff --git a/shaders/opaque.vert b/shaders/opaque.vert index bc0f6243..79d7c7a8 100644 --- a/shaders/opaque.vert +++ b/shaders/opaque.vert @@ -24,21 +24,21 @@ struct Output { float4 Position : SV_Position; float4 WorldPosition : TEXCOORD0; - nointerpolation float3 Normal : TEXCOORD1; - float3 Texcoord : TEXCOORD2; - nointerpolation uint Voxel : TEXCOORD3; + float2 Texcoord : TEXCOORD1; + nointerpolation uint Voxel : TEXCOORD2; + float AO : TEXCOORD3; }; Output main(Input input) { Output output; - int3 chunkPosition = float3(ChunkPosition.x, 0.0f, ChunkPosition.y); + int3 chunkPosition = int3(ChunkPosition.x, 0, ChunkPosition.y); output.WorldPosition.xyz = GetPosition(input.Voxel) + chunkPosition; - output.Normal = GetNormal(input.Voxel); output.Position = mul(View, float4(output.WorldPosition.xyz, 1.0f)); output.WorldPosition.w = output.Position.z; output.Position = mul(Proj, output.Position); output.Texcoord = GetTexcoord(input.Voxel); output.Voxel = input.Voxel; + output.AO = GetAO(input.Voxel); return output; } diff --git a/shaders/raycast.vert b/shaders/raycast.vert index 07eb521c..509929a5 100644 --- a/shaders/raycast.vert +++ b/shaders/raycast.vert @@ -15,14 +15,11 @@ struct Output float4 Position : SV_POSITION; }; -static const float kZ = 0.1f; - Output main(uint vertexID : SV_VertexID) { Output output; - float3 position = GetCubePosition(vertexID); + float3 position = GetCubePosition(vertexID) * 1.02f; position += BlockPosition + 0.5f; output.Position = mul(Transform, float4(position, 1.0f)); - output.Position.z = kZ; return output; } diff --git a/shaders/shader.hlsl b/shaders/shader.hlsl index d6af8862..53e230a8 100644 --- a/shaders/shader.hlsl +++ b/shaders/shader.hlsl @@ -6,66 +6,73 @@ static const float kEpsilon = 0.001f; static const float kPi = 3.14159265f; +static const uint kWater = 16; -static const float3 kNormals[10] = +struct Light { - float3( 0.0f, 0.0f, 1.0f ), - float3( 0.0f, 0.0f,-1.0f ), - float3( 1.0f, 0.0f, 0.0f ), - float3(-1.0f, 0.0f, 0.0f ), - float3( 0.0f, 1.0f, 0.0f ), - float3( 0.0f,-1.0f, 0.0f ), - float3( 0.0f, 1.0f, 0.0f ), - float3( 0.0f, 1.0f, 0.0f ), - float3( 0.0f, 1.0f, 0.0f ), - float3( 0.0f, 1.0f, 0.0f ), + int3 Position; + uint Color; +}; + +struct Block +{ + Light _Light; + uint IsOpaque; + uint IsSolid; + uint IsSprite; + uint UseAO; + uint UseSunNormal; + float SunIntensity; + uint Indices[6]; }; static const float3 kCubePositions[8] = { float3(-0.5f,-0.5f,-0.5f ), - float3( 0.5f,-0.5f,-0.5f ), - float3( 0.5f, 0.5f,-0.5f ), + float3( 0.5f,-0.5f,-0.5f ), + float3( 0.5f, 0.5f,-0.5f ), float3(-0.5f, 0.5f,-0.5f ), float3(-0.5f,-0.5f, 0.5f ), - float3( 0.5f,-0.5f, 0.5f ), - float3( 0.5f, 0.5f, 0.5f ), - float3(-0.5f, 0.5f, 0.5f ), + float3( 0.5f,-0.5f, 0.5f ), + float3( 0.5f, 0.5f, 0.5f ), + float3(-0.5f, 0.5f, 0.5f ), }; -static const float3 kCubeNormals[6] = +static const uint kCubeIndices[36] = { + 0, 1, 2, 0, 2, 3, + 5, 4, 7, 5, 7, 6, + 4, 0, 3, 4, 3, 7, + 1, 5, 6, 1, 6, 2, + 3, 2, 6, 3, 6, 7, + 4, 5, 1, 4, 1, 0, +}; + +static const float3 kNormals[6] = +{ + float3( 0.0f, 0.0f, 1.0f ), float3( 0.0f, 0.0f,-1.0f ), - float3( 0.0f, 0.0f, 1.0f ), + float3( 1.0f, 0.0f, 0.0f ), float3(-1.0f, 0.0f, 0.0f ), - float3( 1.0f, 0.0f, 0.0f ), - float3( 0.0f, 1.0f, 0.0f ), + float3( 0.0f, 1.0f, 0.0f ), float3( 0.0f,-1.0f, 0.0f ), }; -static const uint kCubeIndices[36] = -{ - 0, 1, 2, 0, 2, 3, - 5, 4, 7, 5, 7, 6, - 4, 0, 3, 4, 3, 7, - 1, 5, 6, 1, 6, 2, - 3, 2, 6, 3, 6, 7, - 4, 5, 1, 4, 1, 0 -}; +static const float kAO[4] = {0.4f, 0.6f, 0.8f, 1.0f}; -bool GetOcclusion(uint voxel) +uint GetDirection(uint voxel) { - return (voxel >> OCCLUSION_OFFSET) & OCCLUSION_MASK; + return (voxel >> DIRECTION_OFFSET) & DIRECTION_MASK; } -uint GetDirection(uint voxel) +uint GetBlockIndex(uint voxel) { - return ((voxel >> DIRECTION_OFFSET) & DIRECTION_MASK) - 1; + return (voxel >> BLOCK_OFFSET) & BLOCK_MASK; } -bool GetShadow(uint voxel) +uint GetAtlasIndex(uint voxel, Block block) { - return (voxel >> SHADOW_OFFSET) & SHADOW_MASK; + return block.Indices[GetDirection(voxel)]; } float3 GetPosition(uint voxel) @@ -73,156 +80,81 @@ float3 GetPosition(uint voxel) return float3((voxel >> X_OFFSET) & X_MASK, (voxel >> Y_OFFSET) & Y_MASK, (voxel >> Z_OFFSET) & Z_MASK); } -uint GetIndex(uint voxel) -{ - return (voxel >> INDEX_OFFSET) & INDEX_MASK; -} - -float3 GetTexcoord(uint voxel) -{ - return float3((voxel >> U_OFFSET) & U_MASK, (voxel >> V_OFFSET) & V_MASK, GetIndex(voxel)); -} - -float3 GetNormal(uint voxel) -{ - return kNormals[GetDirection(voxel)]; -} - float3 GetCubePosition(uint vertexID) { return kCubePositions[kCubeIndices[vertexID]]; } -float3 GetCubeNormal(uint vertexID) +float2 GetTexcoord(uint voxel) { - return kCubeNormals[vertexID / 6]; + return float2((voxel >> U_OFFSET) & U_MASK, (voxel >> V_OFFSET) & V_MASK); } -bool IsSky(uint voxel) +float3 GetNormal(uint voxel) { - return voxel == 0; + return kNormals[GetDirection(voxel)]; } -bool IsCloud(float3 color) +float GetAO(uint voxel) { - return length(color) > (1.0f - kEpsilon); + return kAO[(voxel >> AO_OFFSET) & AO_MASK]; } -struct Light -{ - uint Color; - int X; - int Y; - int Z; -}; - -float3 GetDiffuseLight(StructuredBuffer lights, uint lightCount, float4 position, float3 normal) +float3 GetLight(StructuredBuffer lights, uint count, float3 position, float3 normal, Block block) { static const float3 kOffset = float3(0.0f, 0.25f, 0.0f); - static const float kLight = 2.0f; - float3 finalColor = float3(0.0f, 0.0f, 0.0f); - for (uint i = 0; i < lightCount; i++) + float3 final = float3(0.0f, 0.0f, 0.0f); + for (uint i = 0; i < count; i++) { Light light = lights[i]; float radius = (light.Color & 0xFF000000) >> 24; - float3 lightPosition = float3(light.X, light.Y, light.Z) + 0.5f + kOffset; - float3 offset = lightPosition - position.xyz; + float3 offset = light.Position + 0.5f + kOffset - position; float distance = length(offset); - if (distance >= radius || radius <= 0.0f) + if (distance >= radius) { continue; } - float3 lightDirection = offset / distance; - float NdotL = saturate(dot(normal, lightDirection)); - if (NdotL <= 0.0f) + float angle = 1.0f; + if (!block.IsSprite) + { + angle = saturate(dot(normal, offset / distance)); + } + if (angle <= 0.0f) { continue; } - float attenuation = 1.0f - (distance / radius); - attenuation = saturate(attenuation); - attenuation *= attenuation; + float attenuation = 1.0f - smoothstep(0.0f, 1.0f, saturate(distance / radius)); float3 color; color.r = ((light.Color & 0x000000FF) >> 0) / 255.0f; color.g = ((light.Color & 0x0000FF00) >> 8) / 255.0f; color.b = ((light.Color & 0x00FF0000) >> 16) / 255.0f; - finalColor += color * NdotL * attenuation; + final += color * angle * attenuation; } - return finalColor * kLight; + return final; } -float GetSunLight(Texture2D texture, SamplerState state, float4x4 transform, float3 position, float3 normal, uint voxel) +float GetSunlight(float3 direction, float intensity, float3 normal, Block block) { - static const float kBias = 0.001f; - static const float kBase = 0.0f; - static const float kShadow = 0.4f; - float4 shadowPosition = mul(transform, float4(position, 1.0f)); - shadowPosition.xyz /= shadowPosition.w; - float2 uv = shadowPosition.xy * 0.5f + 0.5f; - uv.y = 1.0f - uv.y; - if (uv.x < 0.0f || uv.x > 1.0f || uv.y < 0.0f || uv.y > 1.0f) + if (intensity <= 0.0f) { - return kBase + kShadow; - } - float3 direction = normalize(float3(transform[2].xyz)); - float ratio = -0.707f; - if (GetOcclusion(voxel)) - { - ratio = dot(normal, direction); - if (ratio > 0.0f) - { - return 0.0f; - } - } - float depth = shadowPosition.z; - float closestDepth = texture.SampleLevel(state, uv, 0); - if (depth < closestDepth + kBias) - { - return kBase - kShadow * ratio; + return 0.0f; } - else + float angle = 1.0f; + if (block.UseSunNormal) { - return 0.0f; + angle = saturate(-dot(normal, direction)); } + return block.SunIntensity * intensity * angle; } -float3 GetAmbientLight() -{ - return float3(0.5f, 0.5f, 0.5f); -} - -float GetFog(float x) -{ - return min(pow(x / 250.0f, 2.5f), 1.0f); -} - -float3 GetSkyColor(float3 position) -{ - static const float3 kTop = float3(0.212f, 0.773f, 0.957f); - static const float3 kBottom = float3(0.220f, 0.349f, 0.702f); - float dy = position.y; - float dx = length(float2(position.x, position.z)); - float alpha = (atan2(dy, dx) + kPi / 2.0f) / kPi; - return lerp(kBottom, kTop, alpha); -} - -float2 GetRandom2(float2 position) +float GetFogValue(float distance) { - float2 k1 = float2(127.1f, 311.7f); - float2 k2 = float2(269.5f, 183.3f); - float n = sin(dot(position, k1)) * 43758.5453f; - float m = sin(dot(position, k2)) * 43758.5453f; - float2 r = frac(float2(n, m)); - return r * 2.0f - 1.0f; + return min(pow(distance / 250.0f, 2.5f), 1.0f); } -float2 GetRandom2(float3 position) +float3 GetSkyColor(float3 position, float3 top, float3 horizon) { - float3 k1 = float3(127.1, 311.7, 74.7); - float3 k2 = float3(269.5, 183.3, 246.1); - float n = sin(dot(position, k1)) * 43758.5453f; - float m = sin(dot(position, k2)) * 43758.5453f; - float2 r = frac(float2(n, m)); - return r * 2.0f - 1.0f; + return lerp(horizon, top, (atan2(position.y, length(position.xz)) + kPi / 2.0f) / kPi); } #endif diff --git a/shaders/shadow.frag b/shaders/shadow.frag deleted file mode 100644 index 91981030..00000000 --- a/shaders/shadow.frag +++ /dev/null @@ -1,3 +0,0 @@ -void main() -{ -} diff --git a/shaders/shadow.vert b/shaders/shadow.vert deleted file mode 100644 index 71cb384a..00000000 --- a/shaders/shadow.vert +++ /dev/null @@ -1,37 +0,0 @@ -#include "shader.hlsl" - -cbuffer UniformBuffer : register(b0, space1) -{ - float4x4 Proj; -}; - -cbuffer UniformBuffer : register(b1, space1) -{ - float4x4 View; -}; - -cbuffer UniformBuffer : register(b2, space1) -{ - int2 ChunkPosition; -}; - -struct Input -{ - uint Voxel : TEXCOORD0; -}; - -struct Output -{ - float4 Position : SV_Position; - float ClipDistance : SV_ClipDistance0; -}; - -Output main(Input input) -{ - Output output; - int3 chunkPosition = float3(ChunkPosition.x, 0.0f, ChunkPosition.y); - float3 position = GetPosition(input.Voxel) + chunkPosition; - output.Position = mul(Proj, mul(View, float4(position, 1.0f))); - output.ClipDistance = GetShadow(input.Voxel) ? 1.0f : -1.0f; - return output; -} diff --git a/shaders/sky.frag b/shaders/sky.frag index 400450af..ef448087 100644 --- a/shaders/sky.frag +++ b/shaders/sky.frag @@ -9,14 +9,20 @@ struct Output { float4 Color : SV_Target0; float4 Position : SV_Target1; - float4 Light : SV_Target2; - uint Voxel : SV_Target3; +}; + +cbuffer UniformBuffer : register(b0, space3) +{ + float4 Sun : packoffset(c0); + float4 SkyTop : packoffset(c1); + float4 SkyHorizon : packoffset(c2); + float4 Ambient : packoffset(c3); }; Output main(Input input) { Output output; - output.Color = float4(GetSkyColor(input.LocalPosition), 1.0f); - output.Voxel = 0; + output.Color = float4(GetSkyColor(input.LocalPosition, SkyTop.xyz, SkyHorizon.xyz), 1.0f); + output.Position = float4(0.0f, 0.0f, 0.0f, 0.0f); return output; } diff --git a/shaders/ssao.comp b/shaders/ssao.comp deleted file mode 100644 index f4fddfd0..00000000 --- a/shaders/ssao.comp +++ /dev/null @@ -1,66 +0,0 @@ -#include "shader.hlsl" - -Texture2D voxelTexture : register(t0, space0); -Texture2D positionTexture : register(t1, space0); -[[vk::image_format("r8")]] -RWTexture2D ssaoTexture : register(u0, space1); - -static const float kThreshold = 0.05f; -static const float kScale = 75.0f; -static const int kKernel = 2; - -bool IsOccluded(uint2 id, uint direction, float3 position) -{ - uint voxel = voxelTexture[id].x; - if (!GetOcclusion(voxel)) - { - return false; - } - float3 neighbor = positionTexture[id].xyz; - float offsets[6]; - offsets[0] = neighbor.z - position.z; - offsets[1] = position.z - neighbor.z; - offsets[2] = neighbor.x - position.x; - offsets[3] = position.x - neighbor.x; - offsets[4] = neighbor.y - position.y; - offsets[5] = position.y - neighbor.y; - return offsets[direction] > kThreshold; -} - -[numthreads(8, 8, 1)] -void main(uint3 threadID : SV_DispatchThreadID) -{ - uint width; - uint height; - ssaoTexture.GetDimensions(width, height); - if (threadID.x >= width || threadID.y >= height) - { - return; - } - ssaoTexture[threadID.xy] = 0.0f; - uint voxel = voxelTexture[threadID.xy]; - if (!GetOcclusion(voxel)) - { - return; - } - float2 uv = float2(threadID.xy) / float2(width, height); - uint direction = GetDirection(voxel); - float4 position = positionTexture[threadID.xy]; - float depth = max(abs(position.w), 1.0f); - float2 scale = kScale / float2(width, height) / depth; - float ssao = 0.0f; - for (int x = -kKernel; x <= kKernel; x++) - for (int y = -kKernel; y <= kKernel; y++) - { - float2 origin = uv + float2(x, y) * scale; - float2 offset = GetRandom2(origin) * scale; - uint2 id = (origin + offset) * float2(width, height); - if (x == 0 || y == 0 || id.x < 0 || id.y < 0 || id.x >= width || id.y >= height) - { - continue; - } - float value = max(distance(threadID.xy, id), 1.0f); - ssao += IsOccluded(id, direction, position.xyz) / value; - } - ssaoTexture[threadID.xy] = ssao / depth; -} diff --git a/shaders/transparent.frag b/shaders/transparent.frag index fd50eccb..91eefc7d 100644 --- a/shaders/transparent.frag +++ b/shaders/transparent.frag @@ -2,10 +2,9 @@ Texture2DArray atlasTexture : register(t0, space2); SamplerState atlasSampler : register(s0, space2); -Texture2D shadowTexture : register(t1, space2); -SamplerState shadowSampler : register(s1, space2); -Texture2D positionTexture : register(t2, space2); -SamplerState positionSampler : register(s2, space2); +Texture2D positionTexture : register(t1, space2); +SamplerState positionSampler : register(s1, space2); +StructuredBuffer blockBuffer : register(t2, space2); StructuredBuffer lightBuffer : register(t3, space2); cbuffer UniformBuffer : register(b0, space3) @@ -15,41 +14,44 @@ cbuffer UniformBuffer : register(b0, space3) cbuffer UniformBuffer : register(b1, space3) { - float4x4 ShadowTransform : packoffset(c0); + float3 PlayerPosition : packoffset(c0); }; cbuffer UniformBuffer : register(b2, space3) { - float3 PlayerPosition : packoffset(c0); + float4 Sun : packoffset(c0); + float4 SkyTop : packoffset(c1); + float4 SkyHorizon : packoffset(c2); + float4 Ambient : packoffset(c3); }; struct Input { float4 WorldPosition : TEXCOORD0; - nointerpolation float3 Normal : TEXCOORD1; - float3 Texcoord : TEXCOORD2; - nointerpolation uint Voxel : TEXCOORD3; - float2 Fragment : TEXCOORD4; + float2 Texcoord : TEXCOORD1; + nointerpolation uint Voxel : TEXCOORD2; + noperspective float2 Fragment : TEXCOORD3; }; -static const uint kWater = 16; - float4 main(Input input) : SV_Target0 { - float4 color = atlasTexture.Sample(atlasSampler, input.Texcoord); + Block block = blockBuffer[GetBlockIndex(input.Voxel)]; + float3 normal = GetNormal(input.Voxel); + uint index = GetAtlasIndex(input.Voxel, block); + float3 texcoord = float3(input.Texcoord, index); + float4 color = atlasTexture.Sample(atlasSampler, texcoord); float3 albedo = color.rgb; float alpha = color.a; float4 position = input.WorldPosition; - float3 diffuse = GetDiffuseLight(lightBuffer, LightCount, position, input.Normal); - float3 ambient = GetAmbientLight(); - float sun = GetSunLight(shadowTexture, shadowSampler, ShadowTransform, position.xyz, input.Normal, input.Voxel); - float3 sky = GetSkyColor(input.WorldPosition.xyz - PlayerPosition); - float fog = GetFog(distance(position.xz, PlayerPosition.xz)); - if (GetIndex(input.Voxel) == kWater) + float3 light = GetLight(lightBuffer, LightCount, position.xyz, normal, block); + float3 ambient = Ambient.xyz; + float sunlight = GetSunlight(Sun.xyz, Sun.w, normal, block); + float3 sky = GetSkyColor(input.WorldPosition.xyz - PlayerPosition, SkyTop.xyz, SkyHorizon.xyz); + float fog = GetFogValue(distance(position.xz, PlayerPosition.xz)); + if (index == kWater) { - // TODO: Causes bug where alpha is 0 or 1 as camera approaches water - float3 groundPosition = positionTexture.Sample(positionSampler, input.Fragment).xyz; - alpha += (input.WorldPosition.y - groundPosition.y) / 10.0f; + float3 seabed = positionTexture.Sample(positionSampler, input.Fragment).xyz; + alpha += (input.WorldPosition.y - seabed.y) / 10.0f; } - return float4(lerp(albedo * (diffuse + ambient + sun), sky, fog), alpha); + return float4(lerp(albedo * (light + ambient + sunlight), sky, fog), alpha); } diff --git a/shaders/transparent.vert b/shaders/transparent.vert index aa401d21..46f4db9d 100644 --- a/shaders/transparent.vert +++ b/shaders/transparent.vert @@ -24,25 +24,22 @@ struct Output { float4 Position : SV_Position; float4 WorldPosition : TEXCOORD0; - nointerpolation float3 Normal : TEXCOORD1; - float3 Texcoord : TEXCOORD2; - nointerpolation uint Voxel : TEXCOORD3; - float2 Fragment : TEXCOORD4; + float2 Texcoord : TEXCOORD1; + nointerpolation uint Voxel : TEXCOORD2; + noperspective float2 Fragment : TEXCOORD3; }; Output main(Input input) { Output output; - int3 chunkPosition = float3(ChunkPosition.x, 0.0f, ChunkPosition.y); + int3 chunkPosition = int3(ChunkPosition.x, 0, ChunkPosition.y); output.WorldPosition.xyz = GetPosition(input.Voxel) + chunkPosition; - output.Normal = GetNormal(input.Voxel); output.Position = mul(View, float4(output.WorldPosition.xyz, 1.0f)); output.WorldPosition.w = output.Position.z; output.Position = mul(Proj, output.Position); output.Texcoord = GetTexcoord(input.Voxel); output.Voxel = input.Voxel; - output.Fragment = output.Position.xy / output.Position.w; - output.Fragment = output.Fragment * 0.5f + 0.5f; + output.Fragment = output.Position.xy / output.Position.w * 0.5f + 0.5f; output.Fragment.y = 1.0f - output.Fragment.y; return output; } diff --git a/shaders/ui.comp b/shaders/ui.comp deleted file mode 100644 index 033811dc..00000000 --- a/shaders/ui.comp +++ /dev/null @@ -1,68 +0,0 @@ -Texture2DArray atlasTexture : register(t0, space0); -SamplerState atlasSampler : register(s0, space0); -[[vk::image_format("rgba8")]] -RWTexture2D colorTexture : register(u0, space1); - -cbuffer UniformBuffer : register(b0, space2) -{ - int2 Viewport; -}; - -cbuffer UniformBuffer : register(b1, space2) -{ - uint Index; -}; - -static const float kEpsilon = 0.001f; -static const float kWidth = 1280.0f; -static const float kHeight = 720.0f; - -[numthreads(8, 8, 1)] -void main(uint3 threadID : SV_DispatchThreadID) -{ - uint width; - uint height; - colorTexture.GetDimensions(width, height); - if (threadID.x >= width || threadID.y >= height) - { - return; - } - float2 ratio = float2(Viewport) / float2(kWidth, kHeight); - float scale = max(ratio.x, ratio.y); - float blockWidth = 50.0f * scale; - float2 blockStart = float2(10.0f * scale, 10.0f * scale); - float2 blockEnd = blockStart + blockWidth; - float2 pixel = float2(threadID.x, Viewport.y - threadID.y); - if (pixel.x > blockStart.x && pixel.x < blockEnd.x && - pixel.y > blockStart.y && pixel.y < blockEnd.y) - { - float x = (pixel.x - blockStart.x) / blockWidth; - float y = (pixel.y - blockStart.y) / blockWidth; - float4 src = atlasTexture.SampleLevel(atlasSampler, float3(x, 1.0f - y, Index), 0); - if (src.a > kEpsilon) - { - float4 dst = colorTexture[threadID.xy]; - float srcA = saturate(src.a); - float dstA = dst.a; - float3 color = src.rgb * srcA + dst.rgb * (1.0f - srcA); - float alpha = srcA + dstA * (1.0f - srcA); - colorTexture[threadID.xy] = float4(color, alpha); - return; - } - } - float crossWidth = 8.0f * scale; - float crossThickness = 2.0f * scale; - float2 crossCenter = float2(Viewport) * 0.5f; - float2 crossStart1 = crossCenter - float2(crossWidth, crossThickness); - float2 crossEnd1 = crossCenter + float2(crossWidth, crossThickness); - float2 crossStart2 = crossCenter - float2(crossThickness, crossWidth); - float2 crossEnd2 = crossCenter + float2(crossThickness, crossWidth); - if ((pixel.x > crossStart1.x && pixel.y > crossStart1.y && - pixel.x < crossEnd1.x && pixel.y < crossEnd1.y) || - (pixel.x > crossStart2.x && pixel.y > crossStart2.y && - pixel.x < crossEnd2.x && pixel.y < crossEnd2.y)) - { - colorTexture[threadID.xy] = float4(1.0f, 1.0f, 1.0f, 1.0f); - return; - } -} diff --git a/src/block.c b/src/block.c index 40ccb666..dfe6866d 100644 --- a/src/block.c +++ b/src/block.c @@ -1,288 +1,342 @@ +#include + #include "block.h" +#include "buffer.h" #include "direction.h" -#define TORCH_INTENSITY 15 - -struct +typedef struct BlockData { - bool is_opaque; - bool is_sprite; - bool is_solid; - bool has_occlusion; - bool has_shadow; - int indices[6]; - light_t light; -} -static const BLOCKS[BLOCK_COUNT] = + Light light; + Uint32 is_opaque; + Uint32 is_solid; + Uint32 is_sprite; + Uint32 use_ao; + Uint32 use_sun_normal; + float sun_intensity; + Uint32 indices[DIRECTION_COUNT]; +} BlockData; + +static const BlockData BLOCKS[BLOCK_COUNT] = { + [BLOCK_EMPTY] = + { + .light = {0}, + .is_opaque = false, + .is_solid = false, + .is_sprite = false, + .use_ao = false, + .use_sun_normal = false, + .sun_intensity = 0.0f, + .indices = {0}, + }, [BLOCK_GRASS] = { + .light = {0}, .is_opaque = true, - .is_sprite = false, .is_solid = true, - .has_occlusion = true, - .has_shadow = true, + .is_sprite = false, + .use_ao = true, + .use_sun_normal = true, + .sun_intensity = 0.55f, .indices = {2, 2, 2, 2, 1, 3}, - .light = {0, 0, 0, 0}, }, [BLOCK_DIRT] = { + .light = {0}, .is_opaque = true, - .is_sprite = false, .is_solid = true, - .has_occlusion = true, - .has_shadow = true, + .is_sprite = false, + .use_ao = true, + .use_sun_normal = true, + .sun_intensity = 0.55f, .indices = {3, 3, 3, 3, 3, 3}, - .light = {0, 0, 0, 0}, }, [BLOCK_SAND] = { + .light = {0}, .is_opaque = true, - .is_sprite = false, .is_solid = true, - .has_occlusion = true, - .has_shadow = true, + .is_sprite = false, + .use_ao = true, + .use_sun_normal = true, + .sun_intensity = 0.55f, .indices = {5, 5, 5, 5, 5, 5}, - .light = {0, 0, 0, 0}, }, [BLOCK_SNOW] = { + .light = {0}, .is_opaque = true, - .is_sprite = false, .is_solid = true, - .has_occlusion = true, - .has_shadow = true, + .is_sprite = false, + .use_ao = true, + .use_sun_normal = true, + .sun_intensity = 0.55f, .indices = {6, 6, 6, 6, 6, 6}, - .light = {0, 0, 0, 0}, }, [BLOCK_STONE] = { + .light = {0}, .is_opaque = true, - .is_sprite = false, .is_solid = true, - .has_occlusion = true, - .has_shadow = true, + .is_sprite = false, + .use_ao = true, + .use_sun_normal = true, + .sun_intensity = 0.55f, .indices = {4, 4, 4, 4, 4, 4}, - .light = {0, 0, 0, 0}, }, [BLOCK_LOG] = { + .light = {0}, .is_opaque = true, - .is_sprite = false, .is_solid = true, - .has_occlusion = true, - .has_shadow = true, + .is_sprite = false, + .use_ao = true, + .use_sun_normal = true, + .sun_intensity = 0.55f, .indices = {8, 8, 8, 8, 7, 7}, - .light = {0, 0, 0, 0}, }, [BLOCK_LEAVES] = { + .light = {0}, .is_opaque = true, - .is_sprite = false, .is_solid = true, - .has_occlusion = true, - .has_shadow = true, + .is_sprite = false, + .use_ao = true, + .use_sun_normal = true, + .sun_intensity = 0.55f, .indices = {10, 10, 10, 10, 10, 10}, - .light = {0, 0, 0, 0}, }, [BLOCK_CLOUD] = { + .light = {0}, .is_opaque = true, - .is_sprite = false, .is_solid = true, - .has_occlusion = false, - .has_shadow = false, + .is_sprite = false, + .use_ao = true, + .use_sun_normal = false, + .sun_intensity = 1.0f, .indices = {9, 9, 9, 9, 9, 9}, - .light = {0, 0, 0, 0}, }, [BLOCK_BUSH] = { + .light = {0}, .is_opaque = true, - .is_sprite = true, .is_solid = false, - .has_occlusion = false, - .has_shadow = false, + .is_sprite = true, + .use_ao = false, + .use_sun_normal = true, + .sun_intensity = 0.55f, .indices = {15, 15, 15, 15, 15, 15}, - .light = {0, 0, 0, 0}, }, [BLOCK_BLUEBELL] = { + .light = {0}, .is_opaque = true, - .is_sprite = true, .is_solid = false, - .has_occlusion = false, - .has_shadow = false, + .is_sprite = true, + .use_ao = false, + .use_sun_normal = true, + .sun_intensity = 0.55f, .indices = {13, 13, 13, 13, 13, 13}, - .light = {0, 0, 0, 0}, }, [BLOCK_GARDENIA] = { + .light = {0}, .is_opaque = true, - .is_sprite = true, .is_solid = false, - .has_occlusion = false, - .has_shadow = false, + .is_sprite = true, + .use_ao = false, + .use_sun_normal = true, + .sun_intensity = 0.55f, .indices = {12, 12, 12, 12, 12, 12}, - .light = {0, 0, 0, 0}, }, [BLOCK_ROSE] = { + .light = {0}, .is_opaque = true, - .is_sprite = true, .is_solid = false, - .has_occlusion = false, - .has_shadow = false, + .is_sprite = true, + .use_ao = false, + .use_sun_normal = true, + .sun_intensity = 0.55f, .indices = {11, 11, 11, 11, 11, 11}, - .light = {0, 0, 0, 0}, }, [BLOCK_LAVENDER] = { + .light = {0}, .is_opaque = true, - .is_sprite = true, .is_solid = false, - .has_occlusion = false, - .has_shadow = false, + .is_sprite = true, + .use_ao = false, + .use_sun_normal = true, + .sun_intensity = 0.55f, .indices = {14, 14, 14, 14, 14, 14}, - .light = {0, 0, 0, 0}, }, [BLOCK_WATER] = { + .light = {0}, .is_opaque = false, - .is_sprite = false, .is_solid = false, - .has_occlusion = false, - .has_shadow = false, + .is_sprite = false, + .use_ao = false, + .use_sun_normal = true, + .sun_intensity = 0.55f, .indices = {16, 16, 16, 16, 16, 16}, - .light = {0, 0, 0, 0}, }, [BLOCK_RED_TORCH] = { + .light = {0, 0, 0, 236, 39, 63, 15}, .is_opaque = true, - .is_sprite = true, .is_solid = false, - .has_occlusion = false, - .has_shadow = false, + .is_sprite = true, + .use_ao = false, + .use_sun_normal = true, + .sun_intensity = 0.55f, .indices = {17, 17, 17, 17, 17, 17}, - .light = {236, 39, 63, TORCH_INTENSITY}, }, [BLOCK_GREEN_TORCH] = { + .light = {0, 0, 0, 90, 181, 82, 15}, .is_opaque = true, - .is_sprite = true, .is_solid = false, - .has_occlusion = false, - .has_shadow = false, + .is_sprite = true, + .use_ao = false, + .use_sun_normal = true, + .sun_intensity = 0.55f, .indices = {18, 18, 18, 18, 18, 18}, - .light = {90, 181, 82, TORCH_INTENSITY}, }, [BLOCK_BLUE_TORCH] = { + .light = {0, 0, 0, 51, 136, 222, 15}, .is_opaque = true, - .is_sprite = true, .is_solid = false, - .has_occlusion = false, - .has_shadow = false, + .is_sprite = true, + .use_ao = false, + .use_sun_normal = true, + .sun_intensity = 0.55f, .indices = {19, 19, 19, 19, 19, 19}, - .light = {51, 136, 222, TORCH_INTENSITY}, }, [BLOCK_YELLOW_TORCH] = { + .light = {0, 0, 0, 243, 168, 51, 15}, .is_opaque = true, - .is_sprite = true, .is_solid = false, - .has_occlusion = false, - .has_shadow = false, + .is_sprite = true, + .use_ao = false, + .use_sun_normal = true, + .sun_intensity = 0.55f, .indices = {20, 20, 20, 20, 20, 20}, - .light = {243, 168, 51, TORCH_INTENSITY}, }, [BLOCK_CYAN_TORCH] = { + .light = {0, 0, 0, 54, 197, 244, 15}, .is_opaque = true, - .is_sprite = true, .is_solid = false, - .has_occlusion = false, - .has_shadow = false, + .is_sprite = true, + .use_ao = false, + .use_sun_normal = true, + .sun_intensity = 0.55f, .indices = {21, 21, 21, 21, 21, 21}, - .light = {54, 197, 244, TORCH_INTENSITY}, }, [BLOCK_MAGENTA_TORCH] = { + .light = {0, 0, 0, 250, 110, 121, 15}, .is_opaque = true, - .is_sprite = true, .is_solid = false, - .has_occlusion = false, - .has_shadow = false, + .is_sprite = true, + .use_ao = false, + .use_sun_normal = true, + .sun_intensity = 0.55f, .indices = {22, 22, 22, 22, 22, 22}, - .light = {250, 110, 121, TORCH_INTENSITY}, }, [BLOCK_WHITE_TORCH] = { + .light = {0, 0, 0, 255, 255, 255, 15}, .is_opaque = true, - .is_sprite = true, .is_solid = false, - .has_occlusion = false, - .has_shadow = false, + .is_sprite = true, + .use_ao = false, + .use_sun_normal = true, + .sun_intensity = 0.55f, .indices = {23, 23, 23, 23, 23, 23}, - .light = {255, 255, 255, TORCH_INTENSITY}, }, [BLOCK_PLANKS] = { + .light = {0}, .is_opaque = true, - .is_sprite = false, .is_solid = true, - .has_occlusion = true, - .has_shadow = true, - .indices = {24, 24, 24, 24, 24, 24}, - .light = {0, 0, 0, 0}, - }, - [BLOCK_GLASS] = - { - .is_opaque = false, .is_sprite = false, - .is_solid = true, - .has_occlusion = false, - .has_shadow = false, - .indices = {25, 25, 25, 25, 25, 25}, - .light = {0, 0, 0, 0}, + .use_ao = true, + .use_sun_normal = true, + .sun_intensity = 0.55f, + .indices = {24, 24, 24, 24, 24, 24}, }, }; -bool block_is_opaque(block_t block) +SDL_GPUBuffer* Block_GetBuffer(SDL_GPUDevice* device) { - return BLOCKS[block].is_opaque; + SDL_COMPILE_TIME_ASSERT("", sizeof(Light) == sizeof(Uint32) * 4); + SDL_COMPILE_TIME_ASSERT("", sizeof(BlockData) == sizeof(Uint32) * 16); + CPUBuffer cpu_blocks; + GPUBuffer gpu_blocks; + CPUBuffer_Init(&cpu_blocks, device, sizeof(BlockData)); + GPUBuffer_Init(&gpu_blocks, device, SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ); + if (!GPUBuffer_BeginUpload(&gpu_blocks)) + { + CPUBuffer_Free(&cpu_blocks); + GPUBuffer_Free(&gpu_blocks); + return NULL; + } + for (int block_index = 0; block_index < BLOCK_COUNT; block_index++) + { + CPUBuffer_Append(&cpu_blocks, &BLOCKS[block_index]); + } + if (!GPUBuffer_Upload(&gpu_blocks, &cpu_blocks)) + { + GPUBuffer_EndUpload(); + CPUBuffer_Free(&cpu_blocks); + GPUBuffer_Free(&gpu_blocks); + return NULL; + } + GPUBuffer_EndUpload(); + SDL_GPUBuffer* buffer = gpu_blocks.buffer; + gpu_blocks.buffer = NULL; + CPUBuffer_Free(&cpu_blocks); + GPUBuffer_Free(&gpu_blocks); + return buffer; } -bool block_is_sprite(block_t block) +bool Block_IsOpaque(Block block) { - return BLOCKS[block].is_sprite; + return BLOCKS[block].is_opaque; } -bool block_is_solid(block_t block) +bool Block_IsSolid(Block block) { return BLOCKS[block].is_solid; } -bool block_has_occlusion(block_t block) +bool Block_IsSprite(Block block) { - return BLOCKS[block].has_occlusion; + return BLOCKS[block].is_sprite; } -bool block_has_shadow(block_t block) +bool Block_UseAO(Block block) { - return BLOCKS[block].has_shadow; + return BLOCKS[block].use_ao; } -int block_get_index(block_t block, direction_t direction) +int Block_GetIndex(Block block, Direction direction) { return BLOCKS[block].indices[direction]; } -bool block_is_light(block_t block) +bool Block_IsLight(Block block) { return BLOCKS[block].light.radius > 0; } -light_t block_get_light(block_t block) +Light Block_GetLight(Block block) { return BLOCKS[block].light; } diff --git a/src/block.h b/src/block.h index dd88e671..e0a2e7e5 100644 --- a/src/block.h +++ b/src/block.h @@ -4,8 +4,10 @@ #include "direction.h" -typedef Uint8 block_t; -enum // block_t +#define BLOCK_WIDTH 16 + +typedef Uint8 Block; +enum // Block { BLOCK_EMPTY, @@ -31,28 +33,26 @@ enum // block_t BLOCK_MAGENTA_TORCH, BLOCK_WHITE_TORCH, BLOCK_PLANKS, - BLOCK_GLASS, BLOCK_COUNT, }; -typedef struct light +typedef struct Light { + Sint32 x; + Sint32 y; + Sint32 z; Uint8 red; Uint8 green; Uint8 blue; Uint8 radius; - Sint32 x; - Sint32 y; - Sint32 z; -} -light_t; - -bool block_is_opaque(block_t block); -bool block_is_sprite(block_t block); -bool block_is_solid(block_t block); -bool block_has_occlusion(block_t block); -bool block_has_shadow(block_t block); -int block_get_index(block_t block, direction_t direction); -bool block_is_light(block_t block); -light_t block_get_light(block_t block); +} Light; + +SDL_GPUBuffer* Block_GetBuffer(SDL_GPUDevice* device); +bool Block_IsOpaque(Block block); +bool Block_IsSolid(Block block); +bool Block_IsSprite(Block block); +bool Block_UseAO(Block block); +int Block_GetIndex(Block block, Direction direction); +bool Block_IsLight(Block block); +Light Block_GetLight(Block block); diff --git a/src/buffer.c b/src/buffer.c index fda2e2ad..67346a6d 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -1,177 +1,171 @@ #include #include "buffer.h" -#include "check.h" -static _Thread_local SDL_GPUCommandBuffer* cbuf; -static _Thread_local SDL_GPUCopyPass* pass; +static _Thread_local SDL_GPUCommandBuffer* upload_command_buffer; +static _Thread_local SDL_GPUCopyPass* upload_copy_pass; -void cpu_buffer_init(cpu_buffer_t* cpu, SDL_GPUDevice* device, Uint32 stride) +void CPUBuffer_Init(CPUBuffer* buffer, SDL_GPUDevice* device, Uint32 stride) { - CHECK(stride); - cpu->device = device; - cpu->buffer = NULL; - cpu->data = NULL; - cpu->capacity = 0; - cpu->size = 0; - cpu->stride = stride; + SDL_assert(stride); + buffer->device = device; + buffer->buffer = NULL; + buffer->data = NULL; + buffer->capacity = 0; + buffer->size = 0; + buffer->stride = stride; } -void cpu_buffer_free(cpu_buffer_t* cpu) +void CPUBuffer_Free(CPUBuffer* buffer) { - SDL_ReleaseGPUTransferBuffer(cpu->device, cpu->buffer); - cpu->device = NULL; - cpu->buffer = NULL; - cpu->data = NULL; - cpu->capacity = 0; - cpu->size = 0; - cpu->stride = 0; + SDL_ReleaseGPUTransferBuffer(buffer->device, buffer->buffer); + buffer->device = NULL; + buffer->buffer = NULL; + buffer->data = NULL; + buffer->capacity = 0; + buffer->size = 0; + buffer->stride = 0; } -void cpu_buffer_append(cpu_buffer_t* cpu, void* item) +void CPUBuffer_Append(CPUBuffer* buffer, const void* item) { - if (!cpu->data && cpu->buffer) + if (!buffer->data && buffer->buffer) { - CHECK(!cpu->size); - cpu->data = SDL_MapGPUTransferBuffer(cpu->device, cpu->buffer, true); - if (!cpu->data) + SDL_assert(!buffer->size); + buffer->data = SDL_MapGPUTransferBuffer(buffer->device, buffer->buffer, true); + if (!buffer->data) { SDL_Log("Failed to map transfer buffer: %s", SDL_GetError()); return; } } - CHECK(cpu->size <= cpu->capacity); - if (cpu->size == cpu->capacity) + SDL_assert(buffer->size <= buffer->capacity); + if (buffer->size == buffer->capacity) { - int capacity = SDL_max(64, cpu->size * 2); + int capacity = SDL_max(64, buffer->size * 2); SDL_GPUTransferBufferCreateInfo info = {0}; info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; - info.size = capacity * cpu->stride; - SDL_GPUTransferBuffer* buffer = SDL_CreateGPUTransferBuffer(cpu->device, &info); - if (!buffer) + info.size = capacity * buffer->stride; + SDL_GPUTransferBuffer* transfer_buffer = SDL_CreateGPUTransferBuffer(buffer->device, &info); + if (!transfer_buffer) { SDL_Log("Failed to create transfer buffer: %s", SDL_GetError()); return; } - void* data = SDL_MapGPUTransferBuffer(cpu->device, buffer, false); + void* data = SDL_MapGPUTransferBuffer(buffer->device, transfer_buffer, false); if (!data) { SDL_Log("Failed to map transfer buffer: %s", SDL_GetError()); - SDL_ReleaseGPUTransferBuffer(cpu->device, buffer); + SDL_ReleaseGPUTransferBuffer(buffer->device, transfer_buffer); return; } - if (cpu->data) + if (buffer->data) { - SDL_memcpy(data, cpu->data, cpu->size * cpu->stride); - SDL_UnmapGPUTransferBuffer(cpu->device, cpu->buffer); + SDL_memcpy(data, buffer->data, buffer->size * buffer->stride); + SDL_UnmapGPUTransferBuffer(buffer->device, buffer->buffer); } - SDL_ReleaseGPUTransferBuffer(cpu->device, cpu->buffer); - cpu->capacity = capacity; - cpu->buffer = buffer; - cpu->data = data; + SDL_ReleaseGPUTransferBuffer(buffer->device, buffer->buffer); + buffer->capacity = capacity; + buffer->buffer = transfer_buffer; + buffer->data = data; } - CHECK(cpu->data); - SDL_memcpy(cpu->data + cpu->size * cpu->stride, item, cpu->stride); - cpu->size++; + SDL_assert(buffer->data); + SDL_memcpy((Uint8*)buffer->data + buffer->size * buffer->stride, item, buffer->stride); + buffer->size++; } -void cpu_buffer_clear(cpu_buffer_t* cpu) +void GPUBuffer_Init(GPUBuffer* buffer, SDL_GPUDevice* device, SDL_GPUBufferUsageFlags usage) { - cpu->size = 0; + buffer->device = device; + buffer->usage = usage; + buffer->buffer = NULL; + buffer->capacity = 0; + buffer->size = 0; } -void gpu_buffer_init(gpu_buffer_t* gpu, SDL_GPUDevice* device, SDL_GPUBufferUsageFlags usage) +void GPUBuffer_Free(GPUBuffer* buffer) { - gpu->device = device; - gpu->usage = usage; - gpu->buffer = NULL; - gpu->capacity = 0; - gpu->size = 0; + SDL_ReleaseGPUBuffer(buffer->device, buffer->buffer); + buffer->usage = 0; + buffer->buffer = NULL; + buffer->capacity = 0; + buffer->size = 0; } -void gpu_buffer_free(gpu_buffer_t* gpu) +bool GPUBuffer_Upload(GPUBuffer* destination, CPUBuffer* source) { - SDL_ReleaseGPUBuffer(gpu->device, gpu->buffer); - gpu->usage = 0; - gpu->buffer = NULL; - gpu->capacity = 0; - gpu->size = 0; -} - -void gpu_buffer_upload(gpu_buffer_t* gpu, cpu_buffer_t* cpu) -{ - CHECK(cbuf); - CHECK(pass); - gpu->size = 0; - if (cpu->data) + SDL_assert(upload_command_buffer); + SDL_assert(upload_copy_pass); + destination->size = 0; + if (source->data) { - SDL_UnmapGPUTransferBuffer(gpu->device, cpu->buffer); - cpu->data = NULL; + SDL_UnmapGPUTransferBuffer(destination->device, source->buffer); + source->data = NULL; } - if (!cpu->size) + if (!source->size) { - gpu->size = 0; - return; + return true; } - Uint32 size = cpu->size; - cpu->size = 0; - if (size > gpu->size) + Uint32 size = source->size; + source->size = 0; + if (size > destination->capacity) { - SDL_ReleaseGPUBuffer(gpu->device, gpu->buffer); - gpu->buffer = NULL; - gpu->capacity = 0; + SDL_ReleaseGPUBuffer(destination->device, destination->buffer); + destination->buffer = NULL; + destination->capacity = 0; SDL_GPUBufferCreateInfo info = {0}; - info.usage = gpu->usage; - info.size = cpu->capacity * cpu->stride; - gpu->buffer = SDL_CreateGPUBuffer(gpu->device, &info); - if (!gpu->buffer) + info.usage = destination->usage; + info.size = source->capacity * source->stride; + destination->buffer = SDL_CreateGPUBuffer(destination->device, &info); + if (!destination->buffer) { SDL_Log("Failed to create buffer: %s", SDL_GetError()); - return; + return false; } - gpu->capacity = cpu->capacity; + destination->capacity = source->capacity; } SDL_GPUTransferBufferLocation location = {0}; SDL_GPUBufferRegion region = {0}; - location.transfer_buffer = cpu->buffer; - region.buffer = gpu->buffer; - region.size = size * cpu->stride; - SDL_UploadToGPUBuffer(pass, &location, ®ion, true); - gpu->size = size; + location.transfer_buffer = source->buffer; + region.buffer = destination->buffer; + region.size = size * source->stride; + SDL_UploadToGPUBuffer(upload_copy_pass, &location, ®ion, true); + destination->size = size; + return true; } -void gpu_buffer_clear(gpu_buffer_t* gpu) +void GPUBuffer_Clear(GPUBuffer* buffer) { - gpu->size = 0; + buffer->size = 0; } -bool gpu_buffer_begin_upload(gpu_buffer_t* gpu) +bool GPUBuffer_BeginUpload(GPUBuffer* buffer) { - CHECK(!cbuf); - CHECK(!pass); - cbuf = SDL_AcquireGPUCommandBuffer(gpu->device); - if (!cbuf) + SDL_assert(!upload_command_buffer); + SDL_assert(!upload_copy_pass); + upload_command_buffer = SDL_AcquireGPUCommandBuffer(buffer->device); + if (!upload_command_buffer) { SDL_Log("Failed to acquire command buffer: %s", SDL_GetError()); return false; } - pass = SDL_BeginGPUCopyPass(cbuf); - if (!pass) + upload_copy_pass = SDL_BeginGPUCopyPass(upload_command_buffer); + if (!upload_copy_pass) { SDL_Log("Failed to begin copy pass: %s", SDL_GetError()); - SDL_CancelGPUCommandBuffer(cbuf); - cbuf = NULL; + SDL_CancelGPUCommandBuffer(upload_command_buffer); + upload_command_buffer = NULL; return false; } return true; } -void gpu_buffer_end_upload(gpu_buffer_t* gpu) +void GPUBuffer_EndUpload() { - CHECK(pass); - CHECK(cbuf); - SDL_EndGPUCopyPass(pass); - SDL_SubmitGPUCommandBuffer(cbuf); - pass = NULL; - cbuf = NULL; + SDL_assert(upload_copy_pass); + SDL_assert(upload_command_buffer); + SDL_EndGPUCopyPass(upload_copy_pass); + SDL_SubmitGPUCommandBuffer(upload_command_buffer); + upload_copy_pass = NULL; + upload_command_buffer = NULL; } diff --git a/src/buffer.h b/src/buffer.h index ad961bc1..5534ca08 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -2,7 +2,7 @@ #include -typedef struct cpu_buffer +typedef struct CPUBuffer { SDL_GPUDevice* device; SDL_GPUTransferBuffer* buffer; @@ -10,27 +10,24 @@ typedef struct cpu_buffer Uint32 size; Uint32 capacity; Uint32 stride; -} -cpu_buffer_t; +} CPUBuffer; -void cpu_buffer_init(cpu_buffer_t* cpu, SDL_GPUDevice* device, Uint32 stride); -void cpu_buffer_free(cpu_buffer_t* cpu); -void cpu_buffer_append(cpu_buffer_t* cpu, void* item); -void cpu_buffer_clear(cpu_buffer_t* cpu); +void CPUBuffer_Init(CPUBuffer* buffer, SDL_GPUDevice* device, Uint32 stride); +void CPUBuffer_Free(CPUBuffer* buffer); +void CPUBuffer_Append(CPUBuffer* buffer, const void* item); -typedef struct gpu_buffer +typedef struct GPUBuffer { SDL_GPUDevice* device; SDL_GPUBufferUsageFlags usage; SDL_GPUBuffer* buffer; Uint32 size; Uint32 capacity; -} -gpu_buffer_t; +} GPUBuffer; -void gpu_buffer_init(gpu_buffer_t* gpu, SDL_GPUDevice* device, SDL_GPUBufferUsageFlags usage); -void gpu_buffer_free(gpu_buffer_t* gpu); -void gpu_buffer_upload(gpu_buffer_t* gpu, cpu_buffer_t* cpu); -void gpu_buffer_clear(gpu_buffer_t* gpu); -bool gpu_buffer_begin_upload(gpu_buffer_t* gpu); -void gpu_buffer_end_upload(gpu_buffer_t* gpu); +void GPUBuffer_Init(GPUBuffer* buffer, SDL_GPUDevice* device, SDL_GPUBufferUsageFlags usage); +void GPUBuffer_Free(GPUBuffer* buffer); +bool GPUBuffer_Upload(GPUBuffer* destination, CPUBuffer* source); +void GPUBuffer_Clear(GPUBuffer* buffer); +bool GPUBuffer_BeginUpload(GPUBuffer* buffer); +void GPUBuffer_EndUpload(); diff --git a/src/camera.c b/src/camera.c index 369dd92e..26d7264b 100644 --- a/src/camera.c +++ b/src/camera.c @@ -1,21 +1,20 @@ #include #include "camera.h" -#include "check.h" #define DEGREES(rad) ((rad) * 180.0f / SDL_PI_F) #define RADIANS(deg) ((deg) * SDL_PI_F / 180.0f) -static void multiply(float matrix[4][4], float a[4][4], float b[4][4]) +static void Multiply(float matrix[4][4], float lhs[4][4], float rhs[4][4]) { float c[4][4] = {0}; for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) { - c[i][j] += a[0][j] * b[i][0]; - c[i][j] += a[1][j] * b[i][1]; - c[i][j] += a[2][j] * b[i][2]; - c[i][j] += a[3][j] * b[i][3]; + c[i][j] += lhs[0][j] * rhs[i][0]; + c[i][j] += lhs[1][j] * rhs[i][1]; + c[i][j] += lhs[2][j] * rhs[i][2]; + c[i][j] += lhs[3][j] * rhs[i][3]; } for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) @@ -24,7 +23,7 @@ static void multiply(float matrix[4][4], float a[4][4], float b[4][4]) } } -static void perspective(float matrix[4][4], float aspect, float fov, float near, float far) +static void Perspective(float matrix[4][4], float aspect, float fov, float near, float far) { matrix[0][0] = (1.0f / SDL_tanf(fov / 2.0f)) / aspect; matrix[0][1] = 0.0f; @@ -42,7 +41,7 @@ static void perspective(float matrix[4][4], float aspect, float fov, float near, matrix[3][3] = 0.0f; } -static void ortho(float matrix[4][4], float left, float right, float bottom, float top, float near, float far) +static void Ortho(float matrix[4][4], float left, float right, float bottom, float top, float near, float far) { matrix[0][0] = 2.0f / (right - left); matrix[0][1] = 0.0f; @@ -62,7 +61,7 @@ static void ortho(float matrix[4][4], float left, float right, float bottom, flo matrix[3][3] = 1.0f; } -static void translate(float matrix[4][4], float x, float y, float z) +static void Translate(float matrix[4][4], float x, float y, float z) { matrix[0][0] = 1.0f; matrix[0][1] = 0.0f; @@ -82,33 +81,33 @@ static void translate(float matrix[4][4], float x, float y, float z) matrix[3][3] = 1.0f; } -static void frustum(float planes[6][4], float a[4][4]) +static void Frustum(float planes[6][4], float matrix[4][4]) { - planes[0][0] = a[0][3] + a[0][0]; - planes[0][1] = a[1][3] + a[1][0]; - planes[0][2] = a[2][3] + a[2][0]; - planes[0][3] = a[3][3] + a[3][0]; - planes[1][0] = a[0][3] - a[0][0]; - planes[1][1] = a[1][3] - a[1][0]; - planes[1][2] = a[2][3] - a[2][0]; - planes[1][3] = a[3][3] - a[3][0]; - planes[2][0] = a[0][3] + a[0][1]; - planes[2][1] = a[1][3] + a[1][1]; - planes[2][2] = a[2][3] + a[2][1]; - planes[2][3] = a[3][3] + a[3][1]; - planes[3][0] = a[0][3] - a[0][1]; - planes[3][1] = a[1][3] - a[1][1]; - planes[3][2] = a[2][3] - a[2][1]; - planes[3][3] = a[3][3] - a[3][1]; - planes[4][0] = a[0][2]; - planes[4][1] = a[1][2]; - planes[4][2] = a[2][2]; - planes[4][3] = a[3][2]; - planes[5][0] = a[0][3] - a[0][2]; - planes[5][1] = a[1][3] - a[1][2]; - planes[5][2] = a[2][3] - a[2][2]; - planes[5][3] = a[3][3] - a[3][2]; - for (int i = 0; i < 6; ++i) + planes[0][0] = matrix[0][3] + matrix[0][0]; + planes[0][1] = matrix[1][3] + matrix[1][0]; + planes[0][2] = matrix[2][3] + matrix[2][0]; + planes[0][3] = matrix[3][3] + matrix[3][0]; + planes[1][0] = matrix[0][3] - matrix[0][0]; + planes[1][1] = matrix[1][3] - matrix[1][0]; + planes[1][2] = matrix[2][3] - matrix[2][0]; + planes[1][3] = matrix[3][3] - matrix[3][0]; + planes[2][0] = matrix[0][3] + matrix[0][1]; + planes[2][1] = matrix[1][3] + matrix[1][1]; + planes[2][2] = matrix[2][3] + matrix[2][1]; + planes[2][3] = matrix[3][3] + matrix[3][1]; + planes[3][0] = matrix[0][3] - matrix[0][1]; + planes[3][1] = matrix[1][3] - matrix[1][1]; + planes[3][2] = matrix[2][3] - matrix[2][1]; + planes[3][3] = matrix[3][3] - matrix[3][1]; + planes[4][0] = matrix[0][2]; + planes[4][1] = matrix[1][2]; + planes[4][2] = matrix[2][2]; + planes[4][3] = matrix[3][2]; + planes[5][0] = matrix[0][3] - matrix[0][2]; + planes[5][1] = matrix[1][3] - matrix[1][2]; + planes[5][2] = matrix[2][3] - matrix[2][2]; + planes[5][3] = matrix[3][3] - matrix[3][2]; + for (int i = 0; i < 6; i++) { float length = 0.0f; length += planes[i][0] * planes[i][0]; @@ -126,7 +125,7 @@ static void frustum(float planes[6][4], float a[4][4]) } } -static void rotate(float matrix[4][4], float x, float y, float z, float angle) +static void Rotate(float matrix[4][4], float x, float y, float z, float angle) { float s = SDL_sinf(angle); float c = SDL_cosf(angle); @@ -149,7 +148,7 @@ static void rotate(float matrix[4][4], float x, float y, float z, float angle) matrix[3][3] = 1.0f; } -void camera_init(camera_t* camera, camera_type_t type) +void Camera_Init(Camera* camera, CameraType type) { camera->type = type; camera->x = 0.0f; @@ -165,51 +164,52 @@ void camera_init(camera_t* camera, camera_type_t type) camera->ortho = 100.0f; } -void camera_update(camera_t* camera) +void Camera_Update(Camera* camera) { - float s = SDL_sinf(camera->yaw); - float c = SDL_cosf(camera->yaw); - translate(camera->view, -camera->x, -camera->y, -camera->z); - rotate(camera->proj, c, 0.0f, s, camera->pitch); - multiply(camera->view, camera->proj, camera->view); - rotate(camera->proj, 0.0f, 1.0f, 0.0f, -camera->yaw); - multiply(camera->view, camera->proj, camera->view); + float sy = SDL_sinf(camera->yaw); + float cy = SDL_cosf(camera->yaw); + float rotation[4][4]; + Translate(camera->view, -camera->x, -camera->y, -camera->z); + Rotate(rotation, cy, 0.0f, sy, camera->pitch); + Multiply(camera->view, rotation, camera->view); + Rotate(rotation, 0.0f, 1.0f, 0.0f, -camera->yaw); + Multiply(camera->view, rotation, camera->view); float aspect = (float) camera->width / camera->height; if (camera->type == CAMERA_TYPE_PERSPECTIVE) { - perspective(camera->proj, aspect, camera->fov, camera->near, camera->far); + Perspective(camera->proj, aspect, camera->fov, camera->near, camera->far); } else { float ox = camera->ortho * aspect; float oy = camera->ortho; - ortho(camera->proj, -ox, ox, -oy, oy, -camera->far, camera->far); + Ortho(camera->proj, -ox, ox, -oy, oy, -camera->far, camera->far); } - multiply(camera->matrix, camera->proj, camera->view); - frustum(camera->planes, camera->matrix); + Multiply(camera->matrix, camera->proj, camera->view); + Frustum(camera->planes, camera->matrix); } -void camera_move(camera_t* camera, float x, float y, float z) +void Camera_Move(Camera* camera, float right, float up, float forward) { float sy = SDL_sinf(camera->yaw); float cy = SDL_cosf(camera->yaw); float sp = SDL_sinf(camera->pitch); float cp = SDL_cosf(camera->pitch); - camera->x += cp * (sy * z) + cy * x; - camera->y += y + z * sp; - camera->z -= cp * (cy * z) - sy * x; + camera->x += cp * sy * forward + cy * right; + camera->y += up + forward * sp; + camera->z -= cp * cy * forward - sy * right; camera->y = SDL_clamp(camera->y, -camera->far, camera->far); } -void camera_resize(camera_t* camera, int width, int height) +void Camera_Resize(Camera* camera, int width, int height) { - CHECK(width > 0.0f); - CHECK(height > 0.0f); + SDL_assert(width > 0.0f); + SDL_assert(height > 0.0f); camera->width = width; camera->height = height; } -void camera_rotate(camera_t* camera, float pitch, float yaw) +void Camera_Rotate(Camera* camera, float pitch, float yaw) { static const float PITCH = SDL_PI_F / 2.0f - SDL_FLT_EPSILON; camera->pitch += RADIANS(pitch); @@ -217,26 +217,26 @@ void camera_rotate(camera_t* camera, float pitch, float yaw) camera->pitch = SDL_clamp(camera->pitch, -PITCH, PITCH); } -void camera_get_vector(const camera_t* camera, float* x, float* y, float* z) +void Camera_GetVector(const Camera* camera, float* x, float* y, float* z) { - float c = SDL_cosf(camera->pitch); - *x = SDL_cosf(camera->yaw - RADIANS(90.0f)) * c; + float cp = SDL_cosf(camera->pitch); + *x = SDL_cosf(camera->yaw - RADIANS(90.0f)) * cp; *y = SDL_sinf(camera->pitch); - *z = SDL_sinf(camera->yaw - RADIANS(90.0f)) * c; + *z = SDL_sinf(camera->yaw - RADIANS(90.0f)) * cp; } -bool camera_get_vis(const camera_t* camera, float x, float y, float z, float sx, float sy, float sz) +bool Camera_IsVisible(const Camera* camera, float x, float y, float z, float width, float height, float depth) { - float x2 = x + sx; - float y2 = y + sy; - float z2 = z + sz; - for (int i = 0; i < 6; ++i) + float max_x = x + width; + float max_y = y + height; + float max_z = z + depth; + for (int i = 0; i < 6; i++) { - const float *plane = camera->planes[i]; - float a = plane[0] >= 0.0f ? x2 : x; - float b = plane[1] >= 0.0f ? y2 : y; - float c = plane[2] >= 0.0f ? z2 : z; - if (plane[0] * a + plane[1] * b + plane[2] * c + plane[3] < 0.0f) + const float* plane = camera->planes[i]; + float point_x = plane[0] >= 0.0f ? max_x : x; + float point_y = plane[1] >= 0.0f ? max_y : y; + float point_z = plane[2] >= 0.0f ? max_z : z; + if (plane[0] * point_x + plane[1] * point_y + plane[2] * point_z + plane[3] < 0.0f) { return false; } diff --git a/src/camera.h b/src/camera.h index 4f8e704f..1576cdf6 100644 --- a/src/camera.h +++ b/src/camera.h @@ -2,17 +2,15 @@ #include -typedef enum camera_type +typedef enum CameraType { CAMERA_TYPE_ORTHO, CAMERA_TYPE_PERSPECTIVE, - CAMERA_TYPE_COUNT, -} -camera_type_t; +} CameraType; -typedef struct camera +typedef struct Camera { - camera_type_t type; + CameraType type; float view[4][4]; float proj[4][4]; float matrix[4][4]; @@ -42,13 +40,12 @@ typedef struct camera float near; float far; float ortho; -} -camera_t; +} Camera; -void camera_init(camera_t* camera, camera_type_t type); -void camera_update(camera_t* camera); -void camera_move(camera_t* camera, float x, float y, float z); -void camera_resize(camera_t* camera, int width, int height); -void camera_rotate(camera_t* camera, float pitch, float yaw); -void camera_get_vector(const camera_t* camera, float* x, float* y, float* z); -bool camera_get_vis(const camera_t* camera, float x, float y, float z, float sx, float sy, float sz); +void Camera_Init(Camera* camera, CameraType type); +void Camera_Update(Camera* camera); +void Camera_Move(Camera* camera, float right, float up, float forward); +void Camera_Resize(Camera* camera, int width, int height); +void Camera_Rotate(Camera* camera, float pitch, float yaw); +void Camera_GetVector(const Camera* camera, float* x, float* y, float* z); +bool Camera_IsVisible(const Camera* camera, float x, float y, float z, float width, float height, float depth); diff --git a/src/check.h b/src/check.h deleted file mode 100644 index 93f095e3..00000000 --- a/src/check.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include - -#ifndef NDEBUG -#define CHECK(x) SDL_assert_always(x) -#else -#define CHECK(x) -#endif diff --git a/src/direction.h b/src/direction.h index 5ffc7a48..782e9c00 100644 --- a/src/direction.h +++ b/src/direction.h @@ -1,6 +1,6 @@ #pragma once -typedef enum direction +typedef enum Direction { DIRECTION_NORTH, DIRECTION_SOUTH, @@ -9,8 +9,7 @@ typedef enum direction DIRECTION_UP, DIRECTION_DOWN, DIRECTION_COUNT, -} -direction_t; +} Direction; static const int DIRECTIONS[DIRECTION_COUNT][3] = { diff --git a/src/main.c b/src/main.c index 784ebb8e..b8e07f1b 100644 --- a/src/main.c +++ b/src/main.c @@ -2,24 +2,17 @@ #include #include +#include "block.h" #include "camera.h" -#include "check.h" #include "player.h" #include "save.h" #include "shader.h" +#include "sky.h" #include "world.h" static const char* SAVE_PATH = "blocks.sqlite3"; -static const int PLAYER_ID = 0; -static const float ATLAS_WIDTH = 512.0f; -static const int ATLAS_MIP_LEVELS = 4; -static const float BLOCK_WIDTH = 16.0f; -static const int SHADOW_RESOLUTION = 4096.0f; -static const float SHADOW_Y = 30.0f; -static const float SHADOW_ORTHO = 300.0f; -static const float SHADOW_FAR = 300.0f; -static const float SHADOW_PITCH = -45.0f; -static const float SHADOW_YAW = 45.0f; +static const int MIP_LEVELS = 4; +static const SDL_GPUSampleCount SAMPLE_COUNT = SDL_GPU_SAMPLECOUNT_4; static SDL_Window* window; static SDL_GPUDevice* device; @@ -27,35 +20,24 @@ static SDL_GPUTextureFormat color_format; static SDL_GPUTextureFormat depth_format; static SDL_GPUGraphicsPipeline* opaque_pipeline; static SDL_GPUGraphicsPipeline* transparent_pipeline; -static SDL_GPUGraphicsPipeline* depth_pipeline; -static SDL_GPUGraphicsPipeline* shadow_pipeline; static SDL_GPUGraphicsPipeline* sky_pipeline; static SDL_GPUGraphicsPipeline* raycast_pipeline; -static SDL_GPUComputePipeline* ui_pipeline; -static SDL_GPUComputePipeline* ssao_pipeline; -static SDL_GPUComputePipeline* composite_pipeline; -static SDL_GPUComputePipeline* blur_pipeline; +static SDL_GPUGraphicsPipeline* hud_pipeline; static SDL_Surface* atlas_surface; static SDL_GPUTexture* atlas_texture; static SDL_GPUTexture* depth_texture; -static SDL_GPUTexture* color_texture; static SDL_GPUTexture* position_texture; -static SDL_GPUTexture* light_texture; -static SDL_GPUTexture* voxel_texture; -static SDL_GPUTexture* ssao_texture; -static SDL_GPUTexture* blur_texture; -static SDL_GPUTexture* composite_texture; -static SDL_GPUTexture* shadow_texture; -static SDL_GPUSampler* linear_sampler; +static SDL_GPUTexture* msaa_color_texture; +static SDL_GPUTexture* msaa_position_texture; +static SDL_GPUBuffer* block_buffer; static SDL_GPUSampler* nearest_sampler; -static camera_t shadow_camera; -static player_t player; +static Sky sky; +static Player player; static Uint64 ticks1; -static Uint64 ticks2; -static bool create_atlas() +static bool CreateAtlas() { - char path[512] = {0}; + char path[1024] = {0}; SDL_snprintf(path, sizeof(path), "%satlas.png", SDL_GetBasePath()); atlas_surface = SDL_LoadPNG(path); if (!atlas_surface) @@ -63,14 +45,14 @@ static bool create_atlas() SDL_Log("Failed to create atlas surface: %s", SDL_GetError()); return false; } - SDL_GPUTexture* texture = NULL; - SDL_GPUTransferBuffer* buffer = NULL; + SDL_GPUTexture* source_texture = NULL; + SDL_GPUTransferBuffer* transfer_buffer = NULL; { SDL_GPUTextureCreateInfo info = {0}; info.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM; info.type = SDL_GPU_TEXTURETYPE_2D_ARRAY; - info.layer_count_or_depth = ATLAS_WIDTH / BLOCK_WIDTH; - info.num_levels = ATLAS_MIP_LEVELS; + info.layer_count_or_depth = atlas_surface->w / BLOCK_WIDTH; + info.num_levels = MIP_LEVELS; info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER | SDL_GPU_TEXTUREUSAGE_COLOR_TARGET; info.width = BLOCK_WIDTH; info.height = BLOCK_WIDTH; @@ -86,8 +68,8 @@ static bool create_atlas() info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER; info.width = atlas_surface->w; info.height = atlas_surface->h; - texture = SDL_CreateGPUTexture(device, &info); - if (!texture) + source_texture = SDL_CreateGPUTexture(device, &info); + if (!source_texture) { SDL_Log("Failed to create texture: %s", SDL_GetError()); return false; @@ -97,47 +79,47 @@ static bool create_atlas() SDL_GPUTransferBufferCreateInfo info = {0}; info.size = atlas_surface->w * atlas_surface->h * 4; info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; - buffer = SDL_CreateGPUTransferBuffer(device, &info); - if (!buffer) + transfer_buffer = SDL_CreateGPUTransferBuffer(device, &info); + if (!transfer_buffer) { SDL_Log("Failed to create transfer buffer: %s", SDL_GetError()); return false; } } - void* data = SDL_MapGPUTransferBuffer(device, buffer, 0); - if (!data) + void* pixels = SDL_MapGPUTransferBuffer(device, transfer_buffer, false); + if (!pixels) { SDL_Log("Failed to map transfer buffer: %s", SDL_GetError()); return false; } - SDL_memcpy(data, atlas_surface->pixels, atlas_surface->w * atlas_surface->h * 4); - SDL_UnmapGPUTransferBuffer(device, buffer); - SDL_GPUCommandBuffer* cbuf = SDL_AcquireGPUCommandBuffer(device); - if (!cbuf) + SDL_memcpy(pixels, atlas_surface->pixels, atlas_surface->w * atlas_surface->h * 4); + SDL_UnmapGPUTransferBuffer(device, transfer_buffer); + SDL_GPUCommandBuffer* command_buffer = SDL_AcquireGPUCommandBuffer(device); + if (!command_buffer) { SDL_Log("Failed to acquire command buffer: %s", SDL_GetError()); return false; } - SDL_GPUCopyPass* pass = SDL_BeginGPUCopyPass(cbuf); - if (!pass) + SDL_GPUCopyPass* copy_pass = SDL_BeginGPUCopyPass(command_buffer); + if (!copy_pass) { SDL_Log("Failed to begin copy pass: %s", SDL_GetError()); return false; } - SDL_GPUTextureTransferInfo info = {0}; + SDL_GPUTextureTransferInfo transfer_info = {0}; SDL_GPUTextureRegion region = {0}; - info.transfer_buffer = buffer; - region.texture = texture; + transfer_info.transfer_buffer = transfer_buffer; + region.texture = source_texture; region.w = atlas_surface->w; region.h = atlas_surface->h; region.d = 1; - SDL_UploadToGPUTexture(pass, &info, ®ion, 0); - SDL_EndGPUCopyPass(pass); - for (int i = 0; i < ATLAS_WIDTH / BLOCK_WIDTH; i++) + SDL_UploadToGPUTexture(copy_pass, &transfer_info, ®ion, false); + SDL_EndGPUCopyPass(copy_pass); + for (int layer = 0; layer < atlas_surface->w / BLOCK_WIDTH; layer++) { SDL_GPUBlitInfo info = {0}; - info.source.texture = texture; - info.source.x = i * BLOCK_WIDTH; + info.source.texture = source_texture; + info.source.x = layer * BLOCK_WIDTH; info.source.y = 0; info.source.w = BLOCK_WIDTH; info.source.h = BLOCK_WIDTH; @@ -146,42 +128,36 @@ static bool create_atlas() info.destination.y = 0; info.destination.w = BLOCK_WIDTH; info.destination.h = BLOCK_WIDTH; - info.destination.layer_or_depth_plane = i; - SDL_BlitGPUTexture(cbuf, &info); + info.destination.layer_or_depth_plane = layer; + SDL_BlitGPUTexture(command_buffer, &info); } - if (ATLAS_MIP_LEVELS > 1) + if (MIP_LEVELS > 1) { - SDL_GenerateMipmapsForGPUTexture(cbuf, atlas_texture); + SDL_GenerateMipmapsForGPUTexture(command_buffer, atlas_texture); } - SDL_SubmitGPUCommandBuffer(cbuf); - SDL_ReleaseGPUTexture(device, texture); - SDL_ReleaseGPUTransferBuffer(device, buffer); + SDL_SubmitGPUCommandBuffer(command_buffer); + SDL_ReleaseGPUTexture(device, source_texture); + SDL_ReleaseGPUTransferBuffer(device, transfer_buffer); return true; } -static void set_window_icon(block_t block) +static void SetWindowIcon() { - if (!atlas_surface) - { - return; - } + SDL_assert(atlas_surface); SDL_Surface* icon = SDL_CreateSurface(BLOCK_WIDTH, BLOCK_WIDTH, SDL_PIXELFORMAT_RGBA32); if (!icon) { SDL_Log("Failed to create icon surface: %s", SDL_GetError()); return; } - SDL_Rect src; - src.x = block_get_index(block, DIRECTION_NORTH) * BLOCK_WIDTH; - src.y = 0; - src.w = BLOCK_WIDTH; - src.h = BLOCK_WIDTH; - SDL_Rect dst; - dst.x = 0; - dst.y = 0; - dst.w = BLOCK_WIDTH; - dst.h = BLOCK_WIDTH; - if (!SDL_BlitSurface(atlas_surface, &src, icon, &dst)) + SDL_Rect source = {0}; + source.x = Block_GetIndex(BLOCK_GRASS, DIRECTION_NORTH) * BLOCK_WIDTH; + source.w = BLOCK_WIDTH; + source.h = BLOCK_WIDTH; + SDL_Rect destination = {0}; + destination.w = BLOCK_WIDTH; + destination.h = BLOCK_WIDTH; + if (!SDL_BlitSurface(atlas_surface, &source, icon, &destination)) { SDL_Log("Failed to blit icon surface: %s", SDL_GetError()); SDL_DestroySurface(icon); @@ -191,21 +167,19 @@ static void set_window_icon(block_t block) SDL_DestroySurface(icon); } -static bool create_opaque_pipeline() +static bool CreateOpaquePipeline() { - SDL_GPUColorTargetDescription color_targets[4] = {0}; + SDL_GPUColorTargetDescription color_targets[2] = {0}; color_targets[0].format = color_format; color_targets[1].format = SDL_GPU_TEXTUREFORMAT_R32G32B32A32_FLOAT; - color_targets[2].format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM; - color_targets[3].format = SDL_GPU_TEXTUREFORMAT_R8_UINT; SDL_GPUVertexAttribute vertex_attributes[1] = {0}; SDL_GPUVertexBufferDescription vertex_buffers[1] = {0}; vertex_attributes[0].format = SDL_GPU_VERTEXELEMENTFORMAT_UINT; vertex_buffers[0].pitch = 4; SDL_GPUGraphicsPipelineCreateInfo info = {0}; - info.vertex_shader = shader_load(device, "opaque.vert"); - info.fragment_shader = shader_load(device, "opaque.frag"); - info.target_info.num_color_targets = 4; + info.vertex_shader = Shader_Load(device, "opaque.vert"); + info.fragment_shader = Shader_Load(device, "opaque.frag"); + info.target_info.num_color_targets = 2; info.target_info.color_target_descriptions = color_targets; info.target_info.has_depth_stencil_target = true; info.target_info.depth_stencil_format = depth_format; @@ -218,45 +192,14 @@ static bool create_opaque_pipeline() info.depth_stencil_state.compare_op = SDL_GPU_COMPAREOP_LESS; info.rasterizer_state.cull_mode = SDL_GPU_CULLMODE_BACK; info.rasterizer_state.front_face = SDL_GPU_FRONTFACE_CLOCKWISE; - if (info.vertex_shader && info.fragment_shader) - { - opaque_pipeline = SDL_CreateGPUGraphicsPipeline(device, &info); - } + info.multisample_state.sample_count = SAMPLE_COUNT; + opaque_pipeline = SDL_CreateGPUGraphicsPipeline(device, &info); SDL_ReleaseGPUShader(device, info.vertex_shader); SDL_ReleaseGPUShader(device, info.fragment_shader); return opaque_pipeline != NULL; } -static bool create_depth_pipeline() -{ - SDL_GPUVertexAttribute vertex_attributes[1] = {0}; - SDL_GPUVertexBufferDescription vertex_buffers[1] = {0}; - vertex_attributes[0].format = SDL_GPU_VERTEXELEMENTFORMAT_UINT; - vertex_buffers[0].pitch = 4; - SDL_GPUGraphicsPipelineCreateInfo info = {0}; - info.vertex_shader = shader_load(device, "depth.vert"); - info.fragment_shader = shader_load(device, "depth.frag"); - info.target_info.has_depth_stencil_target = true; - info.target_info.depth_stencil_format = depth_format; - info.vertex_input_state.num_vertex_attributes = 1; - info.vertex_input_state.vertex_attributes = vertex_attributes; - info.vertex_input_state.num_vertex_buffers = 1; - info.vertex_input_state.vertex_buffer_descriptions = vertex_buffers; - info.depth_stencil_state.enable_depth_test = true; - info.depth_stencil_state.enable_depth_write = true; - info.depth_stencil_state.compare_op = SDL_GPU_COMPAREOP_LESS; - info.rasterizer_state.cull_mode = SDL_GPU_CULLMODE_BACK; - info.rasterizer_state.front_face = SDL_GPU_FRONTFACE_CLOCKWISE; - if (info.vertex_shader && info.fragment_shader) - { - depth_pipeline = SDL_CreateGPUGraphicsPipeline(device, &info); - } - SDL_ReleaseGPUShader(device, info.vertex_shader); - SDL_ReleaseGPUShader(device, info.fragment_shader); - return depth_pipeline != NULL; -} - -static bool create_transparent_pipeline() +static bool CreateTransparentPipeline() { SDL_GPUColorTargetDescription color_targets[1] = {0}; color_targets[0].format = color_format; @@ -272,8 +215,8 @@ static bool create_transparent_pipeline() vertex_attributes[0].format = SDL_GPU_VERTEXELEMENTFORMAT_UINT; vertex_buffers[0].pitch = 4; SDL_GPUGraphicsPipelineCreateInfo info = {0}; - info.vertex_shader = shader_load(device, "transparent.vert"); - info.fragment_shader = shader_load(device, "transparent.frag"); + info.vertex_shader = Shader_Load(device, "transparent.vert"); + info.fragment_shader = Shader_Load(device, "transparent.frag"); info.target_info.num_color_targets = 1; info.target_info.color_target_descriptions = color_targets; info.target_info.has_depth_stencil_target = true; @@ -284,68 +227,33 @@ static bool create_transparent_pipeline() info.vertex_input_state.vertex_buffer_descriptions = vertex_buffers; info.depth_stencil_state.enable_depth_test = true; info.depth_stencil_state.compare_op = SDL_GPU_COMPAREOP_LESS_OR_EQUAL; - info.rasterizer_state.cull_mode = SDL_GPU_CULLMODE_BACK; - info.rasterizer_state.front_face = SDL_GPU_FRONTFACE_CLOCKWISE; - if (info.vertex_shader && info.fragment_shader) - { - transparent_pipeline = SDL_CreateGPUGraphicsPipeline(device, &info); - } + info.multisample_state.sample_count = SAMPLE_COUNT; + transparent_pipeline = SDL_CreateGPUGraphicsPipeline(device, &info); SDL_ReleaseGPUShader(device, info.vertex_shader); SDL_ReleaseGPUShader(device, info.fragment_shader); return transparent_pipeline != NULL; } -static bool create_shadow_pipeline() +static bool CreateSkyPipeline() { - SDL_GPUVertexAttribute vertex_attributes[1] = {0}; - SDL_GPUVertexBufferDescription vertex_buffers[1] = {0}; - vertex_attributes[0].format = SDL_GPU_VERTEXELEMENTFORMAT_UINT; - vertex_buffers[0].pitch = 4; - SDL_GPUGraphicsPipelineCreateInfo info = {0}; - info.vertex_shader = shader_load(device, "shadow.vert"); - info.fragment_shader = shader_load(device, "shadow.frag"); - info.target_info.has_depth_stencil_target = true; - info.target_info.depth_stencil_format = depth_format; - info.vertex_input_state.num_vertex_attributes = 1; - info.vertex_input_state.vertex_attributes = vertex_attributes; - info.vertex_input_state.num_vertex_buffers = 1; - info.vertex_input_state.vertex_buffer_descriptions = vertex_buffers; - info.depth_stencil_state.enable_depth_test = true; - info.depth_stencil_state.enable_depth_write = true; - info.depth_stencil_state.compare_op = SDL_GPU_COMPAREOP_LESS; - if (info.vertex_shader && info.fragment_shader) - { - shadow_pipeline = SDL_CreateGPUGraphicsPipeline(device, &info); - } - SDL_ReleaseGPUShader(device, info.vertex_shader); - SDL_ReleaseGPUShader(device, info.fragment_shader); - return shadow_pipeline != NULL; -} - -static bool create_sky_pipeline() -{ - SDL_GPUColorTargetDescription color_targets[4] = {0}; + SDL_GPUColorTargetDescription color_targets[2] = {0}; color_targets[0].format = color_format; color_targets[1].format = SDL_GPU_TEXTUREFORMAT_R32G32B32A32_FLOAT; - color_targets[2].format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM; - color_targets[3].format = SDL_GPU_TEXTUREFORMAT_R8_UINT; SDL_GPUGraphicsPipelineCreateInfo info = {0}; - info.vertex_shader = shader_load(device, "sky.vert"); - info.fragment_shader = shader_load(device, "sky.frag"); - info.target_info.num_color_targets = 4; + info.vertex_shader = Shader_Load(device, "sky.vert"); + info.fragment_shader = Shader_Load(device, "sky.frag"); + info.target_info.num_color_targets = 2; info.target_info.color_target_descriptions = color_targets; info.target_info.has_depth_stencil_target = true; info.target_info.depth_stencil_format = depth_format; - if (info.vertex_shader && info.fragment_shader) - { - sky_pipeline = SDL_CreateGPUGraphicsPipeline(device, &info); - } + info.multisample_state.sample_count = SAMPLE_COUNT; + sky_pipeline = SDL_CreateGPUGraphicsPipeline(device, &info); SDL_ReleaseGPUShader(device, info.vertex_shader); SDL_ReleaseGPUShader(device, info.fragment_shader); return sky_pipeline != NULL; } -static bool create_raycast_pipeline() +static bool CreateRaycastPipeline() { SDL_GPUColorTargetDescription color_targets[1] = {0}; color_targets[0].format = color_format; @@ -357,38 +265,54 @@ static bool create_raycast_pipeline() color_targets[0].blend_state.color_blend_op = SDL_GPU_BLENDOP_ADD; color_targets[0].blend_state.alpha_blend_op = SDL_GPU_BLENDOP_ADD; SDL_GPUGraphicsPipelineCreateInfo info = {0}; - info.vertex_shader = shader_load(device, "raycast.vert"); - info.fragment_shader = shader_load(device, "raycast.frag"); + info.vertex_shader = Shader_Load(device, "raycast.vert"); + info.fragment_shader = Shader_Load(device, "raycast.frag"); info.target_info.num_color_targets = 1; info.target_info.color_target_descriptions = color_targets; info.target_info.has_depth_stencil_target = true; info.target_info.depth_stencil_format = depth_format; info.depth_stencil_state.enable_depth_test = true; info.depth_stencil_state.compare_op = SDL_GPU_COMPAREOP_LESS_OR_EQUAL; - if (info.vertex_shader && info.fragment_shader) - { - raycast_pipeline = SDL_CreateGPUGraphicsPipeline(device, &info); - } + info.rasterizer_state.enable_depth_bias = true; + info.rasterizer_state.depth_bias_constant_factor = -1.0f; + info.rasterizer_state.depth_bias_slope_factor = -1.0f; + info.multisample_state.sample_count = SAMPLE_COUNT; + raycast_pipeline = SDL_CreateGPUGraphicsPipeline(device, &info); SDL_ReleaseGPUShader(device, info.vertex_shader); SDL_ReleaseGPUShader(device, info.fragment_shader); return raycast_pipeline != NULL; } -static bool create_samplers() +static bool CreateHudPipeline() +{ + SDL_GPUColorTargetDescription color_target = {0}; + color_target.format = color_format; + color_target.blend_state.enable_blend = true; + color_target.blend_state.src_alpha_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA; + color_target.blend_state.dst_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; + color_target.blend_state.src_color_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA; + color_target.blend_state.dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; + color_target.blend_state.color_blend_op = SDL_GPU_BLENDOP_ADD; + color_target.blend_state.alpha_blend_op = SDL_GPU_BLENDOP_ADD; + SDL_GPUGraphicsPipelineCreateInfo info = {0}; + info.vertex_shader = Shader_Load(device, "hud.vert"); + info.fragment_shader = Shader_Load(device, "hud.frag"); + info.target_info.num_color_targets = 1; + info.target_info.color_target_descriptions = &color_target; + info.multisample_state.sample_count = SDL_GPU_SAMPLECOUNT_1; + hud_pipeline = SDL_CreateGPUGraphicsPipeline(device, &info); + SDL_ReleaseGPUShader(device, info.vertex_shader); + SDL_ReleaseGPUShader(device, info.fragment_shader); + return hud_pipeline != NULL; +} + +static bool CreateSamplers() { SDL_GPUSamplerCreateInfo info = {0}; - info.min_filter = SDL_GPU_FILTER_LINEAR; - info.mag_filter = SDL_GPU_FILTER_LINEAR; info.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST; info.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE; info.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE; info.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE; - linear_sampler = SDL_CreateGPUSampler(device, &info); - if (!linear_sampler) - { - SDL_Log("Failed to create linear sampler: %s", SDL_GetError()); - return false; - } info.min_filter = SDL_GPU_FILTER_NEAREST; info.mag_filter = SDL_GPU_FILTER_NEAREST; nearest_sampler = SDL_CreateGPUSampler(device, &info); @@ -400,25 +324,6 @@ static bool create_samplers() return true; } -static bool create_textures() -{ - SDL_GPUTextureCreateInfo info = {0}; - info.type = SDL_GPU_TEXTURETYPE_2D; - info.format = depth_format; - info.usage = SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET | SDL_GPU_TEXTUREUSAGE_SAMPLER; - info.width = SHADOW_RESOLUTION; - info.height = SHADOW_RESOLUTION; - info.layer_count_or_depth = 1; - info.num_levels = 1; - shadow_texture = SDL_CreateGPUTexture(device, &info); - if (!shadow_texture) - { - SDL_Log("Failed to create shadow texture: %s", SDL_GetError()); - return false; - } - return true; -} - SDL_AppResult SDLCALL SDL_AppInit(void** appstate, int argc, char** argv) { #ifndef NDEBUG @@ -430,7 +335,7 @@ SDL_AppResult SDLCALL SDL_AppInit(void** appstate, int argc, char** argv) SDL_Log("Failed to initialize SDL: %s", SDL_GetError()); return SDL_APP_FAILURE; } - window = SDL_CreateWindow("Blocks", 960, 720, SDL_WINDOW_HIDDEN); + window = SDL_CreateWindow("Blocks", 960, 720, SDL_WINDOW_RESIZABLE); if (!window) { SDL_Log("Failed to create window: %s", SDL_GetError()); @@ -444,125 +349,87 @@ SDL_AppResult SDLCALL SDL_AppInit(void** appstate, int argc, char** argv) if (!device) { SDL_Log("Failed to create device: %s", SDL_GetError()); - return false; + return SDL_APP_FAILURE; } if (!SDL_ClaimWindowForGPUDevice(device, window)) { SDL_Log("Failed to claim window: %s", SDL_GetError()); - return false; + return SDL_APP_FAILURE; } - SDL_SetGPUSwapchainParameters(device, window, SDL_GPU_SWAPCHAINCOMPOSITION_SDR, SDL_GPU_PRESENTMODE_MAILBOX); - color_format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM; + SDL_SetGPUSwapchainParameters(device, window, SDL_GPU_SWAPCHAINCOMPOSITION_SDR, SDL_GPU_PRESENTMODE_IMMEDIATE); + color_format = SDL_GetGPUSwapchainTextureFormat(device, window); depth_format = SDL_GPU_TEXTUREFORMAT_D32_FLOAT; - if (!create_atlas()) + if (!CreateAtlas()) { SDL_Log("Failed to create atlas: %s", SDL_GetError()); return SDL_APP_FAILURE; } - if (!create_samplers()) + if (!CreateSamplers()) { SDL_Log("Failed to create samplers: %s", SDL_GetError()); return SDL_APP_FAILURE; } - if (!create_textures()) - { - SDL_Log("Failed to create textures: %s", SDL_GetError()); - return SDL_APP_FAILURE; - } - if (!create_opaque_pipeline()) + if (!CreateOpaquePipeline()) { SDL_Log("Failed to create opaque pipeline: %s", SDL_GetError()); return SDL_APP_FAILURE; } - if (!create_transparent_pipeline()) + if (!CreateTransparentPipeline()) { SDL_Log("Failed to create transparent pipeline: %s", SDL_GetError()); return SDL_APP_FAILURE; } - if (!create_depth_pipeline()) - { - SDL_Log("Failed to create predepth pipeline: %s", SDL_GetError()); - return SDL_APP_FAILURE; - } - if (!create_shadow_pipeline()) - { - SDL_Log("Failed to create shadow pipeline: %s", SDL_GetError()); - return SDL_APP_FAILURE; - } - if (!create_sky_pipeline()) + if (!CreateSkyPipeline()) { SDL_Log("Failed to create sky pipeline: %s", SDL_GetError()); return SDL_APP_FAILURE; } - if (!create_raycast_pipeline()) + if (!CreateRaycastPipeline()) { SDL_Log("Failed to create raycast pipeline: %s", SDL_GetError()); return SDL_APP_FAILURE; } - ui_pipeline = shader_load(device, "ui.comp"); - if (!ui_pipeline) - { - SDL_Log("Failed to load ui pipeline"); - return SDL_APP_FAILURE; - } - ssao_pipeline = shader_load(device, "ssao.comp"); - if (!ssao_pipeline) - { - SDL_Log("Failed to load ssao pipeline"); - return SDL_APP_FAILURE; - } - composite_pipeline = shader_load(device, "composite.comp"); - if (!composite_pipeline) + if (!CreateHudPipeline()) { - SDL_Log("Failed to load composite pipeline"); + SDL_Log("Failed to create ui pipeline: %s", SDL_GetError()); return SDL_APP_FAILURE; } - blur_pipeline = shader_load(device, "blur.comp"); - if (!blur_pipeline) + block_buffer = Block_GetBuffer(device); + if (!block_buffer) { - SDL_Log("Failed to load blur pipeline"); + SDL_Log("Failed to create block buffer"); return SDL_APP_FAILURE; } - SDL_ShowWindow(window); - SDL_SetWindowResizable(window, true); SDL_FlashWindow(window, SDL_FLASH_BRIEFLY); - set_window_icon(BLOCK_GRASS); - save_init(SAVE_PATH); - world_init(device); - player_save_or_load(&player, PLAYER_ID, false); - world_update(&player.camera); - ticks2 = SDL_GetTicks(); - ticks1 = 0; + SetWindowIcon(); + Save_Init(SAVE_PATH); + Sky_Load(&sky); + World_Init(device); + Player_Load(&player); + Sky_Update(&sky, 0.0f); + World_Update(&player.camera); + ticks1 = SDL_GetTicks(); return SDL_APP_CONTINUE; } void SDLCALL SDL_AppQuit(void* appstate, SDL_AppResult result) { SDL_HideWindow(window); - world_free(); - player_save_or_load(&player, PLAYER_ID, true); - save_free(); - SDL_ReleaseGPUSampler(device, linear_sampler); + World_Free(); + Player_Save(&player); + Sky_Save(&sky); + Save_Free(); SDL_ReleaseGPUSampler(device, nearest_sampler); - SDL_ReleaseGPUTexture(device, shadow_texture); - SDL_ReleaseGPUTexture(device, composite_texture); - SDL_ReleaseGPUTexture(device, blur_texture); - SDL_ReleaseGPUTexture(device, ssao_texture); - SDL_ReleaseGPUTexture(device, color_texture); - SDL_ReleaseGPUTexture(device, light_texture); + SDL_ReleaseGPUTexture(device, msaa_position_texture); + SDL_ReleaseGPUTexture(device, msaa_color_texture); SDL_ReleaseGPUTexture(device, position_texture); - SDL_ReleaseGPUTexture(device, voxel_texture); SDL_ReleaseGPUTexture(device, depth_texture); SDL_ReleaseGPUTexture(device, atlas_texture); + SDL_ReleaseGPUBuffer(device, block_buffer); SDL_DestroySurface(atlas_surface); - SDL_ReleaseGPUComputePipeline(device, blur_pipeline); - SDL_ReleaseGPUComputePipeline(device, composite_pipeline); - SDL_ReleaseGPUComputePipeline(device, ssao_pipeline); - SDL_ReleaseGPUComputePipeline(device, ui_pipeline); + SDL_ReleaseGPUGraphicsPipeline(device, hud_pipeline); SDL_ReleaseGPUGraphicsPipeline(device, raycast_pipeline); SDL_ReleaseGPUGraphicsPipeline(device, sky_pipeline); - SDL_ReleaseGPUGraphicsPipeline(device, shadow_pipeline); - SDL_ReleaseGPUGraphicsPipeline(device, depth_pipeline); SDL_ReleaseGPUGraphicsPipeline(device, transparent_pipeline); SDL_ReleaseGPUGraphicsPipeline(device, opaque_pipeline); SDL_ReleaseWindowFromGPUDevice(device, window); @@ -571,24 +438,16 @@ void SDLCALL SDL_AppQuit(void* appstate, SDL_AppResult result) SDL_Quit(); } -static bool resize(int width, int height) +static bool Resize(int width, int height) { SDL_ReleaseGPUTexture(device, depth_texture); - SDL_ReleaseGPUTexture(device, color_texture); - SDL_ReleaseGPUTexture(device, voxel_texture); SDL_ReleaseGPUTexture(device, position_texture); - SDL_ReleaseGPUTexture(device, ssao_texture); - SDL_ReleaseGPUTexture(device, blur_texture); - SDL_ReleaseGPUTexture(device, composite_texture); - SDL_ReleaseGPUTexture(device, light_texture); + SDL_ReleaseGPUTexture(device, msaa_color_texture); + SDL_ReleaseGPUTexture(device, msaa_position_texture); depth_texture = NULL; - color_texture = NULL; - voxel_texture = NULL; position_texture = NULL; - ssao_texture = NULL; - blur_texture = NULL; - composite_texture = NULL; - light_texture = NULL; + msaa_color_texture = NULL; + msaa_position_texture = NULL; SDL_GPUTextureCreateInfo info = {0}; info.type = SDL_GPU_TEXTURETYPE_2D; info.format = depth_format; @@ -597,148 +456,55 @@ static bool resize(int width, int height) info.height = height; info.layer_count_or_depth = 1; info.num_levels = 1; + info.sample_count = SAMPLE_COUNT; depth_texture = SDL_CreateGPUTexture(device, &info); if (!depth_texture) { SDL_Log("Failed to create depth texture: %s", SDL_GetError()); return false; } - info.format = color_format; - info.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET | SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ; - color_texture = SDL_CreateGPUTexture(device, &info); - if (!color_texture) - { - SDL_Log("Failed to create color texture: %s", SDL_GetError()); - return false; - } - info.format = SDL_GPU_TEXTUREFORMAT_R8_UINT; - info.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET | SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ; - voxel_texture = SDL_CreateGPUTexture(device, &info); - if (!voxel_texture) - { - SDL_Log("Failed to create voxel texture: %s", SDL_GetError()); - return false; - } + info.sample_count = SDL_GPU_SAMPLECOUNT_1; info.format = SDL_GPU_TEXTUREFORMAT_R32G32B32A32_FLOAT; - info.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET | SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ | SDL_GPU_TEXTUREUSAGE_SAMPLER; + info.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET | SDL_GPU_TEXTUREUSAGE_SAMPLER; position_texture = SDL_CreateGPUTexture(device, &info); if (!position_texture) { SDL_Log("Failed to create position texture: %s", SDL_GetError()); return false; } - info.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM; - info.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET | SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ; - light_texture = SDL_CreateGPUTexture(device, &info); - if (!light_texture) - { - SDL_Log("Failed to create light texture: %s", SDL_GetError()); - return false; - } - info.format = SDL_GPU_TEXTUREFORMAT_R8_UNORM; - info.usage = SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE | SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ; - ssao_texture = SDL_CreateGPUTexture(device, &info); - if (!ssao_texture) - { - SDL_Log("Failed to create ssao texture: %s", SDL_GetError()); - return false; - } - info.format = SDL_GPU_TEXTUREFORMAT_R8_UNORM; - info.usage = SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE | SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ; - blur_texture = SDL_CreateGPUTexture(device, &info); - if (!blur_texture) + info.format = color_format; + info.sample_count = SAMPLE_COUNT; + info.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET; + msaa_color_texture = SDL_CreateGPUTexture(device, &info); + if (!msaa_color_texture) { - SDL_Log("Failed to create ssao blur texture: %s", SDL_GetError()); + SDL_Log("Failed to create multisample color texture: %s", SDL_GetError()); return false; } - info.format = color_format; - info.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET | SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE | SDL_GPU_TEXTUREUSAGE_SAMPLER; - composite_texture = SDL_CreateGPUTexture(device, &info); - if (!composite_texture) + info.format = SDL_GPU_TEXTUREFORMAT_R32G32B32A32_FLOAT; + msaa_position_texture = SDL_CreateGPUTexture(device, &info); + if (!msaa_position_texture) { - SDL_Log("Failed to create composite texture: %s", SDL_GetError()); + SDL_Log("Failed to create multisample position texture: %s", SDL_GetError()); return false; } - camera_resize(&player.camera, width, height); + Camera_Resize(&player.camera, width, height); return true; } -static void update_shadow_camera() -{ - camera_init(&shadow_camera, CAMERA_TYPE_ORTHO); - shadow_camera.ortho = SHADOW_ORTHO; - shadow_camera.far = SHADOW_FAR; - shadow_camera.x = SDL_floor(player.camera.x / CHUNK_WIDTH) * CHUNK_WIDTH; - shadow_camera.y = SHADOW_Y; - shadow_camera.z = SDL_floor(player.camera.z / CHUNK_WIDTH) * CHUNK_WIDTH; - shadow_camera.pitch = SHADOW_PITCH; - shadow_camera.yaw = SHADOW_YAW; - camera_update(&shadow_camera); -} - -static void render_shadow(SDL_GPUCommandBuffer* cbuf) -{ - SDL_GPUDepthStencilTargetInfo depth_info = {0}; - depth_info.load_op = SDL_GPU_LOADOP_CLEAR; - depth_info.stencil_load_op = SDL_GPU_LOADOP_CLEAR; - depth_info.store_op = SDL_GPU_STOREOP_STORE; - depth_info.texture = shadow_texture; - depth_info.clear_depth = 1.0f; - depth_info.cycle = true; - SDL_GPURenderPass* pass = SDL_BeginGPURenderPass(cbuf, NULL, 0, &depth_info); - if (!pass) - { - SDL_Log("Failed to begin render pass: %s", SDL_GetError()); - return; - } - SDL_BindGPUGraphicsPipeline(pass, shadow_pipeline); - SDL_PushGPUDebugGroup(cbuf, "shadow"); - world_render(&shadow_camera, cbuf, pass, WORLD_FLAGS_OPAQUE); - SDL_PopGPUDebugGroup(cbuf); - SDL_EndGPURenderPass(pass); -} - -static void render_sky(SDL_GPUCommandBuffer* cbuf, SDL_GPURenderPass* pass) -{ - SDL_PushGPUDebugGroup(cbuf, "sky"); - SDL_BindGPUGraphicsPipeline(pass, sky_pipeline); - SDL_PushGPUVertexUniformData(cbuf, 0, player.camera.proj, 64); - SDL_PushGPUVertexUniformData(cbuf, 1, player.camera.view, 64); - SDL_DrawGPUPrimitives(pass, 36, 1, 0, 0); - SDL_PopGPUDebugGroup(cbuf); -} - -static void render_opaque(SDL_GPUCommandBuffer* cbuf, SDL_GPURenderPass* pass) -{ - SDL_GPUTextureSamplerBinding atlas_binding = {0}; - atlas_binding.texture = atlas_texture; - atlas_binding.sampler = nearest_sampler; - SDL_PushGPUDebugGroup(cbuf, "opaque"); - SDL_BindGPUGraphicsPipeline(pass, opaque_pipeline); - SDL_BindGPUFragmentSamplers(pass, 0, &atlas_binding, 1); - world_render(&player.camera, cbuf, pass, WORLD_FLAGS_OPAQUE | WORLD_FLAGS_LIGHT); - SDL_PopGPUDebugGroup(cbuf); -} - -static void render_gbuffer(SDL_GPUCommandBuffer* cbuf) +static void RenderOpaquePass(SDL_GPUCommandBuffer* command_buffer) { - SDL_GPUColorTargetInfo color_info[4] = {0}; + SDL_GPUColorTargetInfo color_info[2] = {0}; color_info[0].load_op = SDL_GPU_LOADOP_CLEAR; - color_info[0].texture = color_texture; + color_info[0].texture = msaa_color_texture; color_info[0].cycle = true; color_info[0].store_op = SDL_GPU_STOREOP_STORE; color_info[1].load_op = SDL_GPU_LOADOP_CLEAR; - color_info[1].texture = position_texture; + color_info[1].texture = msaa_position_texture; color_info[1].cycle = true; - color_info[1].store_op = SDL_GPU_STOREOP_STORE; - color_info[2].load_op = SDL_GPU_LOADOP_CLEAR; - color_info[2].texture = light_texture; - color_info[2].cycle = true; - color_info[2].store_op = SDL_GPU_STOREOP_STORE; - color_info[3].load_op = SDL_GPU_LOADOP_CLEAR; - color_info[3].texture = voxel_texture; - color_info[3].cycle = true; - color_info[3].store_op = SDL_GPU_STOREOP_STORE; + color_info[1].store_op = SDL_GPU_STOREOP_RESOLVE; + color_info[1].resolve_texture = position_texture; + color_info[1].cycle_resolve_texture = true; SDL_GPUDepthStencilTargetInfo depth_info = {0}; depth_info.load_op = SDL_GPU_LOADOP_CLEAR; depth_info.stencil_load_op = SDL_GPU_LOADOP_CLEAR; @@ -746,210 +512,105 @@ static void render_gbuffer(SDL_GPUCommandBuffer* cbuf) depth_info.texture = depth_texture; depth_info.clear_depth = 1.0f; depth_info.cycle = true; - SDL_GPURenderPass* pass = SDL_BeginGPURenderPass(cbuf, color_info, 4, &depth_info); - if (!pass) + SDL_GPURenderPass* render_pass = SDL_BeginGPURenderPass(command_buffer, color_info, 2, &depth_info); + if (!render_pass) { SDL_Log("Failed to begin render pass: %s", SDL_GetError()); return; } - render_sky(cbuf, pass); - render_opaque(cbuf, pass); - SDL_EndGPURenderPass(pass); -} - -static void render_ssao(SDL_GPUCommandBuffer* cbuf) -{ - SDL_GPUStorageTextureReadWriteBinding write_textures = {0}; - write_textures.texture = ssao_texture; - SDL_GPUComputePass* compute_pass = SDL_BeginGPUComputePass(cbuf, &write_textures, 1, NULL, 0); - if (!compute_pass) - { - SDL_Log("Failed to begin compute pass: %s", SDL_GetError()); - return; - } - SDL_GPUTexture* read_textures[2] = {0}; - read_textures[0] = voxel_texture; - read_textures[1] = position_texture; - int groups_x = (player.camera.width + 8 - 1) / 8; - int groups_y = (player.camera.height + 8 - 1) / 8; - SDL_PushGPUDebugGroup(cbuf, "ssao"); - SDL_BindGPUComputePipeline(compute_pass, ssao_pipeline); - SDL_BindGPUComputeStorageTextures(compute_pass, 0, read_textures, 2); - SDL_DispatchGPUCompute(compute_pass, groups_x, groups_y, 1); - SDL_EndGPUComputePass(compute_pass); - SDL_PopGPUDebugGroup(cbuf); -} - -static void render_blur(SDL_GPUCommandBuffer* cbuf) -{ - SDL_GPUStorageTextureReadWriteBinding write_textures = {0}; - write_textures.texture = blur_texture; - SDL_GPUComputePass* compute_pass = SDL_BeginGPUComputePass(cbuf, &write_textures, 1, NULL, 0); - if (!compute_pass) - { - SDL_Log("Failed to begin compute pass: %s", SDL_GetError()); - return; - } - SDL_GPUTexture* read_textures[1]; - read_textures[0] = ssao_texture; - int groups_x = (player.camera.width + 8 - 1) / 8; - int groups_y = (player.camera.height + 8 - 1) / 8; - SDL_PushGPUDebugGroup(cbuf, "blur"); - SDL_BindGPUComputePipeline(compute_pass, blur_pipeline); - SDL_BindGPUComputeStorageTextures(compute_pass, 0, read_textures, 1); - SDL_DispatchGPUCompute(compute_pass, groups_x, groups_y, 1); - SDL_EndGPUComputePass(compute_pass); - SDL_PopGPUDebugGroup(cbuf); + SDL_PushGPUDebugGroup(command_buffer, "sky"); + SDL_BindGPUGraphicsPipeline(render_pass, sky_pipeline); + SDL_PushGPUVertexUniformData(command_buffer, 0, player.camera.proj, sizeof(player.camera.proj)); + SDL_PushGPUVertexUniformData(command_buffer, 1, player.camera.view, sizeof(player.camera.view)); + SDL_PushGPUFragmentUniformData(command_buffer, 0, sky.sun, sizeof(float) * 16); + SDL_DrawGPUPrimitives(render_pass, 36, 1, 0, 0); + SDL_PopGPUDebugGroup(command_buffer); + SDL_GPUTextureSamplerBinding sampler_binding = {0}; + sampler_binding.texture = atlas_texture; + sampler_binding.sampler = nearest_sampler; + SDL_PushGPUDebugGroup(command_buffer, "opaque"); + SDL_BindGPUGraphicsPipeline(render_pass, opaque_pipeline); + SDL_PushGPUFragmentUniformData(command_buffer, 1, player.camera.position, sizeof(player.camera.position)); + SDL_PushGPUFragmentUniformData(command_buffer, 2, sky.sun, sizeof(float) * 16); + SDL_BindGPUFragmentSamplers(render_pass, 0, &sampler_binding, 1); + SDL_BindGPUFragmentStorageBuffers(render_pass, 0, &block_buffer, 1); + World_Render(&player.camera, WORLD_MESH_TYPE_OPAQUE, command_buffer, render_pass); + SDL_PopGPUDebugGroup(command_buffer); + SDL_EndGPURenderPass(render_pass); } -static void render_composite(SDL_GPUCommandBuffer* cbuf) -{ - SDL_GPUStorageTextureReadWriteBinding write_textures = {0}; - write_textures.texture = composite_texture; - SDL_GPUComputePass* compute_pass = SDL_BeginGPUComputePass(cbuf, &write_textures, 1, NULL, 0); - if (!compute_pass) - { - SDL_Log("Failed to begin compute pass: %s", SDL_GetError()); - return; - } - SDL_GPUTexture* read_textures[5] = {0}; - SDL_GPUTextureSamplerBinding read_samplers = {0}; - read_textures[0] = color_texture; - read_textures[1] = light_texture; - read_textures[2] = blur_texture; - read_textures[3] = voxel_texture; - read_textures[4] = position_texture; - read_samplers.texture = shadow_texture; - read_samplers.sampler = linear_sampler; - int groups_x = (player.camera.width + 8 - 1) / 8; - int groups_y = (player.camera.height + 8 - 1) / 8; - SDL_PushGPUDebugGroup(cbuf, "composite"); - SDL_BindGPUComputePipeline(compute_pass, composite_pipeline); - SDL_BindGPUComputeStorageTextures(compute_pass, 0, read_textures, 5); - SDL_BindGPUComputeSamplers(compute_pass, 0, &read_samplers, 1); - SDL_PushGPUComputeUniformData(cbuf, 0, &shadow_camera.matrix, 64); - SDL_PushGPUComputeUniformData(cbuf, 1, player.camera.position, 12); - SDL_DispatchGPUCompute(compute_pass, groups_x, groups_y, 1); - SDL_EndGPUComputePass(compute_pass); - SDL_PopGPUDebugGroup(cbuf); -} - -static void render_depth(SDL_GPUCommandBuffer* cbuf) +static void RenderTransparentPass(SDL_GPUCommandBuffer* command_buffer, SDL_GPUTexture* swapchain_texture) { + SDL_GPUColorTargetInfo color_info = {0}; + color_info.load_op = SDL_GPU_LOADOP_LOAD; + color_info.texture = msaa_color_texture; + color_info.store_op = SDL_GPU_STOREOP_RESOLVE; + color_info.resolve_texture = swapchain_texture; SDL_GPUDepthStencilTargetInfo depth_info = {0}; depth_info.load_op = SDL_GPU_LOADOP_LOAD; depth_info.store_op = SDL_GPU_STOREOP_STORE; depth_info.texture = depth_texture; - SDL_GPURenderPass* pass = SDL_BeginGPURenderPass(cbuf, NULL, 0, &depth_info); - if (!pass) + SDL_GPURenderPass* render_pass = SDL_BeginGPURenderPass(command_buffer, &color_info, 1, &depth_info); + if (!render_pass) { SDL_Log("Failed to begin render pass: %s", SDL_GetError()); return; } - SDL_PushGPUDebugGroup(cbuf, "depth"); - SDL_BindGPUGraphicsPipeline(pass, depth_pipeline); - world_render(&player.camera, cbuf, pass, WORLD_FLAGS_TRANSPARENT); - SDL_PopGPUDebugGroup(cbuf); - SDL_EndGPURenderPass(pass); -} - -static void render_transparent(SDL_GPUCommandBuffer* cbuf, SDL_GPURenderPass* pass) -{ - SDL_GPUTextureSamplerBinding sampler_bindings[3] = {0}; + SDL_GPUTextureSamplerBinding sampler_bindings[2] = {0}; sampler_bindings[0].texture = atlas_texture; sampler_bindings[0].sampler = nearest_sampler; - sampler_bindings[1].texture = shadow_texture; - sampler_bindings[1].sampler = linear_sampler; - sampler_bindings[2].texture = position_texture; - sampler_bindings[2].sampler = nearest_sampler; - SDL_PushGPUDebugGroup(cbuf, "transparent"); - SDL_BindGPUGraphicsPipeline(pass, transparent_pipeline); - SDL_PushGPUFragmentUniformData(cbuf, 1, &shadow_camera.matrix, 64); - SDL_PushGPUFragmentUniformData(cbuf, 2, player.camera.position, 12); - SDL_BindGPUFragmentSamplers(pass, 0, sampler_bindings, 3); - world_render(&player.camera, cbuf, pass, WORLD_FLAGS_TRANSPARENT | WORLD_FLAGS_LIGHT); - SDL_PopGPUDebugGroup(cbuf); + sampler_bindings[1].texture = position_texture; + sampler_bindings[1].sampler = nearest_sampler; + SDL_PushGPUDebugGroup(command_buffer, "transparent"); + SDL_BindGPUGraphicsPipeline(render_pass, transparent_pipeline); + SDL_PushGPUFragmentUniformData(command_buffer, 1, player.camera.position, sizeof(player.camera.position)); + SDL_PushGPUFragmentUniformData(command_buffer, 2, sky.sun, sizeof(float) * 16); + SDL_BindGPUFragmentSamplers(render_pass, 0, sampler_bindings, 2); + SDL_BindGPUFragmentStorageBuffers(render_pass, 0, &block_buffer, 1); + World_Render(&player.camera, WORLD_MESH_TYPE_TRANSPARENT, command_buffer, render_pass); + SDL_PopGPUDebugGroup(command_buffer); + if (player.query.block != BLOCK_EMPTY) + { + SDL_PushGPUDebugGroup(command_buffer, "raycast"); + SDL_BindGPUGraphicsPipeline(render_pass, raycast_pipeline); + SDL_PushGPUVertexUniformData(command_buffer, 0, player.camera.matrix, sizeof(player.camera.matrix)); + SDL_PushGPUVertexUniformData(command_buffer, 1, player.query.current, sizeof(player.query.current)); + SDL_DrawGPUPrimitives(render_pass, 36, 1, 0, 0); + SDL_PopGPUDebugGroup(command_buffer); + } + SDL_EndGPURenderPass(render_pass); } -static void render_raycast(SDL_GPUCommandBuffer* cbuf, SDL_GPURenderPass* pass) -{ - if (player.query.block == BLOCK_EMPTY) - { - return; - } - SDL_PushGPUDebugGroup(cbuf, "raycast"); - SDL_BindGPUGraphicsPipeline(pass, raycast_pipeline); - SDL_PushGPUVertexUniformData(cbuf, 0, player.camera.matrix, 64); - SDL_PushGPUVertexUniformData(cbuf, 1, player.query.current, 12); - SDL_DrawGPUPrimitives(pass, 36, 1, 0, 0); - SDL_PopGPUDebugGroup(cbuf); -} - -static void render_forward(SDL_GPUCommandBuffer* cbuf) +static void RenderHudPass(SDL_GPUCommandBuffer* command_buffer, SDL_GPUTexture* swapchain_texture) { SDL_GPUColorTargetInfo color_info = {0}; color_info.load_op = SDL_GPU_LOADOP_LOAD; - color_info.texture = composite_texture; color_info.store_op = SDL_GPU_STOREOP_STORE; - SDL_GPUDepthStencilTargetInfo depth_info = {0}; - depth_info.load_op = SDL_GPU_LOADOP_LOAD; - depth_info.store_op = SDL_GPU_STOREOP_STORE; - depth_info.texture = depth_texture; - SDL_GPURenderPass* pass = SDL_BeginGPURenderPass(cbuf, &color_info, 1, &depth_info); - if (!pass) + color_info.texture = swapchain_texture; + SDL_GPURenderPass* render_pass = SDL_BeginGPURenderPass(command_buffer, &color_info, 1, NULL); + if (!render_pass) { SDL_Log("Failed to begin render pass: %s", SDL_GetError()); return; } - render_transparent(cbuf, pass); - render_raycast(cbuf, pass); - SDL_EndGPURenderPass(pass); + Uint32 block = Block_GetIndex(player.block, DIRECTION_NORTH); + SDL_GPUTextureSamplerBinding sampler_binding = {0}; + sampler_binding.texture = atlas_texture; + sampler_binding.sampler = nearest_sampler; + SDL_PushGPUDebugGroup(command_buffer, "ui"); + SDL_BindGPUGraphicsPipeline(render_pass, hud_pipeline); + SDL_BindGPUFragmentSamplers(render_pass, 0, &sampler_binding, 1); + SDL_PushGPUVertexUniformData(command_buffer, 0, &player.camera.size, sizeof(player.camera.size)); + SDL_PushGPUFragmentUniformData(command_buffer, 0, &block, sizeof(block)); + SDL_DrawGPUPrimitives(render_pass, 6, 3, 0, 0); + SDL_PopGPUDebugGroup(command_buffer); + SDL_EndGPURenderPass(render_pass); } -static void render_ui(SDL_GPUCommandBuffer* cbuf) +static void Render() { - SDL_GPUStorageTextureReadWriteBinding write_textures[1] = {0}; - write_textures[0].texture = composite_texture; - SDL_GPUComputePass* compute_pass = SDL_BeginGPUComputePass(cbuf, write_textures, 1, NULL, 0); - if (!compute_pass) - { - SDL_Log("Failed to begin compute pass: %s", SDL_GetError()); - return; - } - SDL_GPUTextureSamplerBinding read_textures[1] = {0}; - read_textures[0].texture = atlas_texture; - read_textures[0].sampler = nearest_sampler; - Sint32 index = block_get_index(player.block, DIRECTION_NORTH); - int groups_x = (player.camera.width + 8 - 1) / 8; - int groups_y = (player.camera.height + 8 - 1) / 8; - SDL_PushGPUDebugGroup(cbuf, "ui"); - SDL_BindGPUComputePipeline(compute_pass, ui_pipeline); - SDL_BindGPUComputeSamplers(compute_pass, 0, read_textures, 1); - SDL_PushGPUComputeUniformData(cbuf, 0, player.camera.size, 8); - SDL_PushGPUComputeUniformData(cbuf, 1, &index, 4); - SDL_DispatchGPUCompute(compute_pass, groups_x, groups_y, 1); - SDL_EndGPUComputePass(compute_pass); - SDL_PopGPUDebugGroup(cbuf); -} - -static void render_swapchain(SDL_GPUCommandBuffer* cbuf, SDL_GPUTexture* swapchain_texture) -{ - SDL_GPUBlitInfo info = {0}; - info.source.texture = composite_texture; - info.source.w = player.camera.width; - info.source.h = player.camera.height; - info.destination.texture = swapchain_texture; - info.destination.w = player.camera.width; - info.destination.h = player.camera.height; - info.load_op = SDL_GPU_LOADOP_DONT_CARE; - info.filter = SDL_GPU_FILTER_NEAREST; - SDL_BlitGPUTexture(cbuf, &info); -} - -static void render() -{ - SDL_GPUCommandBuffer* cbuf = SDL_AcquireGPUCommandBuffer(device); - if (!cbuf) + SDL_GPUCommandBuffer* command_buffer = SDL_AcquireGPUCommandBuffer(device); + if (!command_buffer) { SDL_Log("Failed to acquire command buffer: %s", SDL_GetError()); return; @@ -957,48 +618,41 @@ static void render() SDL_GPUTexture* swapchain_texture; Uint32 width; Uint32 height; - if (!SDL_WaitAndAcquireGPUSwapchainTexture(cbuf, window, &swapchain_texture, &width, &height)) + if (!SDL_WaitAndAcquireGPUSwapchainTexture(command_buffer, window, &swapchain_texture, &width, &height)) { SDL_Log("Failed to acquire swapchain texture: %s", SDL_GetError()); - SDL_CancelGPUCommandBuffer(cbuf); + SDL_CancelGPUCommandBuffer(command_buffer); return; } if (!swapchain_texture || !width || !height) { - SDL_SubmitGPUCommandBuffer(cbuf); + SDL_SubmitGPUCommandBuffer(command_buffer); return; } - if ((width != player.camera.width || height != player.camera.height) && !resize(width, height)) + if ((width != player.camera.width || height != player.camera.height) && !Resize(width, height)) { - SDL_SubmitGPUCommandBuffer(cbuf); + SDL_SubmitGPUCommandBuffer(command_buffer); return; } - camera_update(&player.camera); - render_shadow(cbuf); - render_gbuffer(cbuf); - render_ssao(cbuf); - render_blur(cbuf); - render_composite(cbuf); - render_depth(cbuf); - render_forward(cbuf); - render_ui(cbuf); - render_swapchain(cbuf, swapchain_texture); - SDL_SubmitGPUCommandBuffer(cbuf); + Camera_Update(&player.camera); + RenderOpaquePass(command_buffer); + RenderTransparentPass(command_buffer, swapchain_texture); + RenderHudPass(command_buffer, swapchain_texture); + SDL_SubmitGPUCommandBuffer(command_buffer); } SDL_AppResult SDLCALL SDL_AppIterate(void* appstate) { - ticks2 = SDL_GetTicks(); + Uint64 ticks2 = SDL_GetTicks(); float dt = ticks2 - ticks1; ticks1 = ticks2; if (SDL_GetWindowRelativeMouseMode(window)) { - player_move(&player, dt); - player_save_or_load(&player, PLAYER_ID, true); + Player_Move(&player, dt); + Sky_Update(&sky, dt / 1000.0f); } - update_shadow_camera(); - world_update(&player.camera); - render(); + World_Update(&player.camera); + Render(); return SDL_APP_CONTINUE; } @@ -1008,12 +662,6 @@ SDL_AppResult SDLCALL SDL_AppEvent(void* appstate, SDL_Event* event) { case SDL_EVENT_QUIT: return SDL_APP_SUCCESS; - case SDL_EVENT_MOUSE_MOTION: - if (SDL_GetWindowRelativeMouseMode(window)) - { - player_rotate(&player, event->motion.yrel, event->motion.xrel); - } - break; case SDL_EVENT_KEY_DOWN: if (event->key.scancode == SDL_SCANCODE_ESCAPE) { @@ -1022,20 +670,15 @@ SDL_AppResult SDLCALL SDL_AppEvent(void* appstate, SDL_Event* event) } else if (event->key.scancode == SDL_SCANCODE_F5) { - player_toggle_controller(&player); + Player_ToggleController(&player); + } + else if (event->key.scancode == SDL_SCANCODE_T) + { + Sky_Reset(&sky); } else if (event->key.scancode == SDL_SCANCODE_F11) { - if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) - { - SDL_SetWindowFullscreen(window, false); - SDL_SetWindowRelativeMouseMode(window, false); - } - else - { - SDL_SetWindowFullscreen(window, true); - SDL_SetWindowRelativeMouseMode(window, true); - } + SDL_SetWindowFullscreen(window, !(SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN)); } break; case SDL_EVENT_MOUSE_BUTTON_DOWN: @@ -1043,24 +686,30 @@ SDL_AppResult SDLCALL SDL_AppEvent(void* appstate, SDL_Event* event) { SDL_SetWindowRelativeMouseMode(window, true); } - else + else if (event->button.button == SDL_BUTTON_LEFT) { - if (event->button.button == SDL_BUTTON_LEFT) - { - player_break_block(&player); - } - else if (event->button.button == SDL_BUTTON_MIDDLE) - { - player_select_block(&player); - } - else if (event->button.button == SDL_BUTTON_RIGHT) - { - player_place_block(&player); - } + Player_BreakBlock(&player); + } + else if (event->button.button == SDL_BUTTON_MIDDLE) + { + Player_SelectBlock(&player); + } + else if (event->button.button == SDL_BUTTON_RIGHT) + { + Player_PlaceBlock(&player); } break; case SDL_EVENT_MOUSE_WHEEL: - player_change_block(&player, event->wheel.y); + if (SDL_GetWindowRelativeMouseMode(window)) + { + Player_ChangeBlock(&player, event->wheel.y); + } + break; + case SDL_EVENT_MOUSE_MOTION: + if (SDL_GetWindowRelativeMouseMode(window)) + { + Player_Rotate(&player, event->motion.yrel, event->motion.xrel); + } break; } return SDL_APP_CONTINUE; diff --git a/src/map.c b/src/map.c index 3d483aea..fdeb3881 100644 --- a/src/map.c +++ b/src/map.c @@ -1,13 +1,12 @@ #include -#include "check.h" #include "map.h" static const int EMPTY = 0; static const int TOMBSTONE = 255; static const float MAX_LOAD_FACTOR = 0.75f; -static int hash_int(int x) +static int HashInt(int x) { x += (x << 10); x ^= (x >> 6); @@ -17,40 +16,40 @@ static int hash_int(int x) return x; } -static int hash_xyz(int x, int y, int z) +static int HashPosition(int x, int y, int z) { - return hash_int(x) ^ hash_int(y) ^ hash_int(z); + return HashInt(x) ^ HashInt(y) ^ HashInt(z); } -static bool is_equal(const map_row_t row, int x, int y, int z) +static bool IsEqual(MapRow row, int x, int y, int z) { return row.x == x && row.y == y && row.z == z; } -static void grow(map_t* map) +static void Grow(Map* map) { - map_t old_map = *map; - map_init(map, old_map.capacity * 2); - for (Uint32 i = 0; i < old_map.capacity; ++i) + Map old_map = *map; + Map_Init(map, old_map.capacity * 2); + for (Uint32 i = 0; i < old_map.capacity; i++) { - if (map_is_row_valid(&old_map, i)) + if (Map_IsRowValid(&old_map, i)) { - map_row_t row = old_map.rows[i]; - map_set(map, row.x, row.y, row.z, row.value); + MapRow row = old_map.rows[i]; + Map_Set(map, row.x, row.y, row.z, row.value); } } - map_free(&old_map); + Map_Free(&old_map); } -void map_init(map_t* map, int capacity) +void Map_Init(Map* map, int capacity) { - CHECK(SDL_HasExactlyOneBitSet32(capacity)); - map->rows = SDL_calloc(capacity, sizeof(map_row_t)); + SDL_assert(SDL_HasExactlyOneBitSet32(capacity)); + map->rows = SDL_calloc(capacity, sizeof(MapRow)); map->capacity = capacity; map->size = 0; } -void map_free(map_t* map) +void Map_Free(Map* map) { SDL_free(map->rows); map->rows = NULL; @@ -58,20 +57,20 @@ void map_free(map_t* map) map->capacity = 0; } -void map_set(map_t* map, int x, int y, int z, int value) +void Map_Set(Map* map, int x, int y, int z, int value) { - CHECK(value <= SDL_MAX_UINT8); - CHECK(value != EMPTY && value != TOMBSTONE); - if (((float) (map->size + 1) / map->capacity) > MAX_LOAD_FACTOR) + SDL_assert(value <= SDL_MAX_UINT8); + SDL_assert(value != EMPTY && value != TOMBSTONE); + if ((float) (map->size + 1) / map->capacity > MAX_LOAD_FACTOR) { - grow(map); + Grow(map); } Uint32 mask = map->capacity - 1; - Uint32 index = hash_xyz(x, y, z) & mask; + Uint32 index = HashPosition(x, y, z) & mask; Uint32 tombstone = SDL_MAX_UINT32; for (;;) { - map_row_t* row = &map->rows[index]; + MapRow* row = &map->rows[index]; if (row->value == EMPTY) { if (tombstone != SDL_MAX_UINT32) @@ -92,7 +91,7 @@ void map_set(map_t* map, int x, int y, int z, int value) tombstone = index; } } - else if (is_equal(*row, x, y, z)) + else if (IsEqual(*row, x, y, z)) { row->value = value; return; @@ -101,18 +100,18 @@ void map_set(map_t* map, int x, int y, int z, int value) } } -int map_get(const map_t* map, int x, int y, int z) +int Map_Get(const Map* map, int x, int y, int z) { Uint32 mask = map->capacity - 1; - Uint32 index = hash_xyz(x, y, z) & mask; + Uint32 index = HashPosition(x, y, z) & mask; for (;;) { - const map_row_t row = map->rows[index]; + const MapRow row = map->rows[index]; if (row.value == EMPTY) { return EMPTY; } - if (row.value != TOMBSTONE && is_equal(row, x, y, z)) + if (row.value != TOMBSTONE && IsEqual(row, x, y, z)) { return row.value; } @@ -120,18 +119,18 @@ int map_get(const map_t* map, int x, int y, int z) } } -void map_remove(map_t* map, int x, int y, int z) +void Map_Remove(Map* map, int x, int y, int z) { Uint32 mask = map->capacity - 1; - Uint32 index = hash_xyz(x, y, z) & mask; + Uint32 index = HashPosition(x, y, z) & mask; for (;;) { - map_row_t* row = &map->rows[index]; + MapRow* row = &map->rows[index]; if (row->value == EMPTY) { return; } - if (row->value != TOMBSTONE && is_equal(*row, x, y, z)) + if (row->value != TOMBSTONE && IsEqual(*row, x, y, z)) { row->value = TOMBSTONE; map->size--; @@ -141,20 +140,20 @@ void map_remove(map_t* map, int x, int y, int z) } } -void map_clear(map_t* map) +void Map_Clear(Map* map) { - SDL_memset(map->rows, 0, map->capacity * sizeof(map_row_t)); + SDL_memset(map->rows, 0, map->capacity * sizeof(MapRow)); map->size = 0; } -bool map_is_row_valid(const map_t* map, Uint32 index) +bool Map_IsRowValid(const Map* map, Uint32 index) { - map_row_t row = map->rows[index]; + MapRow row = map->rows[index]; return row.value != EMPTY && row.value != TOMBSTONE; } -map_row_t map_get_row(const map_t* map, Uint32 index) +MapRow Map_GetRow(const Map* map, Uint32 index) { - CHECK(map_is_row_valid(map, index)); + SDL_assert(Map_IsRowValid(map, index)); return map->rows[index]; } diff --git a/src/map.h b/src/map.h index 201b6bd3..9906ab99 100644 --- a/src/map.h +++ b/src/map.h @@ -2,28 +2,26 @@ #include -typedef struct map_row +typedef struct MapRow { Uint8 x; Uint8 y; Uint8 z; Uint8 value; -} -map_row_t; +} MapRow; -typedef struct map +typedef struct Map { - map_row_t* rows; + MapRow* rows; Uint32 size; Uint32 capacity; -} -map_t; +} Map; -void map_init(map_t* map, int capacity); -void map_free(map_t* map); -void map_set(map_t* map, int x, int y, int z, int value); -int map_get(const map_t* map, int x, int y, int z); -void map_remove(map_t* map, int x, int y, int z); -void map_clear(map_t* map); -bool map_is_row_valid(const map_t* map, Uint32 index); -map_row_t map_get_row(const map_t* map, Uint32 index); +void Map_Init(Map* map, int capacity); +void Map_Free(Map* map); +void Map_Set(Map* map, int x, int y, int z, int value); +int Map_Get(const Map* map, int x, int y, int z); +void Map_Remove(Map* map, int x, int y, int z); +void Map_Clear(Map* map); +bool Map_IsRowValid(const Map* map, Uint32 index); +MapRow Map_GetRow(const Map* map, Uint32 index); diff --git a/src/player.c b/src/player.c index f6ddccc3..34ae4d34 100644 --- a/src/player.c +++ b/src/player.c @@ -6,56 +6,44 @@ #include "save.h" #include "world.h" -typedef struct aabb +typedef struct PlayerSave { - float min[3]; - float max[3]; -} -aabb_t; - -static const float PHYSICS_EPSILON = 0.001f; -static const float WALK_SPEED = 5.0f; -static const float SPRINT_SPEED = 9.0f; + float x; + float y; + float z; + float pitch; + float yaw; + Block block; +} PlayerSave; + +static const float EPSILON = 0.001f; +static const float WALK_SPEED = 4.0f; +static const float SPRINT_MULTIPLER = 2.5f; static const float SENSITIVITY = 0.1f; static const float REACH = 10.0f; static const float AIR_ACCELERATION = 6.0f; static const float GRAVITY = 24.0f; static const float JUMP_SPEED = 8.5f; -static const float FLY_SPEED = 0.01f; -static const float FLY_FAST_SPEED = 0.1f; +static const float FLY_SPEED = 0.05f; static const float COLLISION_STEP = 0.1f; static const float GROUND_OFFSET = 0.002f; -static const float COLLISION_RADIUS = 0.3f; -static const float COLLISION_HEIGHT = 1.8f; -static const float EYE_OFFSET = 1.62f; +static const float AABB[2][3] = {{-0.3f, -1.62f, -0.3f}, {0.3f, 1.8f - 1.62f, 0.3f}}; -static aabb_t get_aabb() -{ - return (aabb_t) {{-COLLISION_RADIUS, -EYE_OFFSET, -COLLISION_RADIUS}, - {COLLISION_RADIUS, COLLISION_HEIGHT - EYE_OFFSET, COLLISION_RADIUS}}; -} - -static bool is_solid(const float position[3]) -{ - int index[3] = {position[0], position[1], position[2]}; - return block_is_solid(world_get_block(index)); -} - -static bool is_colliding(const aabb_t *aabb, const float position[3]) +static bool IsColliding(const float position[3]) { int min[3]; int max[3]; for (int i = 0; i < 3; i++) { - min[i] = SDL_floorf(position[i] + aabb->min[i] + PHYSICS_EPSILON); - max[i] = SDL_floorf(position[i] + aabb->max[i] - PHYSICS_EPSILON); + min[i] = SDL_floorf(position[i] + AABB[0][i] + EPSILON); + max[i] = SDL_floorf(position[i] + AABB[1][i] - EPSILON); } for (int bx = min[0]; bx <= max[0]; bx++) for (int by = min[1]; by <= max[1]; by++) for (int bz = min[2]; bz <= max[2]; bz++) { - float location[3] = {bx, by, bz}; - if (is_solid(location)) + int block[3] = {bx, by, bz}; + if (Block_IsSolid(World_GetBlock(block))) { return true; } @@ -63,134 +51,123 @@ static bool is_colliding(const aabb_t *aabb, const float position[3]) return false; } -static void bisect(const aabb_t* aabb, float position[3], int axis, float step) +static void Bisect(float position[3], int axis, float step) { float start[3] = {position[0], position[1], position[2]}; float lower = 0.0f; float upper = 1.0f; for (int i = 0; i < 8; i++) { - float t = (lower + upper) * 0.5f; + float half = (lower + upper) * 0.5f; float location[3] = {start[0], start[1], start[2]}; - location[axis] += step * t; - if (is_colliding(aabb, location)) + location[axis] += step * half; + if (IsColliding(location)) { - upper = t; + upper = half; } else { - lower = t; + lower = half; } } position[axis] = start[axis] + step * lower; } -static bool move(const aabb_t* aabb, float position[3], int axis, float delta) +static bool Move(float position[3], int axis, float delta) { if (SDL_fabsf(delta) <= SDL_FLT_EPSILON) { return false; } - int steps = SDL_ceilf(SDL_fabsf(delta) / COLLISION_STEP); - steps = SDL_max(steps, 1); + int steps = SDL_max(SDL_ceilf(SDL_fabsf(delta) / COLLISION_STEP), 1); float step = delta / steps; for (int i = 0; i < steps; i++) { float location[3] = {position[0], position[1], position[2]}; location[axis] += step; - if (is_colliding(aabb, location)) + if (IsColliding(location)) { - bisect(aabb, position, axis, step); + Bisect(position, axis, step); return true; } - SDL_memcpy(position, location, 12); + SDL_memcpy(position, location, sizeof(location)); } return false; } -void player_save_or_load(player_t* player, int id, bool save) +void Player_Load(Player* player) { - struct - { - float x; - float y; - float z; - float pitch; - float yaw; - block_t block; - } - data; - if (save) - { - data.x = player->camera.x; - data.y = player->camera.y; - data.z = player->camera.z; - data.pitch = player->camera.pitch; - data.yaw = player->camera.yaw; - data.block = player->block; - save_set_player(id, &data, sizeof(data)); - return; - } - camera_init(&player->camera, CAMERA_TYPE_PERSPECTIVE); + PlayerSave save; + Camera_Init(&player->camera, CAMERA_TYPE_PERSPECTIVE); player->camera.x = -200.0f; player->camera.y = 50.0f; player->camera.z = 0.0f; player->controller = PLAYER_CONTROLLER_WALK; player->block = BLOCK_YELLOW_TORCH; - if (save_get_player(id, &data, sizeof(data))) + if (Save_GetPlayer(&save, sizeof(save))) { - player->block = data.block; - player->camera.x = data.x; - player->camera.y = data.y; - player->camera.z = data.z; - player->camera.pitch = data.pitch; - player->camera.yaw = data.yaw; + player->block = save.block; + player->camera.x = save.x; + player->camera.y = save.y; + player->camera.z = save.z; + player->camera.pitch = save.pitch; + player->camera.yaw = save.yaw; } - player->query = world_raycast(&player->camera, REACH); + player->query = World_Raycast(&player->camera, REACH); } -void player_toggle_controller(player_t* player) +void Player_Save(const Player* player) +{ + PlayerSave save; + save.x = player->camera.x; + save.y = player->camera.y; + save.z = player->camera.z; + save.pitch = player->camera.pitch; + save.yaw = player->camera.yaw; + save.block = player->block; + Save_SetPlayer(&save, sizeof(save)); +} + +void Player_ToggleController(Player* player) { player->controller++; player->controller %= PLAYER_CONTROLLER_COUNT; } -void player_rotate(player_t* player, float pitch, float yaw) +void Player_Rotate(Player* player, float pitch, float yaw) { - camera_rotate(&player->camera, pitch * -SENSITIVITY, yaw * SENSITIVITY); - player->query = world_raycast(&player->camera, REACH); + Camera_Rotate(&player->camera, pitch * -SENSITIVITY, yaw * SENSITIVITY); + player->query = World_Raycast(&player->camera, REACH); } -void player_move(player_t* player, float dt) +void Player_Move(Player* player, float dt) { const bool* keys = SDL_GetKeyboardState(NULL); if (player->controller == PLAYER_CONTROLLER_WALK) { - const aabb_t aabb = get_aabb(); dt = SDL_min(dt * 0.001f, 0.05f); - float input_x = keys[SDL_SCANCODE_D] - keys[SDL_SCANCODE_A]; - float input_z = keys[SDL_SCANCODE_W] - keys[SDL_SCANCODE_S]; - float length = SDL_sqrtf(input_x * input_x + input_z * input_z); + float right = keys[SDL_SCANCODE_D] - keys[SDL_SCANCODE_A]; + float forward = keys[SDL_SCANCODE_W] - keys[SDL_SCANCODE_S]; + float length = SDL_sqrtf(right * right + forward * forward); if (length > SDL_FLT_EPSILON) { - input_x /= length; - input_z /= length; + right /= length; + forward /= length; } - float speed = keys[SDL_SCANCODE_LCTRL] ? SPRINT_SPEED : WALK_SPEED; + float speed = WALK_SPEED * (keys[SDL_SCANCODE_LCTRL] ? SPRINT_MULTIPLER : 1.0f); float sy = SDL_sinf(player->camera.yaw); float cy = SDL_cosf(player->camera.yaw); - float target_x = (cy * input_x + sy * input_z) * speed; - float target_z = (sy * input_x - cy * input_z) * speed; + float dx = (cy * right + sy * forward) * speed; + float dz = (sy * right - cy * forward) * speed; if (player->is_on_ground) { - player->velocity[0] = target_x; - player->velocity[2] = target_z; + player->velocity[0] = dx; + player->velocity[2] = dz; } else { - float blend = SDL_min(1.0f, AIR_ACCELERATION * dt); - player->velocity[0] += (target_x - player->velocity[0]) * blend; - player->velocity[2] += (target_z - player->velocity[2]) * blend; + player->velocity[0] += (dx - player->velocity[0]) * AIR_ACCELERATION * dt; + player->velocity[2] += (dz - player->velocity[2]) * AIR_ACCELERATION * dt; } if (keys[SDL_SCANCODE_SPACE] && player->is_on_ground) { @@ -205,65 +182,49 @@ void player_move(player_t* player, float dt) bool hits[3]; for (int i = 0; i < 3; i++) { - hits[i] = move(&aabb, player->camera.position, i, player->velocity[i] * dt); - } - if (hits[0]) - { - player->velocity[0] = 0.0f; - } - if (hits[2]) - { - player->velocity[2] = 0.0f; - } - if (hits[1]) - { - if (player->velocity[1] < 0.0f) - { - player->is_on_ground = true; - } - player->velocity[1] = 0.0f; + hits[i] = Move(player->camera.position, i, player->velocity[i] * dt); } - else + player->is_on_ground = hits[1] && player->velocity[1] < 0.0f; + for (int i = 0; i < 3; i++) { - player->is_on_ground = false; + player->velocity[i] *= !hits[i]; } } else { - float speed = keys[SDL_SCANCODE_LCTRL] ? FLY_FAST_SPEED : FLY_SPEED; + float speed = FLY_SPEED * (keys[SDL_SCANCODE_LCTRL] ? SPRINT_MULTIPLER : 1.0f); float dx = keys[SDL_SCANCODE_D] - keys[SDL_SCANCODE_A]; - float dy = (keys[SDL_SCANCODE_E] || keys[SDL_SCANCODE_SPACE]) - (keys[SDL_SCANCODE_Q] || keys[SDL_SCANCODE_LSHIFT]); + float dy = keys[SDL_SCANCODE_SPACE] + keys[SDL_SCANCODE_E] - keys[SDL_SCANCODE_LSHIFT] - keys[SDL_SCANCODE_Q]; float dz = keys[SDL_SCANCODE_W] - keys[SDL_SCANCODE_S]; - camera_move(&player->camera, dx * speed * dt, dy * speed * dt, dz * speed * dt); + Camera_Move(&player->camera, dx * speed * dt, dy * speed * dt, dz * speed * dt); } - player->query = world_raycast(&player->camera, REACH); + player->query = World_Raycast(&player->camera, REACH); } -void player_place_block(const player_t* player) +void Player_PlaceBlock(const Player* player) { if (player->query.block == BLOCK_EMPTY) { return; } - if (!block_is_solid(player->block)) + if (!Block_IsSolid(player->block)) { - world_set_block(player->query.previous, player->block); + World_SetBlock(player->query.previous, player->block); return; } - const aabb_t aabb = get_aabb(); for (int i = 0; i < 3; i++) { - float min = player->camera.position[i] + aabb.min[i] + PHYSICS_EPSILON; - float max = player->camera.position[i] + aabb.max[i] - PHYSICS_EPSILON; + float min = player->camera.position[i] + AABB[0][i] + EPSILON; + float max = player->camera.position[i] + AABB[1][i] - EPSILON; if (max <= player->query.previous[i] || min >= player->query.previous[i] + 1.0f) { - world_set_block(player->query.previous, player->block); + World_SetBlock(player->query.previous, player->block); break; } } } -void player_select_block(player_t* player) +void Player_SelectBlock(Player* player) { if (player->query.block != BLOCK_EMPTY) { @@ -271,15 +232,15 @@ void player_select_block(player_t* player) } } -void player_break_block(const player_t* player) +void Player_BreakBlock(const Player* player) { if (player->query.block != BLOCK_EMPTY) { - world_set_block(player->query.current, BLOCK_EMPTY); + World_SetBlock(player->query.current, BLOCK_EMPTY); } } -void player_change_block(player_t* player, int dy) +void Player_ChangeBlock(Player* player, int dy) { static const int COUNT = BLOCK_COUNT - BLOCK_EMPTY - 1; int block = player->block - (BLOCK_EMPTY + 1) + dy; diff --git a/src/player.h b/src/player.h index 07ce1e12..de4c758c 100644 --- a/src/player.h +++ b/src/player.h @@ -6,30 +6,29 @@ #include "camera.h" #include "world.h" -typedef enum player_controller +typedef enum PlayerController { PLAYER_CONTROLLER_WALK, PLAYER_CONTROLLER_FLY, PLAYER_CONTROLLER_COUNT, -} -player_controller_t; +} PlayerController; -typedef struct player +typedef struct Player { - camera_t camera; - player_controller_t controller; + Camera camera; + PlayerController controller; float velocity[3]; bool is_on_ground; - world_query_t query; - block_t block; -} -player_t; + WorldQuery query; + Block block; +} Player; -void player_save_or_load(player_t* player, int id, bool save); -void player_toggle_controller(player_t* player); -void player_rotate(player_t* player, float pitch, float yaw); -void player_move(player_t* player, float dt); -void player_place_block(const player_t* player); -void player_select_block(player_t* player); -void player_break_block(const player_t* player); -void player_change_block(player_t* player, int dy); +void Player_Load(Player* player); +void Player_Save(const Player* player); +void Player_ToggleController(Player* player); +void Player_Rotate(Player* player, float pitch, float yaw); +void Player_Move(Player* player, float dt); +void Player_PlaceBlock(const Player* player); +void Player_SelectBlock(Player* player); +void Player_BreakBlock(const Player* player); +void Player_ChangeBlock(Player* player, int dy); diff --git a/src/rand.c b/src/rand.c index 4ef14344..47c49312 100644 --- a/src/rand.c +++ b/src/rand.c @@ -4,29 +4,26 @@ #include "rand.h" #include "world.h" -void rand_get_blocks(void* userdata, int cx, int cz, rand_set_block_t function) +void Rand_GetBlocks(void* userdata, int cx, int cz, RandSetBlock callback) { - for (int a = 0; a < CHUNK_WIDTH; a++) - for (int b = 0; b < CHUNK_WIDTH; b++) + for (int x = 0; x < CHUNK_WIDTH; x++) + for (int z = 0; z < CHUNK_WIDTH; z++) { - int x = cx + a; - int z = cz + b; - bool low = false; - bool grass = false; - float height = stb_perlin_fbm_noise3(x * 0.005f, 0.0f, z * 0.005f, 2.0f, 0.5f, 6); - height *= 50.0f; - height = SDL_powf(SDL_max(height, 0.0f), 1.3f); - height += 30; - height = SDL_clamp(height, 0, CHUNK_HEIGHT - 1); - if (height < 40) + int bx = cx + x; + int bz = cz + z; + float height = stb_perlin_fbm_noise3(bx * 0.005f, 0.0f, bz * 0.005f, 2.0f, 0.5f, 6) * 50.0f; + height = SDL_powf(SDL_max(height, 0.0f), 1.3f) + 30.0f; + height = SDL_clamp(height, 0.0f, CHUNK_HEIGHT - 1.0f); + bool is_low_elevation = false; + if (height < 40.0f) { - height += stb_perlin_fbm_noise3(-x * 0.01f, 0.0f, z * 0.01f, 2.0f, 0.5f, 6) * 12.0f; - low = true; + height += stb_perlin_fbm_noise3(-bx * 0.01f, 0.0f, bz * 0.01f, 2.0f, 0.5f, 6) * 12.0f; + is_low_elevation = true; } - float biome = stb_perlin_fbm_noise3(x * 0.2f, 0.0f, z * 0.2f, 2.0f, 0.5f, 6); - block_t top; - block_t bottom; - if (height + biome < 31) + float biome = stb_perlin_fbm_noise3(bx * 0.2f, 0.0f, bz * 0.2f, 2.0f, 0.5f, 6); + Block top; + Block bottom; + if (height + biome < 31.0f) { top = BLOCK_SAND; bottom = BLOCK_SAND; @@ -35,13 +32,12 @@ void rand_get_blocks(void* userdata, int cx, int cz, rand_set_block_t function) { biome *= 8.0f; biome = SDL_clamp(biome, -5.0f, 5.0f); - if (height + biome < 61) + if (height + biome < 61.0f) { top = BLOCK_GRASS; bottom = BLOCK_DIRT; - grass = true; } - else if (height + biome < 132) + else if (height + biome < 132.0f) { top = BLOCK_STONE; bottom = BLOCK_STONE; @@ -55,22 +51,22 @@ void rand_get_blocks(void* userdata, int cx, int cz, rand_set_block_t function) int y = 0; for (; y < height; y++) { - function(userdata, x, y, z, bottom); + callback(userdata, bx, y, bz, bottom); } - function(userdata, x, y, z, top); + callback(userdata, bx, y, bz, top); for (; y < 30; y++) { - function(userdata, x, y, z, BLOCK_WATER); + callback(userdata, bx, y, bz, BLOCK_WATER); } - if (low && grass) + if (top == BLOCK_GRASS && is_low_elevation) { - float plant = stb_perlin_fbm_noise3(x * 0.2f, 0.0f, z * 0.2f, 2.0f, 0.5f, 3) * 0.5f + 0.5f; - if (plant > 0.8f && a > 2 && a < CHUNK_WIDTH - 2 && b > 2 && b < CHUNK_WIDTH - 2) + float plant = stb_perlin_fbm_noise3(bx * 0.2f, 0.0f, bz * 0.2f, 2.0f, 0.5f, 3) * 0.5f + 0.5f; + if (plant > 0.8f && x > 2 && x < CHUNK_WIDTH - 2 && z > 2 && z < CHUNK_WIDTH - 2) { - int log = 3 + plant * 2.0f; - for (int dy = 0; dy < log; dy++) + int trunk = 3 + plant * 2.0f; + for (int dy = 0; dy < trunk; dy++) { - function(userdata, x, y + dy + 1, z, BLOCK_LOG); + callback(userdata, bx, y + dy + 1, bz, BLOCK_LOG); } for (int dx = -1; dx <= 1; dx++) for (int dz = -1; dz <= 1; dz++) @@ -78,26 +74,26 @@ void rand_get_blocks(void* userdata, int cx, int cz, rand_set_block_t function) { if (dx || dz || dy) { - function(userdata, x + dx, y + log + dy, z + dz, BLOCK_LEAVES); + callback(userdata, bx + dx, y + trunk + dy, bz + dz, BLOCK_LEAVES); } } } else if (plant > 0.55f) { - function(userdata, x, y + 1, z, BLOCK_BUSH); + callback(userdata, bx, y + 1, bz, BLOCK_BUSH); } else if (plant > 0.52f) { - int value = SDL_max(((int) (plant * 1000.0f)) % 4, 0); - block_t flowers[] = {BLOCK_BLUEBELL, BLOCK_GARDENIA, BLOCK_LAVENDER, BLOCK_ROSE}; - function(userdata, x, y + 1, z, flowers[value]); + int i = (int)(plant * 1000.0f) % 4; + Block flowers[] = {BLOCK_BLUEBELL, BLOCK_GARDENIA, BLOCK_LAVENDER, BLOCK_ROSE}; + callback(userdata, bx, y + 1, bz, flowers[i]); } } - if (height > 130) + if (height > 130.0f) { continue; } - float cloud = stb_perlin_turbulence_noise3(x * 0.015f, 0.0f, z * 0.015f, 2.0f, 0.5f, 6); + float cloud = stb_perlin_turbulence_noise3(bx * 0.015f, 0.0f, bz * 0.015f, 2.0f, 0.5f, 6); int scale = -1; if (cloud > 0.9f) { @@ -107,13 +103,13 @@ void rand_get_blocks(void* userdata, int cx, int cz, rand_set_block_t function) { scale = 1; } - else if (cloud > 0.6) + else if (cloud > 0.6f) { scale = 0; } for (int y = -scale; y <= scale; y++) { - function(userdata, x, 155 - y, z, BLOCK_CLOUD); + callback(userdata, bx, 155 - y, bz, BLOCK_CLOUD); } } } diff --git a/src/rand.h b/src/rand.h index f5d7d380..8d92869b 100644 --- a/src/rand.h +++ b/src/rand.h @@ -4,6 +4,6 @@ #include "block.h" -typedef void (*rand_set_block_t)(void* userdata, int bx, int by, int bz, block_t block); +typedef void (*RandSetBlock)(void* userdata, int bx, int by, int bz, Block block); -void rand_get_blocks(void* userdata, int cx, int cz, rand_set_block_t function); +void Rand_GetBlocks(void* userdata, int cx, int cz, RandSetBlock callback); diff --git a/src/save.c b/src/save.c index a482b30f..54e7562a 100644 --- a/src/save.c +++ b/src/save.c @@ -3,12 +3,11 @@ #include "save.h" -static const char* PLAYER_TABLE = +static const char* SCHEMA = "CREATE TABLE IF NOT EXISTS players (" " id INT PRIMARY KEY NOT NULL," " data BLOB NOT NULL" - ");"; -static const char* BLOCK_TABLE = + ");" "CREATE TABLE IF NOT EXISTS blocks (" " cx INTEGER NOT NULL," " cz INTEGER NOT NULL," @@ -17,109 +16,110 @@ static const char* BLOCK_TABLE = " bz INTEGER NOT NULL," " block INTEGER NOT NULL," " PRIMARY KEY (cx, cz, bx, by, bz)" - ");"; -static const char* SET_PLAYER = "INSERT OR REPLACE INTO players (id, data) VALUES (?, ?);"; -static const char* GET_PLAYER = "SELECT data FROM players WHERE id = ?;"; + ");" + "CREATE TABLE IF NOT EXISTS sky (" + " id INTEGER PRIMARY KEY NOT NULL," + " time_of_day REAL NOT NULL" + ");" + "CREATE INDEX IF NOT EXISTS blocks_index ON blocks (cx, cz);"; +static const char* SET_PLAYER = "INSERT OR REPLACE INTO players (id, data) VALUES (0, ?);"; +static const char* GET_PLAYER = "SELECT data FROM players WHERE id = 0;"; +static const char* SET_SKY = "INSERT OR REPLACE INTO sky (id, time_of_day) VALUES (0, ?);"; +static const char* GET_SKY = "SELECT time_of_day FROM sky WHERE id = 0;"; static const char* SET_BLOCK = "INSERT OR REPLACE INTO blocks (cx, cz, bx, by, bz, block) VALUES (?, ?, ?, ?, ?, ?);"; static const char* GET_BLOCKS = "SELECT bx, by, bz, block FROM blocks WHERE cx = ? AND cz = ?;"; -static const char* BLOCK_INDEX = "CREATE INDEX IF NOT EXISTS bindex ON blocks (cx, cz);"; static sqlite3* handle; static sqlite3_stmt* set_player; static sqlite3_stmt* get_player; +static sqlite3_stmt* set_sky; +static sqlite3_stmt* get_sky; static sqlite3_stmt* set_block; static sqlite3_stmt* get_blocks; static SDL_Mutex* mutex; -bool save_init(const char* path) +static bool Execute(const char* sql, const char* name) { - if (sqlite3_open(path, &handle)) - { - SDL_Log("Failed to open %s database: %s", path, sqlite3_errmsg(handle)); - return false; - } - if (sqlite3_exec(handle, PLAYER_TABLE, NULL, NULL, NULL)) - { - SDL_Log("Failed to create player table: %s", sqlite3_errmsg(handle)); - return false; - } - if (sqlite3_exec(handle, BLOCK_TABLE, NULL, NULL, NULL)) - { - SDL_Log("Failed to create block table: %s", sqlite3_errmsg(handle)); - return false; - } - if (sqlite3_prepare_v2(handle, SET_PLAYER, -1, &set_player, NULL)) - { - SDL_Log("Failed to prepare set player: %s", sqlite3_errmsg(handle)); - return false; - } - if (sqlite3_prepare_v2(handle, GET_PLAYER, -1, &get_player, NULL)) - { - SDL_Log("Failed to prepare get player: %s", sqlite3_errmsg(handle)); - return false; - } - if (sqlite3_prepare_v2(handle, SET_BLOCK, -1, &set_block, NULL)) + if (sqlite3_exec(handle, sql, NULL, NULL, NULL)) { - SDL_Log("Failed to prepare set block: %s", sqlite3_errmsg(handle)); + SDL_Log("Failed to %s: %s", name, sqlite3_errmsg(handle)); return false; } - if (sqlite3_prepare_v2(handle, GET_BLOCKS, -1, &get_blocks, NULL)) + return true; +} + +static bool Prepare(sqlite3_stmt** statement, const char* sql, const char* name) +{ + if (sqlite3_prepare_v2(handle, sql, -1, statement, NULL)) { - SDL_Log("Failed to prepare get blocks: %s", sqlite3_errmsg(handle)); + SDL_Log("Failed to prepare %s: %s", name, sqlite3_errmsg(handle)); return false; } - if (sqlite3_exec(handle, BLOCK_INDEX, NULL, NULL, NULL)) + return true; +} + +bool Save_Init(const char* path) +{ + if (sqlite3_open(path, &handle)) { - SDL_Log("Failed to create block index: %s", sqlite3_errmsg(handle)); + SDL_Log("Failed to open %s database: %s", path, sqlite3_errmsg(handle)); + sqlite3_close(handle); + handle = NULL; return false; } mutex = SDL_CreateMutex(); if (!mutex) { SDL_Log("Failed to create mutex: %s", SDL_GetError()); + sqlite3_close(handle); + handle = NULL; + return false; + } + if (!Execute(SCHEMA, "create schema") || !Prepare(&set_player, SET_PLAYER, "set player") || + !Prepare(&get_player, GET_PLAYER, "get player") || !Prepare(&set_sky, SET_SKY, "set sky") || + !Prepare(&get_sky, GET_SKY, "get sky") || !Prepare(&set_block, SET_BLOCK, "set block") || + !Prepare(&get_blocks, GET_BLOCKS, "get blocks")) + { + Save_Free(); return false; } sqlite3_exec(handle, "BEGIN;", NULL, NULL, NULL); return true; } -void save_free() +void Save_Free() { + if (!handle) + { + return; + } SDL_DestroyMutex(mutex); sqlite3_exec(handle, "COMMIT;", NULL, NULL, NULL); sqlite3_finalize(set_player); sqlite3_finalize(get_player); + sqlite3_finalize(set_sky); + sqlite3_finalize(get_sky); sqlite3_finalize(set_block); sqlite3_finalize(get_blocks); sqlite3_close(handle); handle = NULL; set_player = NULL; get_player = NULL; + set_sky = NULL; + get_sky = NULL; set_block = NULL; get_blocks = NULL; mutex = NULL; } -void save_commit() -{ - if (!handle) - { - return; - } - SDL_LockMutex(mutex); - sqlite3_exec(handle, "COMMIT; BEGIN;", NULL, NULL, NULL); - SDL_UnlockMutex(mutex); -} - -void save_set_player(int id, const void* data, int size) +void Save_SetPlayer(const void* data, int size) { if (!handle) { return; } SDL_LockMutex(mutex); - sqlite3_bind_int(set_player, 1, id); - sqlite3_bind_blob(set_player, 2, data, size, SQLITE_TRANSIENT); + sqlite3_bind_blob(set_player, 1, data, size, SQLITE_TRANSIENT); if (sqlite3_step(set_player) != SQLITE_DONE) { SDL_Log("Failed to set player: %s", sqlite3_errmsg(handle)); @@ -128,14 +128,13 @@ void save_set_player(int id, const void* data, int size) SDL_UnlockMutex(mutex); } -bool save_get_player(int id, void* data, int size) +bool Save_GetPlayer(void* data, int size) { if (!handle) { return false; } SDL_LockMutex(mutex); - sqlite3_bind_int(get_player, 1, id); bool has_player = sqlite3_step(get_player) == SQLITE_ROW; if (has_player) { @@ -148,6 +147,7 @@ bool save_get_player(int id, void* data, int size) else { SDL_Log("Failed to get player: Out of date"); + has_player = false; } } sqlite3_reset(get_player); @@ -155,7 +155,40 @@ bool save_get_player(int id, void* data, int size) return has_player; } -void save_set_block(int cx, int cz, int bx, int by, int bz, block_t block) +void Save_SetSky(float time_of_day) +{ + if (!handle) + { + return; + } + SDL_LockMutex(mutex); + sqlite3_bind_double(set_sky, 1, time_of_day); + if (sqlite3_step(set_sky) != SQLITE_DONE) + { + SDL_Log("Failed to set sky: %s", sqlite3_errmsg(handle)); + } + sqlite3_reset(set_sky); + SDL_UnlockMutex(mutex); +} + +bool Save_GetSky(float* time_of_day) +{ + if (!handle) + { + return false; + } + SDL_LockMutex(mutex); + bool has_sky = sqlite3_step(get_sky) == SQLITE_ROW; + if (has_sky) + { + *time_of_day = sqlite3_column_double(get_sky, 0); + } + sqlite3_reset(get_sky); + SDL_UnlockMutex(mutex); + return has_sky; +} + +void Save_SetBlock(int cx, int cz, int bx, int by, int bz, Block block) { if (!handle) { @@ -176,7 +209,7 @@ void save_set_block(int cx, int cz, int bx, int by, int bz, block_t block) SDL_UnlockMutex(mutex); } -void save_get_blocks(void* userdata, int cx, int cz, save_set_block_t function) +void Save_GetBlocks(void* userdata, int cx, int cz, SaveSetBlock callback) { if (!handle) { @@ -190,8 +223,8 @@ void save_get_blocks(void* userdata, int cx, int cz, save_set_block_t function) int bx = sqlite3_column_int(get_blocks, 0); int by = sqlite3_column_int(get_blocks, 1); int bz = sqlite3_column_int(get_blocks, 2); - block_t block = sqlite3_column_int(get_blocks, 3); - function(userdata, bx, by, bz, block); + Block block = sqlite3_column_int(get_blocks, 3); + callback(userdata, bx, by, bz, block); } sqlite3_reset(get_blocks); SDL_UnlockMutex(mutex); diff --git a/src/save.h b/src/save.h index b341ea06..93e5fcdc 100644 --- a/src/save.h +++ b/src/save.h @@ -4,12 +4,13 @@ #include "block.h" -typedef void (*save_set_block_t)(void* userdata, int bx, int by, int bz, block_t block); - -bool save_init(const char* path); -void save_free(); -void save_commit(); -void save_set_player(int id, const void* data, int size); -bool save_get_player(int id, void* data, int size); -void save_set_block(int cx, int cz, int bx, int by, int bz, block_t block); -void save_get_blocks(void* userdata, int cx, int cz, save_set_block_t function); +typedef void (*SaveSetBlock)(void* userdata, int bx, int by, int bz, Block block); + +bool Save_Init(const char* path); +void Save_Free(); +void Save_SetPlayer(const void* data, int size); +bool Save_GetPlayer(void* data, int size); +void Save_SetSky(float time_of_day); +bool Save_GetSky(float* time_of_day); +void Save_SetBlock(int cx, int cz, int bx, int by, int bz, Block block); +void Save_GetBlocks(void* userdata, int cx, int cz, SaveSetBlock callback); diff --git a/src/shader.c b/src/shader.c index 6baa3dc2..848d77ad 100644 --- a/src/shader.c +++ b/src/shader.c @@ -1,10 +1,9 @@ #include #include -#include "check.h" #include "shader.h" -void* shader_load(SDL_GPUDevice* device, const char* name) +SDL_GPUShader* Shader_Load(SDL_GPUDevice* device, const char* name) { SDL_GPUShaderFormat format = SDL_GetGPUShaderFormats(device); const char* entrypoint; @@ -29,7 +28,7 @@ void* shader_load(SDL_GPUDevice* device, const char* name) } else { - CHECK(false); + SDL_assert(false); } char shader_path[512] = {0}; char shader_json_path[512] = {0}; diff --git a/src/shader.h b/src/shader.h index b246f2d1..6287d2e9 100644 --- a/src/shader.h +++ b/src/shader.h @@ -2,4 +2,4 @@ #include -void* shader_load(SDL_GPUDevice* device, const char* path); \ No newline at end of file +SDL_GPUShader* Shader_Load(SDL_GPUDevice* device, const char* path); diff --git a/src/sky.c b/src/sky.c new file mode 100644 index 00000000..67200f01 --- /dev/null +++ b/src/sky.c @@ -0,0 +1,104 @@ +#include +#include + +#include "save.h" +#include "sky.h" + +static const float TOTAL_LENGTH = 180.0f; +static const float SUNRISE_END = 30.0f / 180.0f; +static const float DAY_END = 90.0f / 180.0f; +static const float SUNSET_END = 120.0f / 180.0f; +static const float SPEED = 0.1f; +static const float AMBIENT_SCALE = 0.35f; +static const float NIGHT_SKY_TOP[3] = {0.01f, 0.02f, 0.06f}; +static const float NIGHT_SKY_HORIZON[3] = {0.06f, 0.08f, 0.18f}; +static const float TWILIGHT_SKY_TOP[3] = {0.24f, 0.16f, 0.32f}; +static const float TWILIGHT_SKY_HORIZON[3] = {0.95f, 0.45f, 0.28f}; +static const float DAY_SKY_TOP[3] = {0.32f, 0.58f, 0.92f}; +static const float DAY_SKY_HORIZON[3] = {0.72f, 0.84f, 0.98f}; +static const float NIGHT_AMBIENT[3] = {0.12f, 0.16f, 0.28f}; +static const float DAY_AMBIENT[3] = {0.85f, 0.9f, 1.0f}; + +static void Lerp(float out[4], const float start[3], const float end[3], float alpha) +{ + out[0] = start[0] + (end[0] - start[0]) * alpha; + out[1] = start[1] + (end[1] - start[1]) * alpha; + out[2] = start[2] + (end[2] - start[2]) * alpha; + out[3] = 0.0f; +} + +static void Copy(float out[4], const float in[3]) +{ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = 0.0f; +} + +void Sky_Reset(Sky* sky) +{ + sky->time_of_day = 3.0f / 8.0f; +} + +void Sky_Save(const Sky* sky) +{ + Save_SetSky(sky->time_of_day); +} + +void Sky_Load(Sky* sky) +{ + SDL_COMPILE_TIME_ASSERT("", offsetof(Sky, time_of_day) == sizeof(float) * 16); + sky->time_of_day = SUNRISE_END + (DAY_END - SUNRISE_END) / 2.0f; + float time; + if (Save_GetSky(&time) && time >= 0.0f && time < 1.0f) + { + sky->time_of_day = time; + } +} + +void Sky_Update(Sky* sky, float dt) +{ + sky->time_of_day += dt * SPEED / TOTAL_LENGTH; + sky->time_of_day = SDL_fmodf(sky->time_of_day, 1.0f); + float alpha; + if (sky->time_of_day < SUNRISE_END) + { + alpha = sky->time_of_day / SUNRISE_END; + Lerp(sky->top, NIGHT_SKY_TOP, TWILIGHT_SKY_TOP, alpha); + Lerp(sky->horizon, NIGHT_SKY_HORIZON, TWILIGHT_SKY_HORIZON, alpha); + Lerp(sky->ambient, NIGHT_AMBIENT, DAY_AMBIENT, alpha); + } + else if (sky->time_of_day < DAY_END) + { + alpha = (sky->time_of_day - SUNRISE_END) / (DAY_END - SUNRISE_END); + Lerp(sky->top, TWILIGHT_SKY_TOP, DAY_SKY_TOP, alpha); + Lerp(sky->horizon, TWILIGHT_SKY_HORIZON, DAY_SKY_HORIZON, alpha); + Copy(sky->ambient, DAY_AMBIENT); + } + else if (sky->time_of_day < SUNSET_END) + { + alpha = (sky->time_of_day - DAY_END) / (SUNSET_END - DAY_END); + Lerp(sky->top, DAY_SKY_TOP, TWILIGHT_SKY_TOP, alpha); + Lerp(sky->horizon, DAY_SKY_HORIZON, TWILIGHT_SKY_HORIZON, alpha); + Lerp(sky->ambient, DAY_AMBIENT, NIGHT_AMBIENT, alpha); + } + else + { + alpha = (sky->time_of_day - SUNSET_END) / (1.0f - SUNSET_END); + Lerp(sky->top, TWILIGHT_SKY_TOP, NIGHT_SKY_TOP, alpha); + Lerp(sky->horizon, TWILIGHT_SKY_HORIZON, NIGHT_SKY_HORIZON, alpha); + Copy(sky->ambient, NIGHT_AMBIENT); + } + float angle = sky->time_of_day * 2.0f * SDL_PI_F - SDL_PI_F * 0.5f; + float s = SDL_sinf(angle); + float c = SDL_cosf(angle); + float intensity = SDL_clamp(s, 0.0f, 1.0f); + sky->sun[0] = c * SDL_sqrtf(0.5f); + sky->sun[1] = -intensity; + sky->sun[2] = -c * SDL_sqrtf(0.5f); + sky->sun[3] = intensity; + float ambient = SDL_clamp(intensity, 0.1f, 1.0f) * AMBIENT_SCALE; + sky->ambient[0] *= ambient; + sky->ambient[1] *= ambient; + sky->ambient[2] *= ambient; +} diff --git a/src/sky.h b/src/sky.h new file mode 100644 index 00000000..730dbc40 --- /dev/null +++ b/src/sky.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +typedef struct Sky +{ + float sun[4]; + float top[4]; + float horizon[4]; + float ambient[4]; + float time_of_day; +} Sky; + +void Sky_Reset(Sky* sky); +void Sky_Save(const Sky* sky); +void Sky_Load(Sky* sky); +void Sky_Update(Sky* sky, float dt); diff --git a/src/sort.c b/src/sort.c new file mode 100644 index 00000000..71275126 --- /dev/null +++ b/src/sort.c @@ -0,0 +1,18 @@ +#include + +#include "sort.h" + +static int Distance2D(void* userdata, const void* lhs, const void* rhs) +{ + int center = *(int*) userdata; + const int* l = lhs; + const int* r = rhs; + int dl = (l[0] - center) * (l[0] - center) + (l[1] - center) * (l[1] - center); + int dr = (r[0] - center) * (r[0] - center) + (r[1] - center) * (r[1] - center); + return (dl > dr) - (dl < dr); +} + +void Sort_Distance2D(int data[][2], int size, int center) +{ + SDL_qsort_r(data, size, sizeof(data[0]), Distance2D, ¢er); +} diff --git a/src/sort.h b/src/sort.h new file mode 100644 index 00000000..eb695ae8 --- /dev/null +++ b/src/sort.h @@ -0,0 +1,3 @@ +#pragma once + +void Sort_Distance2D(int data[][2], int size, int center); diff --git a/src/voxel.c b/src/voxel.c index 376f0495..114f7136 100644 --- a/src/voxel.c +++ b/src/voxel.c @@ -1,99 +1,101 @@ #include #include "block.h" -#include "check.h" #include "direction.h" #include "voxel.h" #include "voxel.inc" -static voxel_t pack(block_t block, int x, int y, int z, int u, int v, direction_t direction, int normal) +static const int CUBE_POSITIONS[][4][3] = { - normal++; + {{0, 0, 1}, {0, 1, 1}, {1, 0, 1}, {1, 1, 1}}, + {{0, 0, 0}, {1, 0, 0}, {0, 1, 0}, {1, 1, 0}}, + {{1, 0, 0}, {1, 0, 1}, {1, 1, 0}, {1, 1, 1}}, + {{0, 0, 0}, {0, 1, 0}, {0, 0, 1}, {0, 1, 1}}, + {{0, 1, 0}, {1, 1, 0}, {0, 1, 1}, {1, 1, 1}}, + {{0, 0, 0}, {0, 0, 1}, {1, 0, 0}, {1, 0, 1}}, +}; + +static const int TEXCOORDS[][4][2] = +{ + {{1, 1}, {1, 0}, {0, 1}, {0, 0}}, + {{1, 1}, {0, 1}, {1, 0}, {0, 0}}, + {{1, 1}, {0, 1}, {1, 0}, {0, 0}}, + {{1, 1}, {1, 0}, {0, 1}, {0, 0}}, + {{0, 0}, {1, 0}, {0, 1}, {1, 1}}, + {{0, 0}, {0, 1}, {1, 0}, {1, 1}}, +}; + +static const int SPRITE_POSITIONS[][4][3] = +{ + {{0, 0, 0}, {0, 1, 0}, {1, 0, 1}, {1, 1, 1}}, + {{0, 0, 0}, {1, 0, 1}, {0, 1, 0}, {1, 1, 1}}, + {{0, 0, 1}, {1, 0, 0}, {0, 1, 1}, {1, 1, 0}}, + {{0, 0, 1}, {0, 1, 1}, {1, 0, 0}, {1, 1, 0}}, +}; + +void Voxel_GetPosition(Direction direction, int index, int position[3]) +{ + SDL_assert(direction < 6); + SDL_assert(index < 4); + SDL_memcpy(position, CUBE_POSITIONS[direction][index], sizeof(int) * 3); +} + +void Voxel_GetAO(const int ao[4], int order[4]) +{ + static const int AO[2][4] = {{0, 1, 2, 3}, {1, 3, 0, 2}}; + int index = ao[0] + ao[3] > ao[1] + ao[2]; + SDL_memcpy(order, AO[index], sizeof(AO[index])); +} + +static Voxel Voxel_Pack(Block block, int x, int y, int z, int u, int v, Direction direction, int ao) +{ + SDL_COMPILE_TIME_ASSERT("", AO_OFFSET + AO_BITS <= 32); SDL_COMPILE_TIME_ASSERT("", X_OFFSET + X_BITS <= 32); SDL_COMPILE_TIME_ASSERT("", Y_OFFSET + Y_BITS <= 32); SDL_COMPILE_TIME_ASSERT("", Z_OFFSET + Z_BITS <= 32); SDL_COMPILE_TIME_ASSERT("", U_OFFSET + U_BITS <= 32); SDL_COMPILE_TIME_ASSERT("", V_OFFSET + V_BITS <= 32); - SDL_COMPILE_TIME_ASSERT("", INDEX_OFFSET + INDEX_BITS <= 32); SDL_COMPILE_TIME_ASSERT("", DIRECTION_OFFSET + DIRECTION_BITS <= 32); - CHECK(direction <= DIRECTION_COUNT); - int index = block_get_index(block, direction); - CHECK(x <= X_MASK); - CHECK(y <= Y_MASK); - CHECK(z <= Z_MASK); - CHECK(u <= U_MASK); - CHECK(v <= V_MASK); - CHECK(index <= INDEX_MASK); - CHECK(normal <= DIRECTION_MASK); - voxel_t voxel = 0; - voxel |= block_has_occlusion(block) << OCCLUSION_OFFSET; - voxel |= normal << DIRECTION_OFFSET; - voxel |= block_has_shadow(block) << SHADOW_OFFSET; + SDL_COMPILE_TIME_ASSERT("", BLOCK_OFFSET + BLOCK_BITS <= 32); + SDL_assert(direction < DIRECTION_COUNT); + SDL_assert(block <= BLOCK_MASK); + SDL_assert(x <= X_MASK); + SDL_assert(y <= Y_MASK); + SDL_assert(z <= Z_MASK); + SDL_assert(u <= U_MASK); + SDL_assert(v <= V_MASK); + SDL_assert(direction <= DIRECTION_MASK); + SDL_assert(ao <= AO_MASK); + Voxel voxel = 0; + voxel |= direction << DIRECTION_OFFSET; + voxel |= block << BLOCK_OFFSET; + voxel |= ao << AO_OFFSET; voxel |= x << X_OFFSET; voxel |= y << Y_OFFSET; voxel |= z << Z_OFFSET; voxel |= u << U_OFFSET; voxel |= v << V_OFFSET; - voxel |= index << INDEX_OFFSET; return voxel; } -voxel_t voxel_pack_sprite(block_t block, int x, int y, int z, direction_t direction, int i) +Voxel Voxel_PackSprite(Block block, int x, int y, int z, Direction direction, int index) { - CHECK(block > BLOCK_EMPTY); - CHECK(block < BLOCK_COUNT); - CHECK(direction < 4); - CHECK(i < 4); - static const int POSITIONS[][4][3] = - { - {{0, 0, 0}, {0, 1, 0}, {1, 0, 1}, {1, 1, 1}}, - {{0, 0, 0}, {1, 0, 1}, {0, 1, 0}, {1, 1, 1}}, - {{0, 0, 1}, {1, 0, 0}, {0, 1, 1}, {1, 1, 0}}, - {{0, 0, 1}, {0, 1, 1}, {1, 0, 0}, {1, 1, 0}}, - }; - static const int TEXCOORDS[][4][2] = - { - {{1, 1}, {1, 0}, {0, 1}, {0, 0}}, - {{1, 1}, {0, 1}, {1, 0}, {0, 0}}, - {{1, 1}, {0, 1}, {1, 0}, {0, 0}}, - {{1, 1}, {1, 0}, {0, 1}, {0, 0}}, - }; - int a = POSITIONS[direction][i][0] + x; - int b = POSITIONS[direction][i][1] + y; - int c = POSITIONS[direction][i][2] + z; - int d = TEXCOORDS[direction][i][0]; - int e = TEXCOORDS[direction][i][1]; - return pack(block, a, b, c, d, e, DIRECTION_NORTH, DIRECTION_COUNT + direction); + SDL_assert(block > BLOCK_EMPTY); + SDL_assert(block < BLOCK_COUNT); + SDL_assert(direction < 4); + SDL_assert(index < 4); + const int* p = SPRITE_POSITIONS[direction][index]; + const int* t = TEXCOORDS[direction][index]; + return Voxel_Pack(block, x + p[0], y + p[1], z + p[2], t[0], t[1], DIRECTION_UP, AO_MASK); } -voxel_t voxel_pack_cube(block_t block, int x, int y, int z, direction_t direction, int i) +Voxel Voxel_PackCube(Block block, int x, int y, int z, Direction direction, int index, int ao) { - CHECK(block > BLOCK_EMPTY); - CHECK(block < BLOCK_COUNT); - CHECK(direction < 6); - CHECK(i < 4); - static const int POSITIONS[][4][3] = - { - {{0, 0, 1}, {0, 1, 1}, {1, 0, 1}, {1, 1, 1}}, - {{0, 0, 0}, {1, 0, 0}, {0, 1, 0}, {1, 1, 0}}, - {{1, 0, 0}, {1, 0, 1}, {1, 1, 0}, {1, 1, 1}}, - {{0, 0, 0}, {0, 1, 0}, {0, 0, 1}, {0, 1, 1}}, - {{0, 1, 0}, {1, 1, 0}, {0, 1, 1}, {1, 1, 1}}, - {{0, 0, 0}, {0, 0, 1}, {1, 0, 0}, {1, 0, 1}}, - }; - static const int TEXCOORDS[][4][2] = - { - {{1, 1}, {1, 0}, {0, 1}, {0, 0}}, - {{1, 1}, {0, 1}, {1, 0}, {0, 0}}, - {{1, 1}, {0, 1}, {1, 0}, {0, 0}}, - {{1, 1}, {1, 0}, {0, 1}, {0, 0}}, - {{0, 0}, {1, 0}, {0, 1}, {1, 1}}, - {{0, 0}, {0, 1}, {1, 0}, {1, 1}}, - }; - int a = POSITIONS[direction][i][0] + x; - int b = POSITIONS[direction][i][1] + y; - int c = POSITIONS[direction][i][2] + z; - int d = TEXCOORDS[direction][i][0]; - int e = TEXCOORDS[direction][i][1]; - return pack(block, a, b, c, d, e, direction, direction); + SDL_assert(block > BLOCK_EMPTY); + SDL_assert(block < BLOCK_COUNT); + SDL_assert(direction < 6); + SDL_assert(index < 4); + const int* p = CUBE_POSITIONS[direction][index]; + const int* t = TEXCOORDS[direction][index]; + return Voxel_Pack(block, x + p[0], y + p[1], z + p[2], t[0], t[1], direction, ao); } diff --git a/src/voxel.h b/src/voxel.h index 9f916903..7d2dcb62 100644 --- a/src/voxel.h +++ b/src/voxel.h @@ -5,7 +5,9 @@ #include "block.h" #include "direction.h" -typedef Uint32 voxel_t; +typedef Uint32 Voxel; -voxel_t voxel_pack_sprite(block_t block, int x, int y, int z, direction_t direction, int i); -voxel_t voxel_pack_cube(block_t block, int x, int y, int z, direction_t direction, int i); \ No newline at end of file +void Voxel_GetPosition(Direction direction, int index, int position[3]); +void Voxel_GetAO(const int ao[4], int order[4]); +Voxel Voxel_PackSprite(Block block, int x, int y, int z, Direction direction, int index); +Voxel Voxel_PackCube(Block block, int x, int y, int z, Direction direction, int index, int ao); diff --git a/src/voxel.inc b/src/voxel.inc index ca7e51b1..60db64b5 100644 --- a/src/voxel.inc +++ b/src/voxel.inc @@ -1,32 +1,29 @@ #ifndef INC #define INC -#define OCCLUSION_BITS 1 -#define DIRECTION_BITS 4 -#define SHADOW_BITS 1 +#define AO_BITS 2 +#define DIRECTION_BITS 3 +#define BLOCK_BITS 5 #define X_BITS 5 #define Y_BITS 8 #define Z_BITS 5 #define U_BITS 1 #define V_BITS 1 -#define INDEX_BITS 6 -#define OCCLUSION_OFFSET (0) -#define DIRECTION_OFFSET (OCCLUSION_OFFSET + OCCLUSION_BITS) -#define SHADOW_OFFSET (DIRECTION_OFFSET + DIRECTION_BITS) -#define X_OFFSET (6) -#define Y_OFFSET (11) -#define Z_OFFSET (19) +#define DIRECTION_OFFSET (0) +#define BLOCK_OFFSET (DIRECTION_OFFSET + DIRECTION_BITS) +#define AO_OFFSET (BLOCK_OFFSET + BLOCK_BITS) +#define X_OFFSET (AO_OFFSET + AO_BITS) +#define Y_OFFSET (X_OFFSET + X_BITS) +#define Z_OFFSET (Y_OFFSET + Y_BITS) #define U_OFFSET (Z_OFFSET + Z_BITS) #define V_OFFSET (U_OFFSET + U_BITS) -#define INDEX_OFFSET (V_OFFSET + V_BITS) -#define OCCLUSION_MASK ((1 << OCCLUSION_BITS) - 1) +#define AO_MASK ((1 << AO_BITS) - 1) #define DIRECTION_MASK ((1 << DIRECTION_BITS) - 1) -#define SHADOW_MASK ((1 << SHADOW_BITS) - 1) +#define BLOCK_MASK ((1 << BLOCK_BITS) - 1) #define X_MASK ((1 << X_BITS) - 1) #define Y_MASK ((1 << Y_BITS) - 1) #define Z_MASK ((1 << Z_BITS) - 1) #define U_MASK ((1 << U_BITS) - 1) #define V_MASK ((1 << V_BITS) - 1) -#define INDEX_MASK ((1 << INDEX_BITS) - 1) #endif diff --git a/src/worker.c b/src/worker.c new file mode 100644 index 00000000..81f48080 --- /dev/null +++ b/src/worker.c @@ -0,0 +1,90 @@ +#include + +#include "worker.h" + +static int WorkerFunction(void* args) +{ + Worker* worker = args; + while (true) + { + SDL_LockMutex(worker->mutex); + while (!worker->task && !worker->quit) + { + SDL_WaitCondition(worker->condition, worker->mutex); + } + if (worker->quit) + { + SDL_UnlockMutex(worker->mutex); + return 0; + } + WorkerTask task = worker->task; + void* data = worker->data; + SDL_UnlockMutex(worker->mutex); + task(data); + SDL_LockMutex(worker->mutex); + worker->task = NULL; + worker->data = NULL; + SDL_SignalCondition(worker->condition); + SDL_UnlockMutex(worker->mutex); + } +} + +void Worker_Init(Worker* worker) +{ + worker->task = NULL; + worker->data = NULL; + worker->quit = false; + worker->mutex = SDL_CreateMutex(); + if (!worker->mutex) + { + SDL_Log("Failed to create mutex: %s", SDL_GetError()); + } + worker->condition = SDL_CreateCondition(); + if (!worker->condition) + { + SDL_Log("Failed to create condition variable: %s", SDL_GetError()); + } + worker->thread = SDL_CreateThread(WorkerFunction, "worker", worker); + if (!worker->thread) + { + SDL_Log("Failed to create thread: %s", SDL_GetError()); + } +} + +void Worker_Free(Worker* worker) +{ + SDL_LockMutex(worker->mutex); + while (worker->task) + { + SDL_WaitCondition(worker->condition, worker->mutex); + } + worker->quit = true; + SDL_SignalCondition(worker->condition); + SDL_UnlockMutex(worker->mutex); + SDL_WaitThread(worker->thread, NULL); + SDL_DestroyMutex(worker->mutex); + SDL_DestroyCondition(worker->condition); + worker->thread = NULL; + worker->mutex = NULL; + worker->condition = NULL; +} + +bool Worker_IsBusy(Worker* worker) +{ + SDL_LockMutex(worker->mutex); + bool busy = worker->task != NULL; + SDL_UnlockMutex(worker->mutex); + return busy; +} + +void Worker_Dispatch(Worker* worker, WorkerTask task, void* data) +{ + SDL_assert(!Worker_IsBusy(worker)); + SDL_LockMutex(worker->mutex); + SDL_assert(!worker->task); + SDL_assert(!worker->quit); + worker->task = task; + worker->data = data; + SDL_SignalCondition(worker->condition); + SDL_UnlockMutex(worker->mutex); +} diff --git a/src/worker.h b/src/worker.h new file mode 100644 index 00000000..01f1733a --- /dev/null +++ b/src/worker.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +typedef void (*WorkerTask)(void* data); + +typedef struct Worker +{ + SDL_Thread* thread; + SDL_Mutex* mutex; + SDL_Condition* condition; + WorkerTask task; + void* data; + bool quit; +} Worker; + +void Worker_Init(Worker* worker); +void Worker_Free(Worker* worker); +bool Worker_IsBusy(Worker* worker); +void Worker_Dispatch(Worker* worker, WorkerTask task, void* data); diff --git a/src/world.c b/src/world.c index 4c910b3a..a6c6b00c 100644 --- a/src/world.c +++ b/src/world.c @@ -3,61 +3,47 @@ #include "block.h" #include "buffer.h" #include "camera.h" -#include "check.h" #include "map.h" #include "rand.h" #include "save.h" +#include "sort.h" #include "voxel.h" +#include "voxel.inc" +#include "worker.h" #include "world.h" #define WORKERS 4 -typedef enum job_type +typedef enum TaskType { - JOB_TYPE_NONE, - JOB_TYPE_QUIT, - JOB_TYPE_BLOCKS, - JOB_TYPE_VOXELS, - JOB_TYPE_LIGHTS, -} -job_type_t; - -typedef enum job_state -{ - JOB_STATE_REQUESTED, - JOB_STATE_RUNNING, - JOB_STATE_COMPLETED, -} -job_state_t; + TASK_TYPE_BLOCKS, + TASK_TYPE_VOXELS, + TASK_TYPE_LIGHTS, +} TaskType; -typedef enum mesh_type +typedef enum TaskState { - MESH_TYPE_OPAQUE, - MESH_TYPE_TRANSPARENT, - MESH_TYPE_COUNT, -} -mesh_type_t; + TASK_STATE_REQUESTED, + TASK_STATE_RUNNING, + TASK_STATE_COMPLETED, +} TaskState; -typedef struct job +typedef struct Task { - job_type_t type; + TaskType type; int x; int z; -} -job_t; +} Task; -typedef struct worker +typedef struct WorldWorker { - SDL_Thread* thread; - SDL_Mutex* mutex; - SDL_Condition* condition; - job_t job; - cpu_buffer_t voxels[MESH_TYPE_COUNT]; - cpu_buffer_t lights; -} -worker_t; + Worker worker; + Task task; + CPUBuffer voxels[WORLD_MESH_TYPE_COUNT]; + CPUBuffer lights; +} WorldWorker; -typedef struct chunk +typedef struct Chunk { SDL_AtomicInt block_state; SDL_AtomicInt voxel_state; @@ -71,66 +57,52 @@ typedef struct chunk }; Sint32 position[2]; }; - block_t blocks[CHUNK_WIDTH][CHUNK_HEIGHT][CHUNK_WIDTH]; - map_t lights; - gpu_buffer_t gpu_voxels[MESH_TYPE_COUNT]; - gpu_buffer_t gpu_lights; -} -chunk_t; + Block blocks[CHUNK_WIDTH][CHUNK_HEIGHT][CHUNK_WIDTH]; + Map lights; + GPUBuffer gpu_voxels[WORLD_MESH_TYPE_COUNT]; + GPUBuffer gpu_lights; +} Chunk; static SDL_GPUDevice* device; +static Chunk* chunks[WORLD_WIDTH][WORLD_WIDTH]; +static WorldWorker all_workers[WORKERS]; +static GPUBuffer gpu_indices; +static GPUBuffer gpu_empty_lights; +static CPUBuffer cpu_voxels[WORLD_MESH_TYPE_COUNT]; +static int sorted_chunks[WORLD_WIDTH * WORLD_WIDTH][2]; static int world_x; static int world_z; -static bool is_moving; -static worker_t workers[WORKERS]; -static cpu_buffer_t cpu_indices; -static gpu_buffer_t gpu_indices; -static cpu_buffer_t cpu_empty_lights; -static gpu_buffer_t gpu_empty_lights; -static cpu_buffer_t cpu_voxels[MESH_TYPE_COUNT]; -static chunk_t* chunks[WORLD_WIDTH][WORLD_WIDTH]; -static int sorted_chunks[WORLD_WIDTH][WORLD_WIDTH][2]; -static SDL_Mutex* mutex; -static bool is_block_local(int bx, int by, int bz) +static int FloorChunkIndex(float index) { - CHECK(by >= 0 && by < CHUNK_HEIGHT); - CHECK(bx >= -1 && bz >= -1 && bx <= CHUNK_WIDTH && bz <= CHUNK_WIDTH);; - return bx >= 0 && bz >= 0 && bx < CHUNK_WIDTH && bz < CHUNK_WIDTH; -} - -static void world_to_chunk(const chunk_t* chunk, int* bx, int* by, int* bz) -{ - *bx -= chunk->x; - *bz -= chunk->z; - CHECK(is_block_local(*bx, *by, *bz)); + return SDL_floorf(index / CHUNK_WIDTH); } -static void chunk_to_world(const chunk_t* chunk, int* bx, int* by, int* bz) +static bool IsBlockInChunk(int bx, int by, int bz) { - CHECK(*by >= 0 && *by < CHUNK_HEIGHT); - *bx += chunk->x; - *bz += chunk->z; + return bx >= 0 && bz >= 0 && bx < CHUNK_WIDTH && bz < CHUNK_WIDTH; } -static bool is_chunk_local(int cx, int cz) +static bool IsChunkInWorld(int cx, int cz) { return cx >= 0 && cz >= 0 && cx < WORLD_WIDTH && cz < WORLD_WIDTH; } -static bool is_chunk_on_border(int cx, int cz) +static bool IsChunkOnWorldBorder(int cx, int cz) { return cx == 0 || cz == 0 || cx == WORLD_WIDTH - 1 || cz == WORLD_WIDTH - 1; } -static int floor_chunk_index(float index) +static void WorldBlockToChunkBlock(const Chunk* chunk, int* bx, int* by, int* bz) { - return SDL_floorf(index / CHUNK_WIDTH); + *bx -= chunk->x; + *bz -= chunk->z; + SDL_assert(IsBlockInChunk(*bx, *by, *bz)); } -static chunk_t* get_chunk(int cx, int cz) +static Chunk* GetChunk(int cx, int cz) { - if (is_chunk_local(cx, cz)) + if (IsChunkInWorld(cx, cz)) { return chunks[cx][cz]; } @@ -140,120 +112,94 @@ static chunk_t* get_chunk(int cx, int cz) } } -static void get_neighborhood(int cx, int cz, chunk_t* neighborhood[3][3]) -{ - for (int i = -1; i <= 1; i++) - for (int j = -1; j <= 1; j++) - { - int x = cx + i; - int z = cz + j; - neighborhood[i + 1][j + 1] = get_chunk(x, z); - CHECK(neighborhood[i + 1][j + 1]); - } -} - -static mesh_type_t get_mesh_for_flags(world_flags_t flags) -{ - if (flags & WORLD_FLAGS_OPAQUE) - { - return MESH_TYPE_OPAQUE; - } - else - { - return MESH_TYPE_TRANSPARENT; - } -} - -static mesh_type_t get_mesh_for_block(block_t block) +static void GetGroup(int cx, int cz, Chunk* group[3][3]) { - if (block_is_opaque(block)) + for (int dx = -1; dx <= 1; dx++) + for (int dz = -1; dz <= 1; dz++) { - return MESH_TYPE_OPAQUE; - } - else - { - return MESH_TYPE_TRANSPARENT; + int x = cx + dx; + int z = cz + dz; + group[dx + 1][dz + 1] = GetChunk(x, z); + SDL_assert(group[dx + 1][dz + 1]); } } -static chunk_t* create_chunk() +static Chunk* CreateChunk() { - chunk_t* chunk = SDL_malloc(sizeof(chunk_t)); + Chunk* chunk = SDL_calloc(1, sizeof(Chunk)); if (!chunk) { SDL_Log("Failed to allocate chunk"); + return NULL; } - SDL_SetAtomicInt(&chunk->block_state, JOB_STATE_REQUESTED); - SDL_SetAtomicInt(&chunk->voxel_state, JOB_STATE_COMPLETED); - SDL_SetAtomicInt(&chunk->light_state, JOB_STATE_COMPLETED); - chunk->x = 0; - chunk->z = 0; - map_init(&chunk->lights, 8); - for (int i = 0; i < MESH_TYPE_COUNT; i++) + SDL_SetAtomicInt(&chunk->block_state, TASK_STATE_REQUESTED); + SDL_SetAtomicInt(&chunk->voxel_state, TASK_STATE_COMPLETED); + SDL_SetAtomicInt(&chunk->light_state, TASK_STATE_COMPLETED); + Map_Init(&chunk->lights, 8); + for (int i = 0; i < WORLD_MESH_TYPE_COUNT; i++) { - gpu_buffer_init(&chunk->gpu_voxels[i], device, SDL_GPU_BUFFERUSAGE_VERTEX); + GPUBuffer_Init(&chunk->gpu_voxels[i], device, SDL_GPU_BUFFERUSAGE_VERTEX); } - gpu_buffer_init(&chunk->gpu_lights, device, SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ); + GPUBuffer_Init(&chunk->gpu_lights, device, SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ); return chunk; } -static void free_chunk(chunk_t* chunk) +static void FreeChunk(Chunk* chunk) { - gpu_buffer_free(&chunk->gpu_lights); - for (int i = 0; i < MESH_TYPE_COUNT; i++) + GPUBuffer_Free(&chunk->gpu_lights); + for (int i = 0; i < WORLD_MESH_TYPE_COUNT; i++) { - gpu_buffer_free(&chunk->gpu_voxels[i]); + GPUBuffer_Free(&chunk->gpu_voxels[i]); } - SDL_memset(chunk->blocks, 0, sizeof(chunk->blocks)); - map_free(&chunk->lights); + Map_Free(&chunk->lights); SDL_free(chunk); } -static block_t set_chunk_block(chunk_t* chunk, int bx, int by, int bz, block_t block) +static Block SetChunkBlock(Chunk* chunk, int bx, int by, int bz, Block block) { - SDL_SetAtomicInt(&chunk->voxel_state, JOB_STATE_REQUESTED); - world_to_chunk(chunk, &bx, &by, &bz); + SDL_SetAtomicInt(&chunk->voxel_state, TASK_STATE_REQUESTED); + WorldBlockToChunkBlock(chunk, &bx, &by, &bz); + Block old_block = chunk->blocks[bx][by][bz]; chunk->blocks[bx][by][bz] = block; - block_t old_block = map_get(&chunk->lights, bx, by, bz); - if (!block_is_light(block) && !block_is_light(old_block)) + if (!Block_IsLight(block) && !Block_IsLight(old_block)) { return old_block; } - SDL_SetAtomicInt(&chunk->light_state, JOB_STATE_REQUESTED); - if (block_is_light(block)) + SDL_SetAtomicInt(&chunk->light_state, TASK_STATE_REQUESTED); + if (Block_IsLight(block)) { - map_set(&chunk->lights, bx, by, bz, block); + Map_Set(&chunk->lights, bx, by, bz, block); } else { - map_remove(&chunk->lights, bx, by, bz); + Map_Remove(&chunk->lights, bx, by, bz); } return old_block; } -static void set_chunk_block_function(void* userdata, int bx, int by, int bz, block_t block) +static void SetChunkBlockFunction(void* userdata, int bx, int by, int bz, Block block) { - chunk_t* chunk = userdata; - CHECK(SDL_GetAtomicInt(&chunk->block_state) == JOB_STATE_RUNNING); - set_chunk_block(userdata, bx, by, bz, block); + Chunk* chunk = userdata; + SDL_assert(SDL_GetAtomicInt(&chunk->block_state) == TASK_STATE_RUNNING); + SetChunkBlock(userdata, bx, by, bz, block); } -static block_t get_chunk_block(chunk_t* chunk, int bx, int by, int bz) +static Block GetChunkBlock(Chunk* chunk, int bx, int by, int bz) { - CHECK(SDL_GetAtomicInt(&chunk->block_state) == JOB_STATE_COMPLETED); - world_to_chunk(chunk, &bx, &by, &bz); + SDL_assert(SDL_GetAtomicInt(&chunk->block_state) == TASK_STATE_COMPLETED); + WorldBlockToChunkBlock(chunk, &bx, &by, &bz); return chunk->blocks[bx][by][bz]; } -static block_t get_neighborhood_block(chunk_t* chunks[3][3], int bx, int by, int bz, int dx, int dy, int dz) +static Block GetGroupBlock(Chunk* chunks[3][3], int bx, int by, int bz, int dx, int dy, int dz) { - CHECK(dx >= -1 && dx <= 1); - CHECK(dy >= -1 && dy <= 1); - CHECK(dz >= -1 && dz <= 1); + SDL_assert(dx >= -1 && dx <= 1); + SDL_assert(dy >= -1 && dy <= 1); + SDL_assert(dz >= -1 && dz <= 1); bx += dx; by += dy; bz += dz; - const chunk_t* chunk = chunks[1][1]; + const Chunk* chunk = chunks[1][1]; if (by == CHUNK_HEIGHT) { return BLOCK_EMPTY; @@ -262,848 +208,717 @@ static block_t get_neighborhood_block(chunk_t* chunks[3][3], int bx, int by, int { return BLOCK_GRASS; } - else if (is_block_local(bx, by, bz)) + else if (IsBlockInChunk(bx, by, bz)) { return chunk->blocks[bx][by][bz]; } - chunk_to_world(chunk, &bx, &by, &bz); - chunk_t* neighbor = chunks[dx + 1][dz + 1]; - CHECK(neighbor); - return get_chunk_block(neighbor, bx, by, bz); + int cx = 1; + int cz = 1; + if (bx < 0) + { + cx = 0; + bx += CHUNK_WIDTH; + } + else if (bx >= CHUNK_WIDTH) + { + cx = 2; + bx -= CHUNK_WIDTH; + } + if (bz < 0) + { + cz = 0; + bz += CHUNK_WIDTH; + } + else if (bz >= CHUNK_WIDTH) + { + cz = 2; + bz -= CHUNK_WIDTH; + } + Chunk* neighbor = chunks[cx][cz]; + SDL_assert(neighbor); + SDL_assert(SDL_GetAtomicInt(&neighbor->block_state) == TASK_STATE_COMPLETED); + return neighbor->blocks[bx][by][bz]; } -static void upload_voxels(chunk_t* chunk, cpu_buffer_t voxels[MESH_TYPE_COUNT]) +static void UploadVoxels(Chunk* chunk, CPUBuffer voxels[WORLD_MESH_TYPE_COUNT]) { - CHECK(SDL_GetAtomicInt(&chunk->block_state) == JOB_STATE_COMPLETED); - CHECK(SDL_GetAtomicInt(&chunk->voxel_state) == JOB_STATE_RUNNING); + SDL_assert(SDL_GetAtomicInt(&chunk->block_state) == TASK_STATE_COMPLETED); + SDL_assert(SDL_GetAtomicInt(&chunk->voxel_state) == TASK_STATE_RUNNING); bool has_voxels = false; - for (int i = 0; i < MESH_TYPE_COUNT; i++) + for (int i = 0; i < WORLD_MESH_TYPE_COUNT; i++) { - gpu_buffer_clear(&chunk->gpu_voxels[i]); + GPUBuffer_Clear(&chunk->gpu_voxels[i]); has_voxels |= voxels[i].size > 0; } - if (!has_voxels) - { - return; - } - if (!gpu_buffer_begin_upload(&chunk->gpu_voxels[0])) + if (!has_voxels || !GPUBuffer_BeginUpload(&chunk->gpu_voxels[0])) { return; } - for (int i = 0; i < MESH_TYPE_COUNT; i++) + for (int i = 0; i < WORLD_MESH_TYPE_COUNT; i++) { - gpu_buffer_upload(&chunk->gpu_voxels[i], &voxels[i]); + GPUBuffer_Upload(&chunk->gpu_voxels[i], &voxels[i]); } - gpu_buffer_end_upload(&chunk->gpu_voxels[0]); + GPUBuffer_EndUpload(); } -static void upload_lights(chunk_t* chunk, cpu_buffer_t* lights) +static void UploadLights(Chunk* chunk, CPUBuffer* lights) { - CHECK(SDL_GetAtomicInt(&chunk->block_state) == JOB_STATE_COMPLETED); - CHECK(SDL_GetAtomicInt(&chunk->light_state) == JOB_STATE_RUNNING); - gpu_buffer_clear(&chunk->gpu_lights); + SDL_assert(SDL_GetAtomicInt(&chunk->block_state) == TASK_STATE_COMPLETED); + SDL_assert(SDL_GetAtomicInt(&chunk->light_state) == TASK_STATE_RUNNING); + GPUBuffer_Clear(&chunk->gpu_lights); if (!lights->size) { return; } - if (!gpu_buffer_begin_upload(&chunk->gpu_lights)) + if (!GPUBuffer_BeginUpload(&chunk->gpu_lights)) { return; } - gpu_buffer_upload(&chunk->gpu_lights, lights); - gpu_buffer_end_upload(&chunk->gpu_lights); + GPUBuffer_Upload(&chunk->gpu_lights, lights); + GPUBuffer_EndUpload(); } -static bool is_visible(block_t block, block_t neighbor) +static bool IsVisible(Block block, Block neighbor) { if (neighbor == BLOCK_EMPTY) { return true; } - if (block_is_sprite(neighbor)) + if (Block_IsSprite(neighbor)) { return true; } - if (block_is_opaque(block) && !block_is_opaque(neighbor)) + if (Block_IsOpaque(block) && !Block_IsOpaque(neighbor)) { return true; } return false; } -static void gen_chunk_blocks(chunk_t* chunk) +static int GetAO(Chunk* chunks[3][3], int bx, int by, int bz, Direction direction, int vertex) { - CHECK(SDL_GetAtomicInt(&chunk->block_state) == JOB_STATE_RUNNING); - CHECK(SDL_GetAtomicInt(&chunk->voxel_state) == JOB_STATE_REQUESTED); - CHECK(SDL_GetAtomicInt(&chunk->light_state) == JOB_STATE_REQUESTED); - SDL_memset(chunk->blocks, 0, sizeof(chunk->blocks)); - map_clear(&chunk->lights); - rand_get_blocks(chunk, chunk->x, chunk->z, set_chunk_block_function); - save_get_blocks(chunk, chunk->x, chunk->z, set_chunk_block_function); - CHECK(SDL_GetAtomicInt(&chunk->block_state) == JOB_STATE_RUNNING); - SDL_SetAtomicInt(&chunk->block_state, JOB_STATE_COMPLETED); - if (SDL_GetAtomicInt(&chunk->voxel_state) == JOB_STATE_REQUESTED) + int position[3]; + Voxel_GetPosition(direction, vertex, position); + int side1[3] = {DIRECTIONS[direction][0], DIRECTIONS[direction][1], DIRECTIONS[direction][2]}; + int side2[3] = {DIRECTIONS[direction][0], DIRECTIONS[direction][1], DIRECTIONS[direction][2]}; + int corner[3] = {DIRECTIONS[direction][0], DIRECTIONS[direction][1], DIRECTIONS[direction][2]}; + int sides = 0; + for (int i = 0; i < 3; i++) + { + if (DIRECTIONS[direction][i]) + { + continue; + } + int offset = position[i] ? 1 : -1; + if (sides++ == 0) + { + side1[i] = offset; + } + else + { + side2[i] = offset; + } + corner[i] = offset; + } + SDL_assert(sides == 2); + bool has_side1 = Block_UseAO(GetGroupBlock(chunks, bx, by, bz, side1[0], side1[1], side1[2])); + bool has_side2 = Block_UseAO(GetGroupBlock(chunks, bx, by, bz, side2[0], side2[1], side2[2])); + bool has_corner = Block_UseAO(GetGroupBlock(chunks, bx, by, bz, corner[0], corner[1], corner[2])); + if (!has_side1 || !has_side2) { - SDL_SetAtomicInt(&chunk->light_state, JOB_STATE_REQUESTED); + return AO_MASK - has_side1 - has_side2 - has_corner; } + else + { + return 0; + } +} + +static void GenerateChunkBlocks(Chunk* chunk) +{ + SDL_assert(SDL_GetAtomicInt(&chunk->block_state) == TASK_STATE_RUNNING); + SDL_assert(SDL_GetAtomicInt(&chunk->voxel_state) == TASK_STATE_REQUESTED); + SDL_assert(SDL_GetAtomicInt(&chunk->light_state) == TASK_STATE_REQUESTED); + SDL_memset(chunk->blocks, 0, sizeof(chunk->blocks)); + Map_Clear(&chunk->lights); + Rand_GetBlocks(chunk, chunk->x, chunk->z, SetChunkBlockFunction); + Save_GetBlocks(chunk, chunk->x, chunk->z, SetChunkBlockFunction); + SDL_assert(SDL_GetAtomicInt(&chunk->block_state) == TASK_STATE_RUNNING); + SDL_SetAtomicInt(&chunk->block_state, TASK_STATE_COMPLETED); } -static void gen_chunk_voxels(chunk_t* chunks[3][3], cpu_buffer_t voxels[MESH_TYPE_COUNT]) +static void GenerateChunkVoxels(Chunk* chunks[3][3], CPUBuffer voxels[WORLD_MESH_TYPE_COUNT]) { - chunk_t* chunk = chunks[1][1]; - CHECK(SDL_GetAtomicInt(&chunk->block_state) == JOB_STATE_COMPLETED); - CHECK(SDL_GetAtomicInt(&chunk->voxel_state) == JOB_STATE_RUNNING); + Chunk* chunk = chunks[1][1]; + SDL_assert(SDL_GetAtomicInt(&chunk->block_state) == TASK_STATE_COMPLETED); + SDL_assert(SDL_GetAtomicInt(&chunk->voxel_state) == TASK_STATE_RUNNING); for (int bx = 0; bx < CHUNK_WIDTH; bx++) for (int by = 0; by < CHUNK_HEIGHT; by++) for (int bz = 0; bz < CHUNK_WIDTH; bz++) { - block_t block = chunk->blocks[bx][by][bz]; + Block block = chunk->blocks[bx][by][bz]; if (block == BLOCK_EMPTY) { continue; } - if (block_is_sprite(block)) + if (Block_IsSprite(block)) { - for (int j = 0; j < 4; j++) - for (int k = 0; k < 4; k++) + for (Direction direction = 0; direction < 4; direction++) + for (int vertex = 0; vertex < 4; vertex++) { - voxel_t voxel = voxel_pack_sprite(block, bx, by, bz, j, k); - cpu_buffer_append(&voxels[MESH_TYPE_OPAQUE], &voxel); + Voxel voxel = Voxel_PackSprite(block, bx, by, bz, direction, vertex); + CPUBuffer_Append(&voxels[WORLD_MESH_TYPE_OPAQUE], &voxel); } continue; } - for (int j = 0; j < 6; j++) - { - int dx = DIRECTIONS[j][0]; - int dy = DIRECTIONS[j][1]; - int dz = DIRECTIONS[j][2]; - block_t neighbor = get_neighborhood_block(chunks, bx, by, bz, dx, dy, dz); - if (!is_visible(block, neighbor)) + WorldMeshType type = Block_IsOpaque(block) ? WORLD_MESH_TYPE_OPAQUE : WORLD_MESH_TYPE_TRANSPARENT; + for (Direction direction = 0; direction < DIRECTION_COUNT; direction++) + { + int dx = DIRECTIONS[direction][0]; + int dy = DIRECTIONS[direction][1]; + int dz = DIRECTIONS[direction][2]; + Block neighbor = GetGroupBlock(chunks, bx, by, bz, dx, dy, dz); + if (!IsVisible(block, neighbor)) { continue; } - for (int k = 0; k < 4; k++) + int ao[4]; + for (int i = 0; i < 4; i++) { - voxel_t voxel = voxel_pack_cube(block, bx, by, bz, j, k); - cpu_buffer_append(&voxels[get_mesh_for_block(block)], &voxel); + ao[i] = GetAO(chunks, bx, by, bz, direction, i); + } + int order[4]; + Voxel_GetAO(ao, order); + for (int i = 0; i < 4; i++) + { + int index = order[i]; + Voxel voxel = Voxel_PackCube(block, bx, by, bz, direction, index, ao[index]); + CPUBuffer_Append(&voxels[type], &voxel); } } } - upload_voxels(chunk, voxels); - SDL_SetAtomicInt(&chunk->voxel_state, JOB_STATE_COMPLETED); -} - -static void regen_chunk_voxels(int x, int z) -{ - CHECK(!is_chunk_on_border(x, z)); - chunk_t* chunks[3][3] = {0}; - get_neighborhood(x, z, chunks); - SDL_SetAtomicInt(&chunks[1][1]->voxel_state, JOB_STATE_RUNNING); - gen_chunk_voxels(chunks, cpu_voxels); + UploadVoxels(chunk, voxels); + SDL_SetAtomicInt(&chunk->voxel_state, TASK_STATE_COMPLETED); } -static void gen_chunk_lights(chunk_t* chunks[3][3], cpu_buffer_t* lights) +static void GenerateChunkLights(Chunk* chunks[3][3], CPUBuffer* lights) { - chunk_t* chunk = chunks[1][1]; - CHECK(SDL_GetAtomicInt(&chunk->block_state) == JOB_STATE_COMPLETED); - CHECK(SDL_GetAtomicInt(&chunk->light_state) == JOB_STATE_RUNNING); - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) + Chunk* chunk = chunks[1][1]; + SDL_assert(SDL_GetAtomicInt(&chunk->block_state) == TASK_STATE_COMPLETED); + SDL_assert(SDL_GetAtomicInt(&chunk->light_state) == TASK_STATE_RUNNING); + for (int x = 0; x < 3; x++) + for (int z = 0; z < 3; z++) { - const chunk_t* neighbor = chunks[i][j]; - CHECK(neighbor); + const Chunk* neighbor = chunks[x][z]; + SDL_assert(neighbor); for (Uint32 i = 0; i < neighbor->lights.capacity; i++) { - if (!map_is_row_valid(&neighbor->lights, i)) + if (!Map_IsRowValid(&neighbor->lights, i)) { continue; } - map_row_t row = map_get_row(&neighbor->lights, i); - CHECK(row.value != BLOCK_EMPTY); - CHECK(block_is_light(row.value)); - light_t light = block_get_light(row.value); + MapRow row = Map_GetRow(&neighbor->lights, i); + Block block = row.value; + SDL_assert(Block_IsLight(block)); + Light light = Block_GetLight(block); light.x = neighbor->x + row.x; light.y = row.y; light.z = neighbor->z + row.z; - cpu_buffer_append(lights, &light); + CPUBuffer_Append(lights, &light); } } - upload_lights(chunk, lights); - SDL_SetAtomicInt(&chunk->light_state, JOB_STATE_COMPLETED); + UploadLights(chunk, lights); + SDL_SetAtomicInt(&chunk->light_state, TASK_STATE_COMPLETED); } -static void gen_lights() +static void GenerateEmptyLightBuffer() { - if (!gpu_buffer_begin_upload(&gpu_empty_lights)) + CPUBuffer lights; + CPUBuffer_Init(&lights, device, sizeof(Light)); + if (!GPUBuffer_BeginUpload(&gpu_empty_lights)) { + CPUBuffer_Free(&lights); return; } - light_t light = {0}; - cpu_buffer_append(&cpu_empty_lights, &light); - gpu_buffer_upload(&gpu_empty_lights, &cpu_empty_lights); - gpu_buffer_end_upload(&gpu_empty_lights); + Light light = {0}; + CPUBuffer_Append(&lights, &light); + GPUBuffer_Upload(&gpu_empty_lights, &lights); + GPUBuffer_EndUpload(); + CPUBuffer_Free(&lights); } -static void gen_indices(Uint32 size) +static void GenerateIndexBuffer() { - SDL_LockMutex(mutex); - size *= 1.5; - if (gpu_indices.size >= size) - { - SDL_UnlockMutex(mutex); - return; - } - if (!gpu_buffer_begin_upload(&gpu_indices)) + CPUBuffer indices; + CPUBuffer_Init(&indices, device, sizeof(Uint32)); + if (!GPUBuffer_BeginUpload(&gpu_indices)) { - SDL_UnlockMutex(mutex); + CPUBuffer_Free(&indices); return; } static const int INDICES[] = {0, 1, 2, 3, 2, 1}; - for (Uint32 i = 0; i < size; i++) + Uint32 max_indices = CHUNK_WIDTH * CHUNK_HEIGHT * CHUNK_WIDTH * DIRECTION_COUNT * 6; + for (Uint32 i = 0; i < max_indices / 6; i++) for (Uint32 j = 0; j < 6; j++) { Uint32 index = i * 4 + INDICES[j]; - cpu_buffer_append(&cpu_indices, &index); - } - gpu_buffer_upload(&gpu_indices, &cpu_indices); - gpu_buffer_end_upload(&gpu_indices); - SDL_UnlockMutex(mutex); -} - -static void wait_for_job(worker_t* worker) -{ - SDL_LockMutex(worker->mutex); - while (worker->job.type == JOB_TYPE_NONE) - { - SDL_WaitCondition(worker->condition, worker->mutex); + CPUBuffer_Append(&indices, &index); } - SDL_UnlockMutex(worker->mutex); + GPUBuffer_Upload(&gpu_indices, &indices); + GPUBuffer_EndUpload(); + CPUBuffer_Free(&indices); } -static void wait_for_job_finish(const worker_t* worker) +static void TaskFunction(void* args) { - SDL_LockMutex(worker->mutex); - while (worker->job.type != JOB_TYPE_NONE) + WorldWorker* worker = args; + Task task = worker->task; + Chunk* chunk = GetChunk(task.x, task.z); + SDL_assert(chunk); + if (task.type == TASK_TYPE_BLOCKS) { - SDL_WaitCondition(worker->condition, worker->mutex); + GenerateChunkBlocks(chunk); + return; } - SDL_UnlockMutex(worker->mutex); -} - -static int clear_job(worker_t* worker) -{ - SDL_LockMutex(worker->mutex); - SDL_assert(worker->job.type != JOB_TYPE_NONE); - worker->job.type = JOB_TYPE_NONE; - SDL_SignalCondition(worker->condition); - SDL_UnlockMutex(worker->mutex); - return 0; -} - -static int worker_function(void* args) -{ - worker_t* worker = args; - while (true) + Chunk* chunks[3][3]; + GetGroup(task.x, task.z, chunks); + if (task.type == TASK_TYPE_VOXELS) { - wait_for_job(worker); - job_t job = worker->job; - if (job.type == JOB_TYPE_QUIT) - { - return clear_job(worker); - } - chunk_t* chunk = get_chunk(job.x, job.z); - CHECK(chunk); - if (job.type == JOB_TYPE_BLOCKS) - { - gen_chunk_blocks(chunk); - } - else - { - chunk_t* chunks[3][3]; - get_neighborhood(job.x, job.z, chunks); - if (job.type == JOB_TYPE_VOXELS) - { - gen_chunk_voxels(chunks, worker->voxels); - for (int i = 0; i < MESH_TYPE_COUNT; i++) - { - gen_indices(chunk->gpu_voxels[i].size); - } - } - else if (job.type == JOB_TYPE_LIGHTS) - { - gen_chunk_lights(chunks, &worker->lights); - } - else - { - CHECK(false); - } - } - clear_job(worker); + GenerateChunkVoxels(chunks, worker->voxels); } - return 0; -} - -static bool is_job_running(const worker_t* worker) -{ - SDL_LockMutex(worker->mutex); - if (worker->job.type != JOB_TYPE_NONE) + else if (task.type == TASK_TYPE_LIGHTS) { - SDL_UnlockMutex(worker->mutex); - return true; + GenerateChunkLights(chunks, &worker->lights); } else { - SDL_UnlockMutex(worker->mutex); - return false; - } -} - -static SDL_AtomicInt* get_job_state(chunk_t* chunk, job_type_t type) -{ - switch (type) - { - case JOB_TYPE_BLOCKS: - return &chunk->block_state; - case JOB_TYPE_VOXELS: - return &chunk->voxel_state; - case JOB_TYPE_LIGHTS: - return &chunk->light_state; - default: - return NULL; + SDL_assert(false); } } -static void dispatch_job(worker_t* worker, const job_t* job) +static bool TryDispatchTask(int x, int z, WorldWorker* worker) { - if (job->type != JOB_TYPE_QUIT) + SDL_assert(IsChunkInWorld(x, z)); + SDL_assert(!Worker_IsBusy(&worker->worker)); + Chunk* chunk = chunks[x][z]; + worker->task.x = x; + worker->task.z = z; + if (SDL_GetAtomicInt(&chunk->block_state) == TASK_STATE_REQUESTED) { - CHECK(!is_job_running(worker)); - chunk_t* chunk = get_chunk(job->x, job->z); - SDL_SetAtomicInt(get_job_state(chunk, job->type), JOB_STATE_RUNNING); + worker->task.type = TASK_TYPE_BLOCKS; + SDL_SetAtomicInt(&chunk->block_state, TASK_STATE_RUNNING); } else { - wait_for_job_finish(worker); - } - SDL_LockMutex(worker->mutex); - CHECK(worker->job.type == JOB_TYPE_NONE); - worker->job = *job; - SDL_SignalCondition(worker->condition); - SDL_UnlockMutex(worker->mutex); -} - -static void start_worker(worker_t* worker) -{ - for (int i = 0; i < MESH_TYPE_COUNT; i++) - { - cpu_buffer_init(&worker->voxels[i], device, sizeof(voxel_t)); - } - cpu_buffer_init(&worker->lights, device, sizeof(light_t)); - worker->mutex = SDL_CreateMutex(); - if (!worker->mutex) - { - SDL_Log("Failed to create mutex: %s", SDL_GetError()); - } - worker->condition = SDL_CreateCondition(); - if (!worker->condition) - { - SDL_Log("Failed to create condition variable: %s", SDL_GetError()); - } - worker->thread = SDL_CreateThread(worker_function, "worker", worker); - if (!worker->thread) - { - SDL_Log("Failed to create thread: %s", SDL_GetError()); + if (IsChunkOnWorldBorder(x, z)) + { + return false; + } + bool voxels = SDL_GetAtomicInt(&chunk->voxel_state) == TASK_STATE_REQUESTED; + bool lights = SDL_GetAtomicInt(&chunk->light_state) == TASK_STATE_REQUESTED; + if (!voxels && !lights) + { + return false; + } + Chunk* group[3][3]; + GetGroup(x, z, group); + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + { + if (SDL_GetAtomicInt(&group[i][j]->block_state) != TASK_STATE_COMPLETED) + { + return false; + } + } + if (voxels) + { + worker->task.type = TASK_TYPE_VOXELS; + SDL_SetAtomicInt(&chunk->voxel_state, TASK_STATE_RUNNING); + } + else + { + worker->task.type = TASK_TYPE_LIGHTS; + SDL_SetAtomicInt(&chunk->light_state, TASK_STATE_RUNNING); + } } + Worker_Dispatch(&worker->worker, TaskFunction, worker); + return true; } -static void stop_worker(worker_t* worker) -{ - job_t job = {0}; - job.type = JOB_TYPE_QUIT; - dispatch_job(worker, &job); - SDL_WaitThread(worker->thread, NULL); - SDL_DestroyMutex(worker->mutex); - SDL_DestroyCondition(worker->condition); - worker->thread = NULL; - worker->mutex = NULL; - worker->condition = NULL; - for (int i = 0; i < MESH_TYPE_COUNT; i++) - { - cpu_buffer_free(&worker->voxels[i]); - } - cpu_buffer_free(&worker->lights); -} - -static int sort_function(void* userdata, const void* lhs, const void* rhs) +static int GetWorkers(WorldWorker* workers[WORKERS]) { - int w = WORLD_WIDTH / 2; - const int* l = lhs; - const int* r = rhs; - int a = (l[0] - w) * (l[0] - w) + (l[1] - w) * (l[1] - w); - int b = (r[0] - w) * (r[0] - w) + (r[1] - w) * (r[1] - w); - if (a < b) - { - return -1; - } - else if (a > b) + int count = 0; + for (int i = 0; i < WORKERS; i++) { - return 1; + if (!Worker_IsBusy(&all_workers[i].worker)) + { + workers[count++] = &all_workers[i]; + } } - return 0; + return count; } -void world_init(SDL_GPUDevice* handle) +void World_Init(SDL_GPUDevice* gpu_device) { - mutex = SDL_CreateMutex(); - if (!mutex) - { - SDL_Log("Failed to create mutex: %s", SDL_GetError()); - } - device = handle; + device = gpu_device; world_x = SDL_MAX_SINT32; world_z = SDL_MAX_SINT32; - cpu_buffer_init(&cpu_indices, device, sizeof(Uint32)); - gpu_buffer_init(&gpu_indices, device, SDL_GPU_BUFFERUSAGE_INDEX); - cpu_buffer_init(&cpu_empty_lights, device, sizeof(light_t)); - gpu_buffer_init(&gpu_empty_lights, device, SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ); - for (int i = 0; i < MESH_TYPE_COUNT; i++) + GPUBuffer_Init(&gpu_indices, device, SDL_GPU_BUFFERUSAGE_INDEX); + GPUBuffer_Init(&gpu_empty_lights, device, SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ); + for (int i = 0; i < WORLD_MESH_TYPE_COUNT; i++) { - cpu_buffer_init(&cpu_voxels[i], device, sizeof(voxel_t)); + CPUBuffer_Init(&cpu_voxels[i], device, sizeof(Voxel)); } for (int i = 0; i < WORKERS; i++) { - start_worker(&workers[i]); + WorldWorker* worker = &all_workers[i]; + for (int j = 0; j < WORLD_MESH_TYPE_COUNT; j++) + { + CPUBuffer_Init(&worker->voxels[j], device, sizeof(Voxel)); + } + CPUBuffer_Init(&worker->lights, device, sizeof(Light)); + Worker_Init(&worker->worker); } for (int x = 0; x < WORLD_WIDTH; x++) for (int z = 0; z < WORLD_WIDTH; z++) { - chunks[x][z] = create_chunk(); - sorted_chunks[x][z][0] = x; - sorted_chunks[x][z][1] = z; + chunks[x][z] = CreateChunk(); + int index = x * WORLD_WIDTH + z; + sorted_chunks[index][0] = x; + sorted_chunks[index][1] = z; } - SDL_qsort_r(sorted_chunks, WORLD_WIDTH * WORLD_WIDTH, sizeof(int) * 2, sort_function, NULL); - gen_lights(); - gen_indices(1000000); + Sort_Distance2D(sorted_chunks, WORLD_WIDTH * WORLD_WIDTH, WORLD_WIDTH / 2); + GenerateEmptyLightBuffer(); + GenerateIndexBuffer(); } -void world_free() +void World_Free() { for (int i = 0; i < WORKERS; i++) { - stop_worker(&workers[i]); + WorldWorker* worker = &all_workers[i]; + Worker_Free(&worker->worker); + for (int i = 0; i < WORLD_MESH_TYPE_COUNT; i++) + { + CPUBuffer_Free(&worker->voxels[i]); + } + CPUBuffer_Free(&worker->lights); } for (int x = 0; x < WORLD_WIDTH; x++) for (int z = 0; z < WORLD_WIDTH; z++) { - free_chunk(chunks[x][z]); - } - cpu_buffer_free(&cpu_indices); - gpu_buffer_free(&gpu_indices); - cpu_buffer_free(&cpu_empty_lights); - gpu_buffer_free(&gpu_empty_lights); - for (int i = 0; i < MESH_TYPE_COUNT; i++) - { - cpu_buffer_free(&cpu_voxels[i]); - } - SDL_DestroyMutex(mutex); -} - -static int get_running_count() -{ - int num_running = 0; - for (int i = 0; i < WORKERS; i++) - { - if (is_job_running(&workers[i])) - { - num_running++; - } + FreeChunk(chunks[x][z]); } - return num_running; -} - -static int get_workers(worker_t* local_workers[WORKERS]) -{ - int num_workers = 0; - for (int i = 0; i < WORKERS; i++) + GPUBuffer_Free(&gpu_indices); + GPUBuffer_Free(&gpu_empty_lights); + for (int i = 0; i < WORLD_MESH_TYPE_COUNT; i++) { - if (!is_job_running(&workers[i])) - { - local_workers[num_workers++] = &workers[i]; - } + CPUBuffer_Free(&cpu_voxels[i]); } - return num_workers; } -static void shuffle(int offset_x, int offset_z) +static void Shuffle(int dx, int dz) { - world_x += offset_x; - world_z += offset_z; - chunk_t* in[WORLD_WIDTH][WORLD_WIDTH] = {0}; - chunk_t* out[WORLD_WIDTH * WORLD_WIDTH] = {0}; - int size = 0; + world_x += dx; + world_z += dz; + Chunk* kept[WORLD_WIDTH][WORLD_WIDTH] = {0}; + Chunk* recycled[WORLD_WIDTH * WORLD_WIDTH] = {0}; + int count = 0; for (int x = 0; x < WORLD_WIDTH; x++) for (int z = 0; z < WORLD_WIDTH; z++) { - CHECK(chunks[x][z]); - const int a = x - offset_x; - const int b = z - offset_z; - if (is_chunk_local(a, b)) + SDL_assert(chunks[x][z]); + int new_x = x - dx; + int new_z = z - dz; + if (IsChunkInWorld(new_x, new_z)) { - in[a][b] = chunks[x][z]; + kept[new_x][new_z] = chunks[x][z]; } else { - out[size++] = chunks[x][z]; + recycled[count++] = chunks[x][z]; } chunks[x][z] = NULL; } - SDL_memcpy(chunks, in, sizeof(in)); + SDL_memcpy(chunks, kept, sizeof(kept)); for (int x = 0; x < WORLD_WIDTH; x++) for (int z = 0; z < WORLD_WIDTH; z++) { if (!chunks[x][z]) { - CHECK(size > 0); - chunk_t* chunk = out[--size]; - SDL_SetAtomicInt(&chunk->block_state, JOB_STATE_REQUESTED); - SDL_SetAtomicInt(&chunk->voxel_state, JOB_STATE_REQUESTED); - SDL_SetAtomicInt(&chunk->light_state, JOB_STATE_REQUESTED); + SDL_assert(count > 0); + Chunk* chunk = recycled[--count]; + SDL_SetAtomicInt(&chunk->block_state, TASK_STATE_REQUESTED); + SDL_SetAtomicInt(&chunk->voxel_state, TASK_STATE_REQUESTED); + SDL_SetAtomicInt(&chunk->light_state, TASK_STATE_REQUESTED); chunks[x][z] = chunk; } - chunk_t* chunk = chunks[x][z]; + Chunk* chunk = chunks[x][z]; chunk->x = (world_x + x) * CHUNK_WIDTH; chunk->z = (world_z + z) * CHUNK_WIDTH; } - CHECK(!size); - is_moving = false; + SDL_assert(!count); } -static void move_chunks(const camera_t* camera) +static bool TryMoveChunks(const Camera* camera) { - const int offset_x = camera->x / CHUNK_WIDTH - WORLD_WIDTH / 2 - world_x; - const int offset_z = camera->z / CHUNK_WIDTH - WORLD_WIDTH / 2 - world_z; - if (offset_x || offset_z) + const int dx = FloorChunkIndex(camera->x) - WORLD_WIDTH / 2 - world_x; + const int dz = FloorChunkIndex(camera->z) - WORLD_WIDTH / 2 - world_z; + if (!dx && !dz) { - is_moving = true; - if (!get_running_count()) - { - shuffle(offset_x, offset_z); - } + return true; } -} - -static bool try_update_blocks(int x, int z, worker_t* worker) -{ - CHECK(is_chunk_local(x, z)); - chunk_t* chunk = chunks[x][z]; - if (SDL_GetAtomicInt(&chunk->block_state) != JOB_STATE_REQUESTED) + WorldWorker* workers[WORKERS]; + if (GetWorkers(workers) != WORKERS) { return false; } - job_t job = {JOB_TYPE_BLOCKS, x, z}; - CHECK(!is_job_running(worker)); - dispatch_job(worker, &job); + Shuffle(dx, dz); return true; } -static bool try_update_voxels_or_lights(int x, int z, worker_t* worker) +void World_Update(const Camera* camera) { - CHECK(is_chunk_local(x, z)); - chunk_t* chunk = chunks[x][z]; - if (is_chunk_on_border(x, z)) - { - return false; - } - bool do_voxel = SDL_GetAtomicInt(&chunk->voxel_state) == JOB_STATE_REQUESTED; - bool do_light = SDL_GetAtomicInt(&chunk->light_state) == JOB_STATE_REQUESTED; - if (!do_voxel && !do_light) - { - return false;; - } - chunk_t* neighborhood[3][3]; - get_neighborhood(x, z, neighborhood); - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - { - if (SDL_GetAtomicInt(&neighborhood[i][j]->block_state) != JOB_STATE_COMPLETED) - { - return false; - } - } - job_t job; - if (do_voxel) - { - job = (job_t) {JOB_TYPE_VOXELS, x, z}; - } - else if (do_light) - { - job = (job_t) {JOB_TYPE_LIGHTS, x, z}; - } - else - { - CHECK(false); - } - dispatch_job(worker, &job); - return true; -} - -void world_update(const camera_t* camera) -{ - move_chunks(camera); - if (is_moving) + if (!TryMoveChunks(camera)) { return; } - worker_t* local_workers[WORKERS] = {0}; - int num_workers = get_workers(local_workers); - for (int x = 0; x < WORLD_WIDTH; x++) - for (int z = 0; z < WORLD_WIDTH; z++) + WorldWorker* workers[WORKERS] = {0}; + int count = GetWorkers(workers); + for (int i = 0; i < WORLD_WIDTH * WORLD_WIDTH; i++) { - if (num_workers == 0) + if (!count) { return; } - int a = sorted_chunks[x][z][0]; - int b = sorted_chunks[x][z][1]; - worker_t* worker = local_workers[num_workers - 1]; - if (try_update_blocks(a, b, worker)) - { - num_workers--; - } - else if (try_update_voxels_or_lights(a, b, worker)) + int cx = sorted_chunks[i][0]; + int cz = sorted_chunks[i][1]; + WorldWorker* worker = workers[count - 1]; + if (TryDispatchTask(cx, cz, worker)) { - num_workers--; + count--; } } } -static void render(chunk_t* chunk, SDL_GPUCommandBuffer* cbuf, SDL_GPURenderPass* pass, world_flags_t flags) +static void Render(Chunk* chunk, WorldMeshType type, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass) { - gpu_buffer_t* gpu_voxels = &chunk->gpu_voxels[get_mesh_for_flags(flags)]; - if (gpu_voxels->size == 0) + GPUBuffer* voxels = &chunk->gpu_voxels[type]; + if (!voxels->size) { return; } SDL_GPUBufferBinding voxel_binding = {0}; SDL_GPUBufferBinding index_binding = {0}; - voxel_binding.buffer = gpu_voxels->buffer; + SDL_GPUBuffer* lights = NULL; + Sint32 light_count; + voxel_binding.buffer = voxels->buffer; index_binding.buffer = gpu_indices.buffer; - if (flags & WORLD_FLAGS_LIGHT) + if (SDL_GetAtomicInt(&chunk->light_state) == TASK_STATE_COMPLETED && chunk->gpu_lights.size) { - Sint32 light_count; - SDL_GPUBuffer* light_binding; - if (SDL_GetAtomicInt(&chunk->light_state) == JOB_STATE_COMPLETED && chunk->gpu_lights.size) - { - light_binding = chunk->gpu_lights.buffer; - light_count = chunk->gpu_lights.size; - } - else - { - light_binding = gpu_empty_lights.buffer; - light_count = 0; - } - SDL_PushGPUFragmentUniformData(cbuf, 0, &light_count, 4); - SDL_BindGPUFragmentStorageBuffers(pass, 0, &light_binding, 1); + lights = chunk->gpu_lights.buffer; + light_count = chunk->gpu_lights.size; } - SDL_PushGPUVertexUniformData(cbuf, 2, chunk->position, 12); - SDL_BindGPUVertexBuffers(pass, 0, &voxel_binding, 1); - SDL_BindGPUIndexBuffer(pass, &index_binding, SDL_GPU_INDEXELEMENTSIZE_32BIT); - SDL_DrawGPUIndexedPrimitives(pass, gpu_voxels->size * 1.5, 1, 0, 0, 0); + else + { + lights = gpu_empty_lights.buffer; + light_count = 0; + } + SDL_PushGPUFragmentUniformData(command_buffer, 0, &light_count, sizeof(light_count)); + SDL_BindGPUFragmentStorageBuffers(render_pass, 1, &lights, 1); + SDL_PushGPUVertexUniformData(command_buffer, 2, chunk->position, sizeof(chunk->position)); + SDL_BindGPUVertexBuffers(render_pass, 0, &voxel_binding, 1); + SDL_BindGPUIndexBuffer(render_pass, &index_binding, SDL_GPU_INDEXELEMENTSIZE_32BIT); + SDL_DrawGPUIndexedPrimitives(render_pass, voxels->size / 4 * 6, 1, 0, 0, 0); } -void world_render(const camera_t* camera, SDL_GPUCommandBuffer* cbuf, SDL_GPURenderPass* pass, world_flags_t flags) +void World_Render(const Camera* camera, WorldMeshType type, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass) { - SDL_PushGPUVertexUniformData(cbuf, 0, camera->proj, 64); - SDL_PushGPUVertexUniformData(cbuf, 1, camera->view, 64); - for (int x = 0; x < WORLD_WIDTH; x++) - for (int y = 0; y < WORLD_WIDTH; y++) + SDL_PushGPUVertexUniformData(command_buffer, 0, camera->proj, sizeof(camera->proj)); + SDL_PushGPUVertexUniformData(command_buffer, 1, camera->view, sizeof(camera->view)); + for (int i = 0; i < WORLD_WIDTH * WORLD_WIDTH; i++) { - int a = sorted_chunks[x][y][0]; - int b = sorted_chunks[x][y][1]; - if (is_chunk_on_border(a, b)) + int cx = sorted_chunks[i][0]; + int cz = sorted_chunks[i][1]; + if (IsChunkOnWorldBorder(cx, cz)) { continue; } - chunk_t* chunk = chunks[a][b]; - if (SDL_GetAtomicInt(&chunk->voxel_state) != JOB_STATE_COMPLETED) + Chunk* chunk = chunks[cx][cz]; + if (SDL_GetAtomicInt(&chunk->voxel_state) != TASK_STATE_COMPLETED) { continue; } - float sx = CHUNK_WIDTH; - float sy = CHUNK_HEIGHT; - float sz = CHUNK_WIDTH; - if (!camera_get_vis(camera, chunk->x, 0.0f, chunk->z, sx, sy, sz)) + if (!Camera_IsVisible(camera, chunk->x, 0.0f, chunk->z, CHUNK_WIDTH, CHUNK_HEIGHT, CHUNK_WIDTH)) { continue; } - render(chunk, cbuf, pass, flags); + Render(chunk, type, command_buffer, render_pass); } } -block_t world_get_block(const int position[3]) +static Chunk* GetWorldChunk(const int position[3]) { if (position[1] < 0 || position[1] >= CHUNK_HEIGHT) { - return BLOCK_EMPTY; + return NULL; } - int chunk_x = floor_chunk_index(position[0] - world_x * CHUNK_WIDTH); - int chunk_z = floor_chunk_index(position[2] - world_z * CHUNK_WIDTH); - chunk_t* chunk = get_chunk(chunk_x, chunk_z); + int cx = FloorChunkIndex(position[0] - world_x * CHUNK_WIDTH); + int cz = FloorChunkIndex(position[2] - world_z * CHUNK_WIDTH); + Chunk* chunk = GetChunk(cx, cz); if (chunk) { - CHECK(chunk->x == (world_x + chunk_x) * CHUNK_WIDTH); - CHECK(chunk->z == (world_z + chunk_z) * CHUNK_WIDTH); + SDL_assert(chunk->x == (world_x + cx) * CHUNK_WIDTH); + SDL_assert(chunk->z == (world_z + cz) * CHUNK_WIDTH); } else { - SDL_Log("Bad chunk position: %d, %d", chunk_x, chunk_z); - return BLOCK_EMPTY; + SDL_Log("Bad chunk position: %d, %d", cx, cz); + return NULL; } - bool has_blocks = SDL_GetAtomicInt(&chunk->block_state) == JOB_STATE_COMPLETED; - bool has_voxels = SDL_GetAtomicInt(&chunk->voxel_state) == JOB_STATE_COMPLETED; - if (has_blocks && has_voxels) + bool blocks = SDL_GetAtomicInt(&chunk->block_state) == TASK_STATE_COMPLETED; + bool voxels = SDL_GetAtomicInt(&chunk->voxel_state) == TASK_STATE_COMPLETED; + if (blocks && voxels) { - return get_chunk_block(chunk, position[0], position[1], position[2]); + return chunk; } else { - return BLOCK_EMPTY; + return NULL; } } -void world_set_block(const int position[3], block_t block) +void World_SetBlock(const int position[3], Block block) { - if (position[1] < 0 || position[1] >= CHUNK_HEIGHT) + Chunk* chunk = GetWorldChunk(position); + if (!chunk) { return; } - int chunk_x = floor_chunk_index(position[0] - world_x * CHUNK_WIDTH); - int chunk_z = floor_chunk_index(position[2] - world_z * CHUNK_WIDTH); - chunk_t* chunk = get_chunk(chunk_x, chunk_z); - if (chunk) - { - CHECK(chunk->x == (world_x + chunk_x) * CHUNK_WIDTH); - CHECK(chunk->z == (world_z + chunk_z) * CHUNK_WIDTH); - } - else + int cx = chunk->x / CHUNK_WIDTH - world_x; + int cz = chunk->z / CHUNK_WIDTH - world_z; + Chunk* group[3][3] = {0}; + for (int dx = -1; dx <= 1; dx++) + for (int dz = -1; dz <= 1; dz++) { - SDL_Log("Bad chunk position: %d, %d", chunk_x, chunk_z); - return; + Chunk* neighbor = GetChunk(cx + dx, cz + dz); + if (!neighbor || + SDL_GetAtomicInt(&neighbor->block_state) != TASK_STATE_COMPLETED || + SDL_GetAtomicInt(&neighbor->voxel_state) != TASK_STATE_COMPLETED || + SDL_GetAtomicInt(&neighbor->light_state) != TASK_STATE_COMPLETED) + { + return; + } + group[dx + 1][dz + 1] = neighbor; + } + Save_SetBlock(chunk->x, chunk->z, position[0], position[1], position[2], block); + int bx = position[0]; + int by = position[1]; + int bz = position[2]; + WorldBlockToChunkBlock(chunk, &bx, &by, &bz); + Block old_block = SetChunkBlock(chunk, position[0], position[1], position[2], block); + int min_x = bx == 0 ? -1 : 0; + int max_x = bx == CHUNK_WIDTH - 1 ? 1 : 0; + int min_z = bz == 0 ? -1 : 0; + int max_z = bz == CHUNK_WIDTH - 1 ? 1 : 0; + for (int dx = min_x; dx <= max_x; dx++) + for (int dz = min_z; dz <= max_z; dz++) + { + int x = cx + dx; + int z = cz + dz; + SDL_assert(IsChunkInWorld(x, z)); + if (!IsChunkOnWorldBorder(x, z)) + { + Chunk* chunks[3][3] = {0}; + GetGroup(x, z, chunks); + SDL_SetAtomicInt(&chunks[1][1]->voxel_state, TASK_STATE_RUNNING); + GenerateChunkVoxels(chunks, cpu_voxels); + } + else + { + SDL_SetAtomicInt(&group[dx + 1][dz + 1]->voxel_state, TASK_STATE_REQUESTED); + } } - bool has_blocks = SDL_GetAtomicInt(&chunk->block_state) == JOB_STATE_COMPLETED; - bool has_voxels = SDL_GetAtomicInt(&chunk->voxel_state) == JOB_STATE_COMPLETED; - if (!has_blocks || !has_voxels) + if (!Block_IsLight(block) && !Block_IsLight(old_block)) { return; } - save_set_block(chunk->x, chunk->z, position[0], position[1], position[2], block); - int local_x = position[0]; - int local_y = position[1]; - int local_z = position[2]; - world_to_chunk(chunk, &local_x, &local_y, &local_z); - block_t old_block = set_chunk_block(chunk, position[0], position[1], position[2], block); - regen_chunk_voxels(chunk_x, chunk_z); - if (local_x == 0) + for (int dx = 0; dx < 3; dx++) + for (int dz = 0; dz < 3; dz++) { - regen_chunk_voxels(chunk_x - 1, chunk_z); + SDL_SetAtomicInt(&group[dx][dz]->light_state, TASK_STATE_REQUESTED); } - else if (local_x == CHUNK_WIDTH - 1) - { - regen_chunk_voxels(chunk_x + 1, chunk_z); - } - if (local_z == 0) - { - regen_chunk_voxels(chunk_x, chunk_z - 1); - } - else if (local_z == CHUNK_WIDTH - 1) +} + +Block World_GetBlock(const int position[3]) +{ + Chunk* chunk = GetWorldChunk(position); + if (chunk) { - regen_chunk_voxels(chunk_x, chunk_z + 1); + return GetChunkBlock(chunk, position[0], position[1], position[2]); } - chunk_t* neighborhood[3][3] = {0}; - get_neighborhood(chunk_x, chunk_z, neighborhood); - if (block_is_light(block) || block_is_light(old_block)) + else { - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - { - SDL_SetAtomicInt(&neighborhood[i][j]->light_state, JOB_STATE_REQUESTED); - } + return BLOCK_EMPTY; } } -world_query_t world_raycast(const camera_t* camera, float length) +WorldQuery World_Raycast(const Camera* camera, float max_distance) { - world_query_t query = {0}; - float direction[3] = {0}; - float distances[3] = {0}; - int steps[3] = {0}; - float deltas[3] = {0}; - camera_get_vector(camera, &direction[0], &direction[1], &direction[2]); + WorldQuery query = {0}; + float vector[3] = {0}; + int step[3] = {0}; + float distance[3] = {0}; + float delta[3] = {0}; + Camera_GetVector(camera, &vector[0], &vector[1], &vector[2]); for (int i = 0; i < 3; i++) { query.current[i] = SDL_floorf(camera->position[i]); query.previous[i] = query.current[i]; - if (SDL_fabsf(direction[i]) > SDL_FLT_EPSILON) + if (SDL_fabsf(vector[i]) > SDL_FLT_EPSILON) { - deltas[i] = SDL_fabsf(1.0f / direction[i]); + delta[i] = SDL_fabsf(1.0f / vector[i]); } else { - deltas[i] = 1e6; + delta[i] = 1e6f; } - if (direction[i] < 0.0f) + if (vector[i] < 0.0f) { - steps[i] = -1; - distances[i] = (camera->position[i] - query.current[i]) * deltas[i]; + step[i] = -1; + distance[i] = (camera->position[i] - query.current[i]) * delta[i]; } else { - steps[i] = 1; - distances[i] = (query.current[i] + 1.0f - camera->position[i]) * deltas[i]; + step[i] = 1; + distance[i] = (query.current[i] + 1.0f - camera->position[i]) * delta[i]; } } - float traveled = 0.0f; - while (traveled <= length) + float length = 0.0f; + while (length <= max_distance) { - query.block = world_get_block(query.current); - if (block_is_solid(query.block)) + query.block = World_GetBlock(query.current); + if (Block_IsSolid(query.block)) { return query; } - for (int i = 0; i < 3; i++) + SDL_memcpy(query.previous, query.current, sizeof(query.current)); + int axis; + if (distance[0] < distance[1] && distance[0] < distance[2]) { - query.previous[i] = query.current[i]; + axis = 0; } - if (distances[0] < distances[1]) + else if (distance[1] < distance[2]) { - if (distances[0] < distances[2]) - { - traveled = distances[0]; - distances[0] += deltas[0]; - query.current[0] += steps[0]; - } - else - { - traveled = distances[2]; - distances[2] += deltas[2]; - query.current[2] += steps[2]; - } + axis = 1; } else { - if (distances[1] < distances[2]) - { - traveled = distances[1]; - distances[1] += deltas[1]; - query.current[1] += steps[1]; - } - else - { - traveled = distances[2]; - distances[2] += deltas[2]; - query.current[2] += steps[2]; - } + axis = 2; } + length = distance[axis]; + distance[axis] += delta[axis]; + query.current[axis] += step[axis]; } query.block = BLOCK_EMPTY; return query; diff --git a/src/world.h b/src/world.h index aa376466..7b10a116 100644 --- a/src/world.h +++ b/src/world.h @@ -8,28 +8,26 @@ #define CHUNK_HEIGHT 240 #define WORLD_WIDTH 20 -typedef struct camera camera_t; +typedef struct Camera Camera; -typedef enum world_flags +typedef enum WorldMeshType { - WORLD_FLAGS_OPAQUE = 0x01, - WORLD_FLAGS_TRANSPARENT = 0x02, - WORLD_FLAGS_LIGHT = 0x04, -} -world_flags_t; + WORLD_MESH_TYPE_OPAQUE, + WORLD_MESH_TYPE_TRANSPARENT, + WORLD_MESH_TYPE_COUNT, +} WorldMeshType; -typedef struct world_query +typedef struct WorldQuery { - block_t block; + Block block; int current[3]; int previous[3]; -} -world_query_t; +} WorldQuery; -void world_init(SDL_GPUDevice* device); -void world_free(); -void world_update(const camera_t* camera); -void world_render(const camera_t* camera, SDL_GPUCommandBuffer* cbuf, SDL_GPURenderPass* pass, world_flags_t flags); -block_t world_get_block(const int position[3]); -void world_set_block(const int position[3], block_t block); -world_query_t world_raycast(const camera_t* camera, float length); +void World_Init(SDL_GPUDevice* device); +void World_Free(); +void World_Update(const Camera* camera); +void World_Render(const Camera* camera, WorldMeshType type, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass); +void World_SetBlock(const int position[3], Block block); +Block World_GetBlock(const int position[3]); +WorldQuery World_Raycast(const Camera* camera, float max_distance); diff --git a/textures/atlas.png b/textures/atlas.png index 95607260..67c3070a 100644 Binary files a/textures/atlas.png and b/textures/atlas.png differ diff --git a/textures/atlas.xcf b/textures/atlas.xcf index 245871d7..4d54453d 100644 Binary files a/textures/atlas.xcf and b/textures/atlas.xcf differ