From 43bee361397315c7105b7214316325b185135331 Mon Sep 17 00:00:00 2001 From: omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 26 Oct 2024 21:55:23 +1100 Subject: move archive into /src --- archive/src/animation.c | 90 -- archive/src/animation.h | 122 -- archive/src/apidocs/coldark_prism.css | 317 ---- archive/src/apidocs/doc_styles.css | 76 - archive/src/apidocs/gen_apidocs.py | 119 -- archive/src/apidocs/index.html | 304 ---- archive/src/apidocs/modules.md | 18 - archive/src/apidocs/prism.css | 3 - archive/src/apidocs/prism.js | 6 - archive/src/apidocs/template.html | 91 -- archive/src/collision.c | 9 - archive/src/colours.h | 89 - archive/src/core/README.md | 3 - archive/src/core/animation.c | 0 archive/src/core/camera.c | 90 -- archive/src/core/camera.h | 39 - archive/src/core/core.c | 81 - archive/src/core/core.h | 43 - archive/src/core/input.c | 0 archive/src/core/vfs.h | 38 - archive/src/empty.c | 3 - archive/src/log.c | 56 - archive/src/log.h | 84 - archive/src/logos/README.md | 6 - archive/src/logos/tasks.h | 74 - archive/src/logos/threadpool.c | 141 -- archive/src/logos/threadpool.h | 96 -- archive/src/maths/geometry.h | 50 - archive/src/maths/maths.c | 35 - archive/src/maths/maths.h | 321 ---- archive/src/maths/maths_types.h | 33 - archive/src/maths/primitives.c | 343 ---- archive/src/maths/primitives.h | 29 - archive/src/physics.h | 44 - archive/src/platform/file.c | 93 -- archive/src/platform/file.h | 26 - archive/src/platform/platform.h | 37 - archive/src/platform/platform_unix.c | 16 - archive/src/platform/platform_windows.c | 22 - archive/src/ral/README.md | 5 - archive/src/ral/backends/metal/backend_metal.h | 0 archive/src/ral/backends/opengl/backend_opengl.c | 449 ------ archive/src/ral/backends/opengl/backend_opengl.h | 109 -- archive/src/ral/backends/opengl/opengl_helpers.h | 159 -- archive/src/ral/backends/vulkan/backend_vulkan.c | 0 archive/src/ral/backends/vulkan/backend_vulkan.h | 44 - archive/src/ral/backends/vulkan/vulkan_glossary.md | 18 - archive/src/ral/backends/vulkan/vulkan_helpers.h | 199 --- archive/src/ral/ral.h | 5 - archive/src/ral/ral_common.c | 70 - archive/src/ral/ral_common.h | 61 - archive/src/ral/ral_impl.h | 102 -- archive/src/ral/ral_types.h | 168 -- archive/src/render/archive/backends/backend_test.c | 1 - .../src/render/archive/backends/metal/README.md | 1 - .../render/archive/backends/metal/backend_metal.h | 74 - .../render/archive/backends/metal/backend_metal.m | 285 ---- .../archive/backends/opengl/backend_opengl.c | 521 ------ .../archive/backends/opengl/backend_opengl.h | 68 - .../src/render/archive/backends/vulkan/README.md | 1 - .../archive/backends/vulkan/backend_vulkan.c | 1705 -------------------- .../archive/backends/vulkan/backend_vulkan.h | 118 -- archive/src/render/immdraw.c | 176 -- archive/src/render/immdraw.h | 63 - archive/src/render/pbr.c | 266 --- archive/src/render/pbr.h | 70 - archive/src/render/render.c | 359 ----- archive/src/render/render.h | 151 -- archive/src/render/render_types.h | 138 -- archive/src/render/shader_layouts.h | 70 - archive/src/render/shadows.c | 211 --- archive/src/render/shadows.h | 48 - archive/src/render/skybox.c | 161 -- archive/src/render/skybox.h | 41 - archive/src/resources/gltf.c | 596 ------- archive/src/resources/loaders.h | 17 - archive/src/resources/obj.c | 398 ----- archive/src/std/buf.h | 11 - archive/src/std/containers/container_utils.h | 17 - archive/src/std/containers/darray.h | 151 -- archive/src/std/containers/graphs.h | 14 - archive/src/std/containers/hashmap.h | 27 - archive/src/std/containers/hashset.h | 29 - archive/src/std/containers/ring_queue.c | 68 - archive/src/std/containers/ring_queue.h | 35 - archive/src/std/containers/stack_array.h | 19 - archive/src/std/mem.c | 135 -- archive/src/std/mem.h | 96 -- archive/src/std/str.c | 74 - archive/src/std/str.h | 89 - archive/src/std/utils.h | 4 - archive/src/systems/grid.c | 84 - archive/src/systems/grid.h | 21 - archive/src/systems/input.c | 105 -- archive/src/systems/input.h | 53 - archive/src/systems/keys.h | 59 - archive/src/systems/screenspace.h | 53 - archive/src/systems/terrain.c | 204 --- archive/src/systems/terrain.h | 72 - archive/src/systems/text.c | 1 - archive/src/systems/text.h | 53 - archive/src/transform_hierarchy.c | 185 --- archive/src/transform_hierarchy.h | 80 - archive/xmake.lua | 205 --- src/archive/src/animation.c | 90 ++ src/archive/src/animation.h | 122 ++ src/archive/src/apidocs/coldark_prism.css | 317 ++++ src/archive/src/apidocs/doc_styles.css | 76 + src/archive/src/apidocs/gen_apidocs.py | 119 ++ src/archive/src/apidocs/index.html | 304 ++++ src/archive/src/apidocs/modules.md | 18 + src/archive/src/apidocs/prism.css | 3 + src/archive/src/apidocs/prism.js | 6 + src/archive/src/apidocs/template.html | 91 ++ src/archive/src/collision.c | 9 + src/archive/src/colours.h | 89 + src/archive/src/core/README.md | 3 + src/archive/src/core/animation.c | 0 src/archive/src/core/camera.c | 90 ++ src/archive/src/core/camera.h | 39 + src/archive/src/core/core.c | 81 + src/archive/src/core/core.h | 43 + src/archive/src/core/input.c | 0 src/archive/src/core/vfs.h | 38 + src/archive/src/empty.c | 3 + src/archive/src/log.c | 56 + src/archive/src/log.h | 84 + src/archive/src/logos/README.md | 6 + src/archive/src/logos/tasks.h | 74 + src/archive/src/logos/threadpool.c | 141 ++ src/archive/src/logos/threadpool.h | 96 ++ src/archive/src/maths/geometry.h | 50 + src/archive/src/maths/maths.c | 35 + src/archive/src/maths/maths.h | 321 ++++ src/archive/src/maths/maths_types.h | 33 + src/archive/src/maths/primitives.c | 343 ++++ src/archive/src/maths/primitives.h | 29 + src/archive/src/physics.h | 44 + src/archive/src/platform/file.c | 93 ++ src/archive/src/platform/file.h | 26 + src/archive/src/platform/platform.h | 37 + src/archive/src/platform/platform_unix.c | 16 + src/archive/src/platform/platform_windows.c | 22 + src/archive/src/ral/README.md | 5 + src/archive/src/ral/backends/metal/backend_metal.h | 0 .../src/ral/backends/opengl/backend_opengl.c | 449 ++++++ .../src/ral/backends/opengl/backend_opengl.h | 109 ++ .../src/ral/backends/opengl/opengl_helpers.h | 159 ++ .../src/ral/backends/vulkan/backend_vulkan.c | 0 .../src/ral/backends/vulkan/backend_vulkan.h | 44 + .../src/ral/backends/vulkan/vulkan_glossary.md | 18 + .../src/ral/backends/vulkan/vulkan_helpers.h | 199 +++ src/archive/src/ral/ral.h | 5 + src/archive/src/ral/ral_common.c | 70 + src/archive/src/ral/ral_common.h | 61 + src/archive/src/ral/ral_impl.h | 102 ++ src/archive/src/ral/ral_types.h | 168 ++ .../src/render/archive/backends/backend_test.c | 1 + .../src/render/archive/backends/metal/README.md | 1 + .../render/archive/backends/metal/backend_metal.h | 74 + .../render/archive/backends/metal/backend_metal.m | 285 ++++ .../archive/backends/opengl/backend_opengl.c | 521 ++++++ .../archive/backends/opengl/backend_opengl.h | 68 + .../src/render/archive/backends/vulkan/README.md | 1 + .../archive/backends/vulkan/backend_vulkan.c | 1705 ++++++++++++++++++++ .../archive/backends/vulkan/backend_vulkan.h | 118 ++ src/archive/src/render/immdraw.c | 176 ++ src/archive/src/render/immdraw.h | 63 + src/archive/src/render/pbr.c | 266 +++ src/archive/src/render/pbr.h | 70 + src/archive/src/render/render.c | 359 +++++ src/archive/src/render/render.h | 151 ++ src/archive/src/render/render_types.h | 138 ++ src/archive/src/render/shader_layouts.h | 70 + src/archive/src/render/shadows.c | 211 +++ src/archive/src/render/shadows.h | 48 + src/archive/src/render/skybox.c | 161 ++ src/archive/src/render/skybox.h | 41 + src/archive/src/resources/gltf.c | 596 +++++++ src/archive/src/resources/loaders.h | 17 + src/archive/src/resources/obj.c | 398 +++++ src/archive/src/std/buf.h | 11 + src/archive/src/std/containers/container_utils.h | 17 + src/archive/src/std/containers/darray.h | 151 ++ src/archive/src/std/containers/graphs.h | 14 + src/archive/src/std/containers/hashmap.h | 27 + src/archive/src/std/containers/hashset.h | 29 + src/archive/src/std/containers/ring_queue.c | 68 + src/archive/src/std/containers/ring_queue.h | 35 + src/archive/src/std/containers/stack_array.h | 19 + src/archive/src/std/mem.c | 135 ++ src/archive/src/std/mem.h | 96 ++ src/archive/src/std/str.c | 74 + src/archive/src/std/str.h | 89 + src/archive/src/std/utils.h | 4 + src/archive/src/systems/grid.c | 84 + src/archive/src/systems/grid.h | 21 + src/archive/src/systems/input.c | 105 ++ src/archive/src/systems/input.h | 53 + src/archive/src/systems/keys.h | 59 + src/archive/src/systems/screenspace.h | 53 + src/archive/src/systems/terrain.c | 204 +++ src/archive/src/systems/terrain.h | 72 + src/archive/src/systems/text.c | 1 + src/archive/src/systems/text.h | 53 + src/archive/src/transform_hierarchy.c | 185 +++ src/archive/src/transform_hierarchy.h | 80 + src/archive/xmake.lua | 205 +++ 208 files changed, 11919 insertions(+), 11919 deletions(-) delete mode 100644 archive/src/animation.c delete mode 100644 archive/src/animation.h delete mode 100644 archive/src/apidocs/coldark_prism.css delete mode 100644 archive/src/apidocs/doc_styles.css delete mode 100644 archive/src/apidocs/gen_apidocs.py delete mode 100644 archive/src/apidocs/index.html delete mode 100644 archive/src/apidocs/modules.md delete mode 100644 archive/src/apidocs/prism.css delete mode 100644 archive/src/apidocs/prism.js delete mode 100644 archive/src/apidocs/template.html delete mode 100644 archive/src/collision.c delete mode 100644 archive/src/colours.h delete mode 100644 archive/src/core/README.md delete mode 100644 archive/src/core/animation.c delete mode 100644 archive/src/core/camera.c delete mode 100644 archive/src/core/camera.h delete mode 100644 archive/src/core/core.c delete mode 100644 archive/src/core/core.h delete mode 100644 archive/src/core/input.c delete mode 100644 archive/src/core/vfs.h delete mode 100644 archive/src/empty.c delete mode 100644 archive/src/log.c delete mode 100644 archive/src/log.h delete mode 100644 archive/src/logos/README.md delete mode 100644 archive/src/logos/tasks.h delete mode 100644 archive/src/logos/threadpool.c delete mode 100644 archive/src/logos/threadpool.h delete mode 100644 archive/src/maths/geometry.h delete mode 100644 archive/src/maths/maths.c delete mode 100644 archive/src/maths/maths.h delete mode 100644 archive/src/maths/maths_types.h delete mode 100644 archive/src/maths/primitives.c delete mode 100644 archive/src/maths/primitives.h delete mode 100644 archive/src/physics.h delete mode 100644 archive/src/platform/file.c delete mode 100644 archive/src/platform/file.h delete mode 100644 archive/src/platform/platform.h delete mode 100644 archive/src/platform/platform_unix.c delete mode 100644 archive/src/platform/platform_windows.c delete mode 100644 archive/src/ral/README.md delete mode 100644 archive/src/ral/backends/metal/backend_metal.h delete mode 100644 archive/src/ral/backends/opengl/backend_opengl.c delete mode 100644 archive/src/ral/backends/opengl/backend_opengl.h delete mode 100644 archive/src/ral/backends/opengl/opengl_helpers.h delete mode 100644 archive/src/ral/backends/vulkan/backend_vulkan.c delete mode 100644 archive/src/ral/backends/vulkan/backend_vulkan.h delete mode 100644 archive/src/ral/backends/vulkan/vulkan_glossary.md delete mode 100644 archive/src/ral/backends/vulkan/vulkan_helpers.h delete mode 100644 archive/src/ral/ral.h delete mode 100644 archive/src/ral/ral_common.c delete mode 100644 archive/src/ral/ral_common.h delete mode 100644 archive/src/ral/ral_impl.h delete mode 100644 archive/src/ral/ral_types.h delete mode 100644 archive/src/render/archive/backends/backend_test.c delete mode 100644 archive/src/render/archive/backends/metal/README.md delete mode 100644 archive/src/render/archive/backends/metal/backend_metal.h delete mode 100644 archive/src/render/archive/backends/metal/backend_metal.m delete mode 100644 archive/src/render/archive/backends/opengl/backend_opengl.c delete mode 100644 archive/src/render/archive/backends/opengl/backend_opengl.h delete mode 100644 archive/src/render/archive/backends/vulkan/README.md delete mode 100644 archive/src/render/archive/backends/vulkan/backend_vulkan.c delete mode 100644 archive/src/render/archive/backends/vulkan/backend_vulkan.h delete mode 100644 archive/src/render/immdraw.c delete mode 100644 archive/src/render/immdraw.h delete mode 100644 archive/src/render/pbr.c delete mode 100644 archive/src/render/pbr.h delete mode 100644 archive/src/render/render.c delete mode 100644 archive/src/render/render.h delete mode 100644 archive/src/render/render_types.h delete mode 100644 archive/src/render/shader_layouts.h delete mode 100644 archive/src/render/shadows.c delete mode 100644 archive/src/render/shadows.h delete mode 100644 archive/src/render/skybox.c delete mode 100644 archive/src/render/skybox.h delete mode 100644 archive/src/resources/gltf.c delete mode 100644 archive/src/resources/loaders.h delete mode 100644 archive/src/resources/obj.c delete mode 100644 archive/src/std/buf.h delete mode 100644 archive/src/std/containers/container_utils.h delete mode 100644 archive/src/std/containers/darray.h delete mode 100644 archive/src/std/containers/graphs.h delete mode 100644 archive/src/std/containers/hashmap.h delete mode 100644 archive/src/std/containers/hashset.h delete mode 100644 archive/src/std/containers/ring_queue.c delete mode 100644 archive/src/std/containers/ring_queue.h delete mode 100644 archive/src/std/containers/stack_array.h delete mode 100644 archive/src/std/mem.c delete mode 100644 archive/src/std/mem.h delete mode 100644 archive/src/std/str.c delete mode 100644 archive/src/std/str.h delete mode 100644 archive/src/std/utils.h delete mode 100644 archive/src/systems/grid.c delete mode 100644 archive/src/systems/grid.h delete mode 100644 archive/src/systems/input.c delete mode 100644 archive/src/systems/input.h delete mode 100644 archive/src/systems/keys.h delete mode 100644 archive/src/systems/screenspace.h delete mode 100644 archive/src/systems/terrain.c delete mode 100644 archive/src/systems/terrain.h delete mode 100644 archive/src/systems/text.c delete mode 100644 archive/src/systems/text.h delete mode 100644 archive/src/transform_hierarchy.c delete mode 100644 archive/src/transform_hierarchy.h delete mode 100644 archive/xmake.lua create mode 100644 src/archive/src/animation.c create mode 100644 src/archive/src/animation.h create mode 100644 src/archive/src/apidocs/coldark_prism.css create mode 100644 src/archive/src/apidocs/doc_styles.css create mode 100644 src/archive/src/apidocs/gen_apidocs.py create mode 100644 src/archive/src/apidocs/index.html create mode 100644 src/archive/src/apidocs/modules.md create mode 100644 src/archive/src/apidocs/prism.css create mode 100644 src/archive/src/apidocs/prism.js create mode 100644 src/archive/src/apidocs/template.html create mode 100644 src/archive/src/collision.c create mode 100644 src/archive/src/colours.h create mode 100644 src/archive/src/core/README.md create mode 100644 src/archive/src/core/animation.c create mode 100644 src/archive/src/core/camera.c create mode 100644 src/archive/src/core/camera.h create mode 100644 src/archive/src/core/core.c create mode 100644 src/archive/src/core/core.h create mode 100644 src/archive/src/core/input.c create mode 100644 src/archive/src/core/vfs.h create mode 100644 src/archive/src/empty.c create mode 100644 src/archive/src/log.c create mode 100644 src/archive/src/log.h create mode 100644 src/archive/src/logos/README.md create mode 100644 src/archive/src/logos/tasks.h create mode 100644 src/archive/src/logos/threadpool.c create mode 100644 src/archive/src/logos/threadpool.h create mode 100644 src/archive/src/maths/geometry.h create mode 100644 src/archive/src/maths/maths.c create mode 100644 src/archive/src/maths/maths.h create mode 100644 src/archive/src/maths/maths_types.h create mode 100644 src/archive/src/maths/primitives.c create mode 100644 src/archive/src/maths/primitives.h create mode 100644 src/archive/src/physics.h create mode 100644 src/archive/src/platform/file.c create mode 100644 src/archive/src/platform/file.h create mode 100644 src/archive/src/platform/platform.h create mode 100644 src/archive/src/platform/platform_unix.c create mode 100644 src/archive/src/platform/platform_windows.c create mode 100644 src/archive/src/ral/README.md create mode 100644 src/archive/src/ral/backends/metal/backend_metal.h create mode 100644 src/archive/src/ral/backends/opengl/backend_opengl.c create mode 100644 src/archive/src/ral/backends/opengl/backend_opengl.h create mode 100644 src/archive/src/ral/backends/opengl/opengl_helpers.h create mode 100644 src/archive/src/ral/backends/vulkan/backend_vulkan.c create mode 100644 src/archive/src/ral/backends/vulkan/backend_vulkan.h create mode 100644 src/archive/src/ral/backends/vulkan/vulkan_glossary.md create mode 100644 src/archive/src/ral/backends/vulkan/vulkan_helpers.h create mode 100644 src/archive/src/ral/ral.h create mode 100644 src/archive/src/ral/ral_common.c create mode 100644 src/archive/src/ral/ral_common.h create mode 100644 src/archive/src/ral/ral_impl.h create mode 100644 src/archive/src/ral/ral_types.h create mode 100644 src/archive/src/render/archive/backends/backend_test.c create mode 100644 src/archive/src/render/archive/backends/metal/README.md create mode 100644 src/archive/src/render/archive/backends/metal/backend_metal.h create mode 100644 src/archive/src/render/archive/backends/metal/backend_metal.m create mode 100644 src/archive/src/render/archive/backends/opengl/backend_opengl.c create mode 100644 src/archive/src/render/archive/backends/opengl/backend_opengl.h create mode 100644 src/archive/src/render/archive/backends/vulkan/README.md create mode 100644 src/archive/src/render/archive/backends/vulkan/backend_vulkan.c create mode 100644 src/archive/src/render/archive/backends/vulkan/backend_vulkan.h create mode 100644 src/archive/src/render/immdraw.c create mode 100644 src/archive/src/render/immdraw.h create mode 100644 src/archive/src/render/pbr.c create mode 100644 src/archive/src/render/pbr.h create mode 100644 src/archive/src/render/render.c create mode 100644 src/archive/src/render/render.h create mode 100644 src/archive/src/render/render_types.h create mode 100644 src/archive/src/render/shader_layouts.h create mode 100644 src/archive/src/render/shadows.c create mode 100644 src/archive/src/render/shadows.h create mode 100644 src/archive/src/render/skybox.c create mode 100644 src/archive/src/render/skybox.h create mode 100644 src/archive/src/resources/gltf.c create mode 100644 src/archive/src/resources/loaders.h create mode 100644 src/archive/src/resources/obj.c create mode 100644 src/archive/src/std/buf.h create mode 100644 src/archive/src/std/containers/container_utils.h create mode 100644 src/archive/src/std/containers/darray.h create mode 100644 src/archive/src/std/containers/graphs.h create mode 100644 src/archive/src/std/containers/hashmap.h create mode 100644 src/archive/src/std/containers/hashset.h create mode 100644 src/archive/src/std/containers/ring_queue.c create mode 100644 src/archive/src/std/containers/ring_queue.h create mode 100644 src/archive/src/std/containers/stack_array.h create mode 100644 src/archive/src/std/mem.c create mode 100644 src/archive/src/std/mem.h create mode 100644 src/archive/src/std/str.c create mode 100644 src/archive/src/std/str.h create mode 100644 src/archive/src/std/utils.h create mode 100644 src/archive/src/systems/grid.c create mode 100644 src/archive/src/systems/grid.h create mode 100644 src/archive/src/systems/input.c create mode 100644 src/archive/src/systems/input.h create mode 100644 src/archive/src/systems/keys.h create mode 100644 src/archive/src/systems/screenspace.h create mode 100644 src/archive/src/systems/terrain.c create mode 100644 src/archive/src/systems/terrain.h create mode 100644 src/archive/src/systems/text.c create mode 100644 src/archive/src/systems/text.h create mode 100644 src/archive/src/transform_hierarchy.c create mode 100644 src/archive/src/transform_hierarchy.h create mode 100644 src/archive/xmake.lua diff --git a/archive/src/animation.c b/archive/src/animation.c deleted file mode 100644 index d7973dc..0000000 --- a/archive/src/animation.c +++ /dev/null @@ -1,90 +0,0 @@ -#include "animation.h" -#include "immdraw.h" -#include "log.h" -#include "maths.h" -#include "maths_types.h" -#include "ral_types.h" - -Keyframe Animation_Sample(AnimationSampler* sampler, f32 t) { - size_t previous_index = 0; - f32 previous_time = 0.0; - // look forwards - DEBUG("%d\n", keyframe_kind_strings[sampler->animation.values.kind]); - TRACE("Total timestamps %d", sampler->animation.n_timestamps); - for (u32 i = 0; i < sampler->animation.n_timestamps; i++) { - f32 current_time = sampler->animation.timestamps[i]; - if (current_time > t) { - break; - } - previous_time = sampler->animation.timestamps[i]; - previous_index = i; - } - - size_t next_index = (previous_index + 1) % sampler->animation.n_timestamps; - f32 next_time = sampler->animation.timestamps[next_index]; - printf("%d %f %d %f\n", previous_index, previous_time, next_index, next_time); - - Keyframe prev_value = sampler->animation.values.values[previous_index]; - Keyframe next_value = sampler->animation.values.values[next_index]; - - printf("%d %d\n", previous_index, next_index); - - f32 time_diff = - sampler->animation.timestamps[next_index] - sampler->animation.timestamps[previous_index]; - f32 percent = (t - previous_time) / time_diff; - - switch (sampler->animation.values.kind) { - case KEYFRAME_ROTATION: - return (Keyframe){ .rotation = quat_slerp( - sampler->animation.values.values[previous_index].rotation, - sampler->animation.values.values[next_index].rotation, percent) }; - case KEYFRAME_TRANSLATION: - case KEYFRAME_SCALE: - case KEYFRAME_WEIGHTS: - WARN("TODO: other keyframe kind interpolation"); - return prev_value; - } -} - -void Animation_Tick(AnimationClip* clip, Armature* armature, f32 time) { - TRACE("Ticking animation %s", clip->clip_name); - - for (u32 c_i = 0; c_i < clip->channels->len; c_i++) { - AnimationSampler* sampler = clip->channels->data; - - // Interpolated keyframe based on time - Keyframe k = Animation_Sample(sampler, time); - - // Get the joint in the armature - Joint* joint = &armature->joints->data[sampler->target_joint_idx]; - if (sampler->animation.values.kind == KEYFRAME_ROTATION) { - // Update the joints rotation - joint->transform_components.rotation = k.rotation; - } else { - WARN("not yet implemented animation kind"); - } - } -} - -void Animation_VisualiseJoints(Armature* armature) { - for (int j = 0; j < armature->joints->len; j++) { - Joint joint = armature->joints->data[j]; - Transform tf = joint.transform_components; - tf.scale = vec3(0.05, 0.05, 0.05); - Immdraw_Sphere(tf, vec4(0, 1, 1, 1), true); - } -} - -ShaderDataLayout AnimData_GetLayout(void* data) { - AnimDataUniform* d = data; - bool has_data = data != NULL; - - ShaderBinding b1 = { .label = "AnimData", - .kind = BINDING_BYTES, - .data.bytes.size = sizeof(AnimDataUniform) }; - - if (has_data) { - b1.data.bytes.data = d; - } - return (ShaderDataLayout){ .bindings = { b1 }, .binding_count = 1 }; -} diff --git a/archive/src/animation.h b/archive/src/animation.h deleted file mode 100644 index 5883f13..0000000 --- a/archive/src/animation.h +++ /dev/null @@ -1,122 +0,0 @@ -#pragma once - -#include "cgltf.h" -#include "darray.h" -#include "defines.h" -#include "maths_types.h" -#include "ral_types.h" - -typedef enum Interpolation { - INTERPOLATION_STEP, - INTERPOLATION_LINEAR, - INTERPOLATION_CUBIC, /** @brief Cubic spline interpolation */ - INTERPOLATION_COUNT -} Interpolation; - -typedef enum KeyframeKind { - KEYFRAME_ROTATION, - KEYFRAME_TRANSLATION, - KEYFRAME_SCALE, - KEYFRAME_WEIGHTS, -} KeyframeKind; - -static const char* keyframe_kind_strings[4] = { "ROTATION", "TRANSLATION", "SCALE", "WEIGHTS"}; - -typedef union Keyframe { - Quat rotation; - Vec3 translation; - Vec3 scale; - f32 weights[4]; -} Keyframe; - -typedef struct Keyframes { - KeyframeKind kind; - Keyframe* values; - size_t count; -} Keyframes; - -typedef struct Joint { - // used instead of pointers later to update correct joints - size_t node_idx; - ssize_t parent; // parent bone. -1 means its the root - size_t children[8]; // children bones, upto 8 - u8 children_count; - char* debug_label; // optional - Mat4 inverse_bind_matrix; - Mat4 local_transform; - /** @brief holds position, rotation, and scale that will be written to by animation - samplers every tick of the animation system. */ - Transform transform_components; -} Joint; -#ifndef TYPED_JOINT_ARRAY -KITC_DECL_TYPED_ARRAY(Joint); -#define TYPED_JOINT_ARRAY -#endif - -typedef u32 JointIdx; - -typedef struct Armature { - char* label; - Joint_darray* joints; -} Armature; - -// NOTE: I think we will need to topologically sort the joints to store them in array if we want to -// do linear array traversal -// when calculating transforms. - -typedef struct AnimationSpline { - f32* timestamps; - size_t n_timestamps; - Keyframes values; - Interpolation interpolation; -} AnimationSpline; - -// combines a sampler and a channel in gltf -typedef struct AnimationSampler { - int current_index; - f32 min; - f32 max; - AnimationSpline animation; - u32 target_joint_idx; // index into the array of joints in an armature -} AnimationSampler; -#ifndef TYPED_ANIM_SAMPLER_ARRAY -KITC_DECL_TYPED_ARRAY(AnimationSampler); -#define TYPED_ANIM_SAMPLER_ARRAY -#endif - -/** @brief Sample an animation at a given time `t` returning an interpolated keyframe */ -PUB Keyframe Animation_Sample(AnimationSampler* sampler, f32 t); - -/** @brief A clip contains one or more animation curves. */ -typedef struct AnimationClip { - const char* clip_name; - bool is_playing; - f32 time; - AnimationSampler_darray* channels; -} AnimationClip; -#ifndef TYPED_ANIM_CLIP_ARRAY -KITC_DECL_TYPED_ARRAY(AnimationClip); -#define TYPED_ANIM_CLIP_ARRAY -#endif - -// typedef struct SkinnedAnimation { -// Mat4* joint_matrices; -// size_t n_joints; -// } SkinnedAnimation; - -PUB void Animation_Play(AnimationClip* clip); - -void Animation_Tick(AnimationClip* clip, Armature* armature, f32 delta_time); - -void Animation_VisualiseJoints(Armature* armature); - -#define MAX_BONES 100 - -typedef struct AnimDataUniform { - Mat4 bone_matrices[MAX_BONES]; -} AnimDataUniform; -ShaderDataLayout AnimData_GetLayout(void* data); - -// Animation Targets: -// - Mesh -// - Joint diff --git a/archive/src/apidocs/coldark_prism.css b/archive/src/apidocs/coldark_prism.css deleted file mode 100644 index 39dd470..0000000 --- a/archive/src/apidocs/coldark_prism.css +++ /dev/null @@ -1,317 +0,0 @@ -/** - * Coldark Theme for Prism.js - * Theme variation: Dark - * Tested with HTML, CSS, JS, JSON, PHP, YAML, Bash script - * @author Armand Philippot - * @homepage https://github.com/ArmandPhilippot/coldark-prism - * @license MIT - */ -code[class*="language-"], -pre[class*="language-"] { - color: #e3eaf2; - background: none; - font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace; - text-align: left; - white-space: pre; - word-spacing: normal; - word-break: normal; - word-wrap: normal; - line-height: 1.5; - -moz-tab-size: 4; - -o-tab-size: 4; - tab-size: 4; - -webkit-hyphens: none; - -moz-hyphens: none; - -ms-hyphens: none; - hyphens: none; -} - -pre[class*="language-"]::-moz-selection, -pre[class*="language-"] ::-moz-selection, -code[class*="language-"]::-moz-selection, -code[class*="language-"] ::-moz-selection { - background: #3c526d; -} - -pre[class*="language-"]::selection, -pre[class*="language-"] ::selection, -code[class*="language-"]::selection, -code[class*="language-"] ::selection { - background: #3c526d; -} - -/* Code blocks */ -pre[class*="language-"] { - padding: 1em; - margin: 0.5em 0; - overflow: auto; -} - -:not(pre) > code[class*="language-"], -pre[class*="language-"] { - background: #111b27; -} - -/* Inline code */ -:not(pre) > code[class*="language-"] { - padding: 0.1em 0.3em; - border-radius: 0.3em; - white-space: normal; -} - -.token.comment, -.token.prolog, -.token.doctype, -.token.cdata { - color: #8da1b9; -} - -.token.punctuation { - color: #e3eaf2; -} - -.token.delimiter.important, -.token.selector .parent, -.token.tag, -.token.tag .token.punctuation { - color: #66cccc; -} - -.token.attr-name, -.token.boolean, -.token.boolean.important, -.token.number, -.token.constant, -.token.selector .token.attribute { - color: #e6d37a; -} - -.token.class-name, -.token.key, -.token.parameter, -.token.property, -.token.property-access, -.token.variable { - color: #6cb8e6; -} - -.token.attr-value, -.token.inserted, -.token.color, -.token.selector .token.value, -.token.string, -.token.string .token.url-link { - color: #91d076; -} - -.token.builtin, -.token.keyword-array, -.token.package, -.token.regex { - color: #f4adf4; -} - -.token.function, -.token.selector .token.class, -.token.selector .token.id { - color: #c699e3; -} - -.token.atrule .token.rule, -.token.combinator, -.token.keyword, -.token.operator, -.token.pseudo-class, -.token.pseudo-element, -.token.selector, -.token.unit { - color: #e9ae7e; -} - -.token.deleted, -.token.important { - color: #cd6660; -} - -.token.keyword-this, -.token.this { - color: #6cb8e6; -} - -.token.important, -.token.keyword-this, -.token.this, -.token.bold { - font-weight: bold; -} - -.token.delimiter.important { - font-weight: inherit; -} - -.token.italic { - font-style: italic; -} - -.token.entity { - cursor: help; -} - -.language-markdown .token.title, -.language-markdown .token.title .token.punctuation { - color: #6cb8e6; - font-weight: bold; -} - -.language-markdown .token.blockquote.punctuation { - color: #f4adf4; -} - -.language-markdown .token.code { - color: #66cccc; -} - -.language-markdown .token.hr.punctuation { - color: #6cb8e6; -} - -.language-markdown .token.url .token.content { - color: #91d076; -} - -.language-markdown .token.url-link { - color: #e6d37a; -} - -.language-markdown .token.list.punctuation { - color: #f4adf4; -} - -.language-markdown .token.table-header { - color: #e3eaf2; -} - -.language-json .token.operator { - color: #e3eaf2; -} - -.language-scss .token.variable { - color: #66cccc; -} - -/* overrides color-values for the Show Invisibles plugin - * https://prismjs.com/plugins/show-invisibles/ - */ -.token.token.tab:not(:empty):before, -.token.token.cr:before, -.token.token.lf:before, -.token.token.space:before { - color: #8da1b9; -} - -/* overrides color-values for the Toolbar plugin - * https://prismjs.com/plugins/toolbar/ - */ -div.code-toolbar > .toolbar.toolbar > .toolbar-item > a, -div.code-toolbar > .toolbar.toolbar > .toolbar-item > button { - color: #111b27; - background: #6cb8e6; -} - -div.code-toolbar > .toolbar.toolbar > .toolbar-item > a:hover, -div.code-toolbar > .toolbar.toolbar > .toolbar-item > a:focus, -div.code-toolbar > .toolbar.toolbar > .toolbar-item > button:hover, -div.code-toolbar > .toolbar.toolbar > .toolbar-item > button:focus { - color: #111b27; - background: #6cb8e6da; - text-decoration: none; -} - -div.code-toolbar > .toolbar.toolbar > .toolbar-item > span, -div.code-toolbar > .toolbar.toolbar > .toolbar-item > span:hover, -div.code-toolbar > .toolbar.toolbar > .toolbar-item > span:focus { - color: #111b27; - background: #8da1b9; -} - -/* overrides color-values for the Line Highlight plugin - * http://prismjs.com/plugins/line-highlight/ - */ -.line-highlight.line-highlight { - background: #3c526d5f; - background: linear-gradient(to right, #3c526d5f 70%, #3c526d55); -} - -.line-highlight.line-highlight:before, -.line-highlight.line-highlight[data-end]:after { - background-color: #8da1b9; - color: #111b27; - box-shadow: 0 1px #3c526d; -} - -pre[id].linkable-line-numbers.linkable-line-numbers span.line-numbers-rows > span:hover:before { - background-color: #8da1b918; -} - -/* overrides color-values for the Line Numbers plugin - * http://prismjs.com/plugins/line-numbers/ - */ -.line-numbers.line-numbers .line-numbers-rows { - border-right: 1px solid #0b121b; - background: #0b121b7a; -} - -.line-numbers .line-numbers-rows > span:before { - color: #8da1b9da; -} - -/* overrides color-values for the Match Braces plugin - * https://prismjs.com/plugins/match-braces/ - */ -.rainbow-braces .token.token.punctuation.brace-level-1, -.rainbow-braces .token.token.punctuation.brace-level-5, -.rainbow-braces .token.token.punctuation.brace-level-9 { - color: #e6d37a; -} - -.rainbow-braces .token.token.punctuation.brace-level-2, -.rainbow-braces .token.token.punctuation.brace-level-6, -.rainbow-braces .token.token.punctuation.brace-level-10 { - color: #f4adf4; -} - -.rainbow-braces .token.token.punctuation.brace-level-3, -.rainbow-braces .token.token.punctuation.brace-level-7, -.rainbow-braces .token.token.punctuation.brace-level-11 { - color: #6cb8e6; -} - -.rainbow-braces .token.token.punctuation.brace-level-4, -.rainbow-braces .token.token.punctuation.brace-level-8, -.rainbow-braces .token.token.punctuation.brace-level-12 { - color: #c699e3; -} - -/* overrides color-values for the Diff Highlight plugin - * https://prismjs.com/plugins/diff-highlight/ - */ -pre.diff-highlight > code .token.token.deleted:not(.prefix), -pre > code.diff-highlight .token.token.deleted:not(.prefix) { - background-color: #cd66601f; -} - -pre.diff-highlight > code .token.token.inserted:not(.prefix), -pre > code.diff-highlight .token.token.inserted:not(.prefix) { - background-color: #91d0761f; -} - -/* overrides color-values for the Command Line plugin - * https://prismjs.com/plugins/command-line/ - */ -.command-line .command-line-prompt { - border-right: 1px solid #0b121b; -} - -.command-line .command-line-prompt > span:before { - color: #8da1b9da; -} diff --git a/archive/src/apidocs/doc_styles.css b/archive/src/apidocs/doc_styles.css deleted file mode 100644 index ee0851b..0000000 --- a/archive/src/apidocs/doc_styles.css +++ /dev/null @@ -1,76 +0,0 @@ -/* - Josh's Custom CSS Reset - https://www.joshwcomeau.com/css/custom-css-reset/ -*/ -*, *::before, *::after { - box-sizing: border-box; -} -* { - margin: 0; -} -body { - line-height: 1.5; - -webkit-font-smoothing: antialiased; -} -img, picture, video, canvas, svg { - display: block; - max-width: 100%; -} -input, button, textarea, select { - font: inherit; -} -p, h1, h2, h3, h4, h5, h6 { - overflow-wrap: break-word; -} -#root, #__next { - isolation: isolate; -} - -/* Styles */ - -html { - -webkit-text-size-adjust: 100%; - -moz-tab-size: 4; - -o-tab-size: 4; - tab-size: 4; - font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; /* 4 */ - font-feature-settings: normal; - font-variation-settings: normal; -} - -pre { - margin: 0; - padding: 0; -} -code { - margin: 0; - padding: 6px 0 !important -} - -:root { - /* TODO: create basic greyscale colours */ -} - -main { - padding: 12px; -} - -h1 { - font-size: 18px; - margin-bottom: 20px; - /* font-weight: 700; */ -} - -h3 { - font-size: 16px; - font-weight: 700; - text-transform: uppercase; -} - -.category-list { - padding: 10px 20px; - list-style-type: none; -} - -.signature { -} diff --git a/archive/src/apidocs/gen_apidocs.py b/archive/src/apidocs/gen_apidocs.py deleted file mode 100644 index d01e441..0000000 --- a/archive/src/apidocs/gen_apidocs.py +++ /dev/null @@ -1,119 +0,0 @@ -# Generates a static webpage for the public C-API of `celeritas-core` -# -# TODO: -# - remove prefixes like 'static' and 'inline' -# - parse docstrings from source - -import re -import os -from pathlib import Path - -# --- HTML Fragments -page_start = """ - - - - - - - - - - - - - - - - Celeritas core API - - -
-""" - -page_header = """ -
-

CELERITAS CORE API DOCS

-
-""" - -page_footer = """ -
-
-""" - -page_end = """ -
- - -""" - -def emit_function_sig(signature: str) -> str: - return f""" -
  • -
    {signature}
    -
  • - """ - -categories = { - "Core": "src/core", - "Render": "src/new_render", - "Maths": "src/maths", - "RAL": "src/ral", - "Systems": "src/systems", -} - -def find_pub_functions_in_folder(folder_path): - functions = [] - for filename in os.listdir(folder_path): - filepath = os.path.join(folder_path, filename) - if os.path.isfile(filepath): - file_funcs = find_pub_functions_in_file(filepath) - functions.extend(file_funcs) - - return functions - -def find_pub_functions_in_file(file_path): - pattern = r'PUB\s+(\w+\s+)*(\w+)\s+(\w+)\s*\((.*?)\)' - - with open(file_path, 'r') as file: - content = file.read() - - matches = re.finditer(pattern, content, re.MULTILINE) - - # Collect all the functions into an array - functions = [] - for match in matches: - signature = match.group(0) - if signature.startswith("PUB "): - signature = signature[4:] - if signature.startswith("c_static_inline "): - signature = signature[16:] - - print(signature) - functions.append(signature) - - return functions - -def generate_html(): - html_filepath = "index.html" - - script_dir = Path(__file__).resolve().parent - grandparent_dir = script_dir.parents[1] - - with open(html_filepath, 'w') as export_file: - export_file.write(page_start) - export_file.write(page_header) - # TODO: make the actual content - for category in categories.keys(): - folder = os.path.join(grandparent_dir, categories[category]) - category_funcs = find_pub_functions_in_folder(folder) - export_file.write(f"

    {category}

    ") - export_file.write("") - export_file.write(page_end) - -if __name__ == "__main__": - generate_html() diff --git a/archive/src/apidocs/index.html b/archive/src/apidocs/index.html deleted file mode 100644 index a72dbf3..0000000 --- a/archive/src/apidocs/index.html +++ /dev/null @@ -1,304 +0,0 @@ - - - - - - - - - - - - - - - - - Celeritas core API - - -
    - -
    -

    CELERITAS CORE API DOCS

    -
    -

    Core

    Render

    Maths

    RAL

    -
    - - diff --git a/archive/src/apidocs/modules.md b/archive/src/apidocs/modules.md deleted file mode 100644 index 7298844..0000000 --- a/archive/src/apidocs/modules.md +++ /dev/null @@ -1,18 +0,0 @@ - - -- core lifecycle -- memory - - arena - - pool -- containers - - darray - - hashtbl - - ring_queue -- maths -- physics -- platform - - file - - path - - mutex - - thread -- threadpool \ No newline at end of file diff --git a/archive/src/apidocs/prism.css b/archive/src/apidocs/prism.css deleted file mode 100644 index 333e985..0000000 --- a/archive/src/apidocs/prism.css +++ /dev/null @@ -1,3 +0,0 @@ -/* PrismJS 1.29.0 -https://prismjs.com/download.html#themes=prism&languages=markup+css+clike */ -code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help} diff --git a/archive/src/apidocs/prism.js b/archive/src/apidocs/prism.js deleted file mode 100644 index d0b4c05..0000000 --- a/archive/src/apidocs/prism.js +++ /dev/null @@ -1,6 +0,0 @@ -/* PrismJS 1.29.0 -https://prismjs.com/download.html#themes=prism&languages=markup+css+clike */ -var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(e){var n=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,r={},a={manual:e.Prism&&e.Prism.manual,disableWorkerMessageHandler:e.Prism&&e.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof i?new i(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,"&").replace(/=g.reach);A+=w.value.length,w=w.next){var E=w.value;if(n.length>e.length)return;if(!(E instanceof i)){var P,L=1;if(y){if(!(P=l(b,A,e,m))||P.index>=e.length)break;var S=P.index,O=P.index+P[0].length,j=A;for(j+=w.value.length;S>=j;)j+=(w=w.next).value.length;if(A=j-=w.value.length,w.value instanceof i)continue;for(var C=w;C!==n.tail&&(jg.reach&&(g.reach=W);var z=w.prev;if(_&&(z=u(n,z,_),A+=_.length),c(n,z,L),w=u(n,z,new i(f,p?a.tokenize(N,p):N,k,N)),M&&u(n,w,M),L>1){var I={cause:f+","+d,reach:W};o(e,n,t,w.prev,A,I),g&&I.reach>g.reach&&(g.reach=I.reach)}}}}}}function s(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function u(e,n,t){var r=n.next,a={value:t,prev:n,next:r};return n.next=a,r.prev=a,e.length++,a}function c(e,n,t){for(var r=n.next,a=0;a"+i.content+""},!e.document)return e.addEventListener?(a.disableWorkerMessageHandler||e.addEventListener("message",(function(n){var t=JSON.parse(n.data),r=t.language,i=t.code,l=t.immediateClose;e.postMessage(a.highlight(i,a.languages[r],r)),l&&e.close()}),!1),a):a;var g=a.util.currentScript();function f(){a.manual||a.highlightAll()}if(g&&(a.filename=g.src,g.hasAttribute("data-manual")&&(a.manual=!0)),!a.manual){var h=document.readyState;"loading"===h||"interactive"===h&&g&&g.defer?document.addEventListener("DOMContentLoaded",f):window.requestAnimationFrame?window.requestAnimationFrame(f):window.setTimeout(f,16)}return a}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism); -Prism.languages.markup={comment:{pattern://,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern://i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},{pattern:/^(\s*)["']|["']$/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},Prism.languages.markup.tag.inside["attr-value"].inside.entity=Prism.languages.markup.entity,Prism.languages.markup.doctype.inside["internal-subset"].inside=Prism.languages.markup,Prism.hooks.add("wrap",(function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))})),Object.defineProperty(Prism.languages.markup.tag,"addInlined",{value:function(a,e){var s={};s["language-"+e]={pattern:/(^$)/i,lookbehind:!0,inside:Prism.languages[e]},s.cdata=/^$/i;var t={"included-cdata":{pattern://i,inside:s}};t["language-"+e]={pattern:/[\s\S]+/,inside:Prism.languages[e]};var n={};n[a]={pattern:RegExp("(<__[^>]*>)(?:))*\\]\\]>|(?!)".replace(/__/g,(function(){return a})),"i"),lookbehind:!0,greedy:!0,inside:t},Prism.languages.insertBefore("markup","cdata",n)}}),Object.defineProperty(Prism.languages.markup.tag,"addAttribute",{value:function(a,e){Prism.languages.markup.tag.inside["special-attr"].push({pattern:RegExp("(^|[\"'\\s])(?:"+a+")\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s'\">=]+(?=[\\s>]))","i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[e,"language-"+e],inside:Prism.languages[e]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup,Prism.languages.xml=Prism.languages.extend("markup",{}),Prism.languages.ssml=Prism.languages.xml,Prism.languages.atom=Prism.languages.xml,Prism.languages.rss=Prism.languages.xml; -!function(s){var e=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;s.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:RegExp("@[\\w-](?:[^;{\\s\"']|\\s+(?!\\s)|"+e.source+")*?(?:;|(?=\\s*\\{))"),inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+e.source+"|(?:[^\\\\\r\n()\"']|\\\\[^])*)\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+e.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+e.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:e,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},s.languages.css.atrule.inside.rest=s.languages.css;var t=s.languages.markup;t&&(t.tag.addInlined("style","css"),t.tag.addAttribute("style","css"))}(Prism); -Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/}; diff --git a/archive/src/apidocs/template.html b/archive/src/apidocs/template.html deleted file mode 100644 index 1e1c7a7..0000000 --- a/archive/src/apidocs/template.html +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - -
    -

    Celeritas Core API

    - -
    -
    - arena - arena_create(void* - backing_buffer, - size_t - capacity); -
    -
    - void* - arena_alloc(arena* - a, - size_t - size); -
    - -
    - - - - \ No newline at end of file diff --git a/archive/src/collision.c b/archive/src/collision.c deleted file mode 100644 index 81cbcfc..0000000 --- a/archive/src/collision.c +++ /dev/null @@ -1,9 +0,0 @@ -#include "immdraw.h" -#include "maths.h" -#include "maths_types.h" -#include "physics.h" - -PUB void Debug_DrawOBB(OBB obb) { - Transform t = transform_create(obb.center, obb.rotation, vec3_sub(obb.bbox.max, obb.bbox.min)); - Immdraw_Cuboid(t, vec4(0.0, 0.8, 0.1, 1.0), true); -} diff --git a/archive/src/colours.h b/archive/src/colours.h deleted file mode 100644 index ac8996a..0000000 --- a/archive/src/colours.h +++ /dev/null @@ -1,89 +0,0 @@ -#pragma once - -#include "defines.h" - -typedef struct rgba { - f32 r, g, b, a; -} rgba; - -#define COLOUR_BLACK ((rgba){ 0.02, 0.02, 0.0, 1.0 }) -#define COLOUR_IMPERIAL_RED ((rgba){ 0.97, 0.09, 0.21, 1.0 }) -#define COLOUR_TRUE_BLUE ((rgba){ 0.11, 0.41, 0.77, 1.0 }) -#define COLOUR_SEA_GREEN ((rgba){ 0.18, 0.77, 0.71, 1.0 }) -#define COLOUR_WHITE ((rgba){ 1.0, 1.0, 1.0, 1.0 }) - -#define rgba_to_vec4(color) (vec4(color.r, color.g, color.b, color.a)) -#define rgba_to_vec3(color) (vec3(color.r, color.g, color.b)) - -// Thanks ChatGPT -#define STONE_50 ((rgba){ 0.980, 0.980, 0.976, 1.0 }) -#define STONE_100 ((rgba){ 0.961, 0.961, 0.957, 1.0 }) -#define STONE_200 ((rgba){ 0.906, 0.898, 0.894, 1.0 }) -#define STONE_300 ((rgba){ 0.839, 0.827, 0.819, 1.0 }) -#define STONE_400 ((rgba){ 0.659, 0.635, 0.620, 1.0 }) -#define STONE_500 ((rgba){ 0.471, 0.443, 0.424, 1.0 }) -#define STONE_600 ((rgba){ 0.341, 0.325, 0.306, 1.0 }) -#define STONE_700 ((rgba){ 0.267, 0.251, 0.235, 1.0 }) -#define STONE_800 ((rgba){ 0.161, 0.145, 0.141, 1.0 }) -#define STONE_900 ((rgba){ 0.110, 0.098, 0.090, 1.0 }) -#define STONE_950 ((rgba){ 0.047, 0.043, 0.035, 1.0 }) - -#define CYAN_50 ((rgba){ 0.930, 1.000, 1.000, 1.0 }) -#define CYAN_100 ((rgba){ 0.810, 0.980, 1.000, 1.0 }) -#define CYAN_200 ((rgba){ 0.650, 0.953, 0.988, 1.0 }) -#define CYAN_300 ((rgba){ 0.404, 0.910, 0.976, 1.0 }) -#define CYAN_400 ((rgba){ 0.133, 0.827, 0.933, 1.0 }) -#define CYAN_500 ((rgba){ 0.023, 0.714, 0.831, 1.0 }) -#define CYAN_600 ((rgba){ 0.031, 0.569, 0.698, 1.0 }) -#define CYAN_700 ((rgba){ 0.055, 0.455, 0.565, 1.0 }) -#define CYAN_800 ((rgba){ 0.082, 0.369, 0.459, 1.0 }) -#define CYAN_900 ((rgba){ 0.086, 0.306, 0.388, 1.0 }) -#define CYAN_950 ((rgba){ 0.033, 0.200, 0.263, 1.0 }) - -#define GRAY_50 ((rgba){ 0.976, 0.980, 0.984, 1.0 }) -#define GRAY_100 ((rgba){ 0.953, 0.957, 0.965, 1.0 }) -#define GRAY_200 ((rgba){ 0.898, 0.906, 0.922, 1.0 }) -#define GRAY_300 ((rgba){ 0.820, 0.835, 0.859, 1.0 }) -#define GRAY_400 ((rgba){ 0.612, 0.639, 0.686, 1.0 }) -#define GRAY_500 ((rgba){ 0.420, 0.447, 0.502, 1.0 }) -#define GRAY_600 ((rgba){ 0.294, 0.333, 0.388, 1.0 }) -#define GRAY_700 ((rgba){ 0.216, 0.255, 0.318, 1.0 }) -#define GRAY_800 ((rgba){ 0.122, 0.161, 0.216, 1.0 }) -#define GRAY_900 ((rgba){ 0.067, 0.094, 0.153, 1.0 }) -#define GRAY_950 ((rgba){ 0.012, 0.027, 0.071, 1.0 }) - -#define RED_50 ((rgba){ 0.996, 0.949, 0.949, 1.0 }) -#define RED_100 ((rgba){ 0.996, 0.886, 0.886, 1.0 }) -#define RED_200 ((rgba){ 0.996, 0.792, 0.792, 1.0 }) -#define RED_300 ((rgba){ 0.988, 0.647, 0.647, 1.0 }) -#define RED_400 ((rgba){ 0.973, 0.443, 0.443, 1.0 }) -#define RED_500 ((rgba){ 0.937, 0.267, 0.267, 1.0 }) -#define RED_600 ((rgba){ 0.863, 0.149, 0.149, 1.0 }) -#define RED_700 ((rgba){ 0.725, 0.110, 0.110, 1.0 }) -#define RED_800 ((rgba){ 0.600, 0.106, 0.106, 1.0 }) -#define RED_900 ((rgba){ 0.498, 0.114, 0.114, 1.0 }) -#define RED_950 ((rgba){ 0.271, 0.039, 0.039, 1.0 }) - -#define ORANGE_50 ((rgba){ 1.000, 0.969, 0.929, 1.0 }) -#define ORANGE_100 ((rgba){ 1.000, 0.929, 0.835, 1.0 }) -#define ORANGE_200 ((rgba){ 0.996, 0.843, 0.667, 1.0 }) -#define ORANGE_300 ((rgba){ 0.992, 0.729, 0.455, 1.0 }) -#define ORANGE_400 ((rgba){ 0.984, 0.573, 0.235, 1.0 }) -#define ORANGE_500 ((rgba){ 0.976, 0.451, 0.086, 1.0 }) -#define ORANGE_600 ((rgba){ 0.918, 0.345, 0.047, 1.0 }) -#define ORANGE_700 ((rgba){ 0.761, 0.255, 0.047, 1.0 }) -#define ORANGE_800 ((rgba){ 0.604, 0.204, 0.071, 1.0 }) -#define ORANGE_900 ((rgba){ 0.486, 0.176, 0.071, 1.0 }) -#define ORANGE_950 ((rgba){ 0.263, 0.078, 0.027, 1.0 }) - -#define AMBER_50 ((rgba){ 1.000, 0.984, 0.922, 1.0 }) -#define AMBER_100 ((rgba){ 0.996, 0.953, 0.780, 1.0 }) -#define AMBER_200 ((rgba){ 0.992, 0.902, 0.541, 1.0 }) -#define AMBER_300 ((rgba){ 0.988, 0.827, 0.302, 1.0 }) -#define AMBER_400 ((rgba){ 0.984, 0.749, 0.141, 1.0 }) -#define AMBER_500 ((rgba){ 0.961, 0.620, 0.043, 1.0 }) -#define AMBER_600 ((rgba){ 0.851, 0.467, 0.024, 1.0 }) -#define AMBER_700 ((rgba){ 0.706, 0.325, 0.035, 1.0 }) -#define AMBER_800 ((rgba){ 0.573, 0.251, 0.055, 1.0 }) -#define AMBER_900 ((rgba){ 0.471, 0.208, 0.059, 1.0 }) -#define AMBER_950 ((rgba){ 0.271, 0.102, 0.012, 1.0 }) diff --git a/archive/src/core/README.md b/archive/src/core/README.md deleted file mode 100644 index 19cc1d0..0000000 --- a/archive/src/core/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Core - -Core engine facilities diff --git a/archive/src/core/animation.c b/archive/src/core/animation.c deleted file mode 100644 index e69de29..0000000 diff --git a/archive/src/core/camera.c b/archive/src/core/camera.c deleted file mode 100644 index 77ddad6..0000000 --- a/archive/src/core/camera.c +++ /dev/null @@ -1,90 +0,0 @@ -#include "camera.h" - -#include "input.h" -#include "keys.h" -#include "maths.h" - -#define CAMERA_SPEED 0.2 -#define CAMERA_SENSITIVITY 0.5 - -Camera Camera_Create(Vec3 pos, Vec3 front, Vec3 up, f32 fov) { - Camera c = { .position = pos, .front = front, .up = up, .fov = fov }; - return c; -} - -Mat4 Camera_ViewProj(Camera* c, f32 lens_height, f32 lens_width, Mat4* out_view, Mat4* out_proj) { - Mat4 proj = mat4_perspective(c->fov, lens_width / lens_height, 0.1, 1000.0); - Vec3 camera_direction = vec3_add(c->position, c->front); - Mat4 view = mat4_look_at(c->position, camera_direction, c->up); - if (out_view) { - *out_view = view; - } - if (out_proj) { - *out_proj = proj; - } - return mat4_mult(view, proj); -} - -void FlyCamera_Update(Camera* camera) { - static f32 yaw = 0.0; - static f32 pitch = 0.0; - - // Keyboard - f32 speed = CAMERA_SPEED; - Vec3 horizontal = vec3_cross(camera->front, camera->up); - if (key_is_pressed(KEYCODE_A) || key_is_pressed(KEYCODE_KEY_LEFT)) { - Vec3 displacement = vec3_mult(horizontal, -speed); - camera->position = vec3_add(camera->position, displacement); - } - if (key_is_pressed(KEYCODE_D) || key_is_pressed(KEYCODE_KEY_RIGHT)) { - Vec3 displacement = vec3_mult(horizontal, speed); - camera->position = vec3_add(camera->position, displacement); - } - if (key_is_pressed(KEYCODE_W) || key_is_pressed(KEYCODE_KEY_UP)) { - Vec3 displacement = vec3_mult(camera->front, speed); - camera->position = vec3_add(camera->position, displacement); - } - if (key_is_pressed(KEYCODE_S) || key_is_pressed(KEYCODE_KEY_DOWN)) { - Vec3 displacement = vec3_mult(camera->front, -speed); - camera->position = vec3_add(camera->position, displacement); - } - if (key_is_pressed(KEYCODE_Q)) { - Vec3 displacement = vec3_mult(camera->up, speed); - camera->position = vec3_add(camera->position, displacement); - } - if (key_is_pressed(KEYCODE_E)) { - Vec3 displacement = vec3_mult(camera->up, -speed); - camera->position = vec3_add(camera->position, displacement); - } - - // Mouse - if (MouseBtn_Held(MOUSEBTN_LEFT)) { - mouse_state mouse = Input_GetMouseState(); - // printf("Delta x: %d Delta y %d\n",mouse.x_delta, mouse.y_delta ); - - f32 x_offset = mouse.x_delta; - f32 y_offset = -mouse.y_delta; - - f32 sensitivity = CAMERA_SENSITIVITY; // change this value to your liking - x_offset *= sensitivity; - y_offset *= sensitivity; - - yaw += x_offset; - pitch += y_offset; - - // make sure that when pitch is out of bounds, screen doesn't get flipped - if (pitch > 89.0f) pitch = 89.0f; - if (pitch < -89.0f) pitch = -89.0f; - - Vec3 front; - front.x = cos(deg_to_rad(yaw) * cos(deg_to_rad(pitch))); - front.y = sin(deg_to_rad(pitch)); - front.z = sin(deg_to_rad(yaw)) * cos(deg_to_rad(pitch)); - front = vec3_normalise(front); - camera->front.x = front.x; - camera->front.y = front.y; - camera->front.z = front.z; - } - - // TODO: Right mouse => pan in screen space -} diff --git a/archive/src/core/camera.h b/archive/src/core/camera.h deleted file mode 100644 index 4300f87..0000000 --- a/archive/src/core/camera.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include "defines.h" -#include "maths_types.h" - -// TODO: swap to position + quaternion - -typedef struct Camera { - Vec3 position; - Vec3 front; - Vec3 up; - f32 fov; -} Camera; - -/** @brief create a camera */ -PUB Camera Camera_Create(Vec3 pos, Vec3 front, Vec3 up, f32 fov); - -/** - * @brief Get 3D camera transform matrix - * @param out_view optionally stores just the view matrix - * @param out_proj optionally stores just the projection matrix - * @returns the camera's view projection matrix pre-multiplied - */ -PUB Mat4 Camera_ViewProj(Camera* c, f32 lens_height, f32 lens_width, Mat4* out_view, - Mat4* out_proj); - -/** @brief Get 2D camera transform matrix */ -PUB Mat4 Camera_View2D(Camera* c); // TODO: 2D cameras - -struct Input_State; - -PUB void FlyCamera_Update(Camera* camera); - -// TODO: (HIGH) Basic reusable camera controls -/* -Right click + move = pan -Left click = orbit camera -WASD = forward/backward/left/right -*/ diff --git a/archive/src/core/core.c b/archive/src/core/core.c deleted file mode 100644 index 64f59f3..0000000 --- a/archive/src/core/core.c +++ /dev/null @@ -1,81 +0,0 @@ -#include "core.h" - -#include - -#include "glfw3.h" -#include "input.h" -#include "keys.h" -#include "log.h" -#include "mem.h" -#include "render.h" -#include "render_types.h" - -// These are only the initial window dimensions -#define SCR_WIDTH 1000 -#define SCR_HEIGHT 1000 - -Core g_core; /** @brief global `Core` that other files can use */ - -/** @brief Gets the global `Core` singleton */ -inline Core* GetCore() { return &g_core; } - -void Core_Bringup(const char* window_name, struct GLFWwindow* optional_window) { - INFO("Initiate Core bringup"); - memset(&g_core, 0, sizeof(Core)); - - RendererConfig conf = { .window_name = window_name, - .scr_width = SCR_WIDTH, - .scr_height = SCR_HEIGHT, - .clear_colour = (Vec3){ .08, .08, .1 } }; - - g_core.renderer = malloc(Renderer_GetMemReqs()); - - // Initialise all subsystems - - // renderer config, renderer ptr, ptr to store a window, and optional preexisting glfw window - if (!Renderer_Init(conf, g_core.renderer, &g_core.window, optional_window)) { - // FATAL("Failed to start renderer"); - ERROR_EXIT("Failed to start renderer\n"); - } - if (optional_window != NULL) { - g_core.window = optional_window; - } - - if (!Input_Init(&g_core.input, g_core.window)) { - // the input system needs the glfw window which is created by the renderer - // hence the order here is important - ERROR_EXIT("Failed to start input system\n"); - } - - size_t model_data_max = 1024 * 1024 * 1024; - arena model_arena = arena_create(malloc(model_data_max), model_data_max); - - Model_pool model_pool = Model_pool_create(&model_arena, 256, sizeof(Model)); - g_core.models = model_pool; - INFO("Created model pool allocator"); -} - -void Core_Shutdown() { - Input_Shutdown(&g_core.input); - Renderer_Shutdown(g_core.renderer); - free(g_core.renderer); -} - -bool ShouldExit() { - return key_just_released(KEYCODE_ESCAPE) || glfwWindowShouldClose(g_core.window); -} - -void Frame_Begin() { - Input_Update(&g_core.input); - Render_FrameBegin(g_core.renderer); -} -void Frame_Draw() {} -void Frame_End() { Render_FrameEnd(g_core.renderer); } - -Core* get_global_core() { return &g_core; } - -GLFWwindow* Core_GetGlfwWindowPtr(Core* core) { return g_core.window; } - -struct Renderer* Core_GetRenderer(Core* core) { return core->renderer; } - -Model* Model_Get(ModelHandle h) { return Model_pool_get(&g_core.models, h); } diff --git a/archive/src/core/core.h b/archive/src/core/core.h deleted file mode 100644 index 14ba65d..0000000 --- a/archive/src/core/core.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include "input.h" -#include "mem.h" -#include "render_types.h" -#include "screenspace.h" -#include "terrain.h" -#include "text.h" - -TYPED_POOL(Model, Model) -#define MODEL_GET(h) (Model_pool_get(&g_core.models, h)) -Model* Model_Get(ModelHandle h); - -typedef struct GLFWwindow GLFWwindow; - -typedef struct Core { - const char* app_name; - GLFWwindow* window; - Renderer* renderer; - Input_State input; - // Model_pool models; -} Core; -extern Core g_core; - -struct Renderer; - -Core* get_global_core(); - -/** - @brief Throws error if the core cannot be instantiated - @param [in] optional_window - Leave NULL if you want Celeritas to instantiate its own window with - GLFW, if you want to provide the glfw window then pass it in here. -*/ -void Core_Bringup(const char* window_name, GLFWwindow* optional_window); -void Core_Shutdown(); -bool ShouldExit(); - -GLFWwindow* Core_GetGlfwWindowPtr(Core* core); -struct Renderer* Core_GetRenderer(Core* core); - -void Frame_Begin(); -void Frame_Draw(); -void Frame_End(); diff --git a/archive/src/core/input.c b/archive/src/core/input.c deleted file mode 100644 index e69de29..0000000 diff --git a/archive/src/core/vfs.h b/archive/src/core/vfs.h deleted file mode 100644 index 41033f5..0000000 --- a/archive/src/core/vfs.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once -#include "defines.h" - -#define MAX_VIRTUAL_FILENAME_LEN 256 - -typedef struct VFS_Pack VFS_Pack; - -const char VFS_OpenErr_DoesNotExist[] = "PATH DOES NOT EXIST"; - -typedef struct VFS_File { - size_t n_bytes; - void* data; -} VFS_File; - -// virtual file open result -typedef struct VFS_FileRes { - bool success; - const char* error_reason; - VFS_File file; -} VFS_FileRes; - -VFS_Pack* VFS_Open(const char* filepath); - -bool VFS_Close(VFS_Pack*); - -VFS_FileRes VFS_VirtualRead(VFS_Pack* vfs, const char* unique_path); - -typedef struct VFS_PackBuilder { - const char* pack_filename; -} VFS_PackBuilder; - -typedef struct VFS_FileEntry { - char filename[MAX_VIRTUAL_FILENAME_LEN]; - size_t offset; - size_t size; -} VFS_FileEntry; - -VFS_PackBuilder VFS_Pack_Create(); \ No newline at end of file diff --git a/archive/src/empty.c b/archive/src/empty.c deleted file mode 100644 index b40cc85..0000000 --- a/archive/src/empty.c +++ /dev/null @@ -1,3 +0,0 @@ -// For some reason on Mac we need an empty file so that 'ar' has something -// to run. -int add(int a, int b) { return a + b; } \ No newline at end of file diff --git a/archive/src/log.c b/archive/src/log.c deleted file mode 100644 index 8bb7a65..0000000 --- a/archive/src/log.c +++ /dev/null @@ -1,56 +0,0 @@ -#include "log.h" - -#include -#include -#include - -#include "defines.h" - -// Regular text -#define BLK "\e[0;30m" -#define RED "\e[0;31m" -#define GRN "\e[0;32m" -#define YEL "\e[0;33m" -#define BLU "\e[0;34m" -#define MAG "\e[0;35m" -#define CYN "\e[0;36m" -#define WHT "\e[0;37m" -#define CRESET "\e[0m" - -static const char* level_strings[6] = { "[FATAL]: ", "[ERROR]: ", "[WARN]: ", - "[INFO]: ", "[DEBUG]: ", "[TRACE]: " }; -static const char* level_colours[6] = { RED, RED, YEL, BLU, CYN, MAG }; - -bool logger_init() { - // TODO: create log file - return true; -} - -void logger_shutdown() { - // does nothing right now -} - -void log_output(log_level level, const char* message, ...) { - char out_message[32000]; - memset(out_message, 0, sizeof(out_message)); - - // format original message - __builtin_va_list arg_ptr; - va_start(arg_ptr, message); - vsnprintf(out_message, 32000, message, arg_ptr); - va_end(arg_ptr); - - char out_message2[32006]; - // prepend log level string - sprintf(out_message2, "%s%s%s%s\n", level_colours[level], level_strings[level], out_message, - CRESET); - - // print message to console - printf("%s", out_message2); -} - -void report_assertion_failure(const char* expression, const char* message, const char* file, - int line) { - log_output(LOG_LEVEL_FATAL, "Assertion failure: %s, message: '%s', in file: %s, on line %d\n", - expression, message, file, line); -} diff --git a/archive/src/log.h b/archive/src/log.h deleted file mode 100644 index 537cb6e..0000000 --- a/archive/src/log.h +++ /dev/null @@ -1,84 +0,0 @@ -#pragma once - -#include -#include -#include - -#define ERROR_EXIT(...) \ - { \ - fprintf(stderr, __VA_ARGS__); \ - exit(1); \ - } - -#define TODO(msg) \ - do { \ - ERROR_EXIT("TODO: %s", msg); \ - } while (0) - -#define LOG_WARN_ENABLED 1 -#define LOG_INFO_ENABLED 1 - -#ifdef CRELEASE -#define LOG_DEBUG_ENABLED 0 -#define LOG_TRACE_ENABLED 0 -#else -#define LOG_DEBUG_ENABLED 1 -#define LOG_TRACE_ENABLED 1 -#endif - -typedef enum log_level { - LOG_LEVEL_FATAL = 0, - LOG_LEVEL_ERROR = 1, - LOG_LEVEL_WARN = 2, - LOG_LEVEL_INFO = 3, - LOG_LEVEL_DEBUG = 4, - LOG_LEVEL_TRACE = 5, -} log_level; - -bool logger_init(); -void logger_shutdown(); - -// TODO: macro that outputs logger macros for a specific subsystem or string prefix e.g. "MEMORY" -> -// logs now have more context potentially have line numbers too? - -void log_output(log_level level, const char* message, ...); - -#define FATAL(message, ...) log_output(LOG_LEVEL_FATAL, message, ##__VA_ARGS__) -#define ERROR(message, ...) log_output(LOG_LEVEL_ERROR, message, ##__VA_ARGS__) -#define WARN(message, ...) log_output(LOG_LEVEL_WARN, message, ##__VA_ARGS__) -#define INFO(message, ...) log_output(LOG_LEVEL_INFO, message, ##__VA_ARGS__) - -#if LOG_DEBUG_ENABLED == 1 -#define DEBUG(message, ...) log_output(LOG_LEVEL_DEBUG, message, ##__VA_ARGS__) -#else -#define DEBUG(message, ...) -#endif - -#if LOG_TRACE_ENABLED == 1 -#define TRACE(message, ...) log_output(LOG_LEVEL_TRACE, message, ##__VA_ARGS__) -#else -#define TRACE(message, ...) -#endif - -// TODO: Move this to an asserts file - -void report_assertion_failure(const char* expression, const char* message, const char* file, - int line); - -#define CASSERT(expr) \ - { \ - if (expr) { \ - } else { \ - report_assertion_failure(#expr, "", __FILE__, __LINE__); \ - __builtin_trap(); \ - } \ - } - -#define CASSERT_MSG(expr, msg) \ - { \ - if (expr) { \ - } else { \ - report_assertion_failure(#expr, msg, __FILE__, __LINE__); \ - __builtin_trap(); \ - } \ - } \ No newline at end of file diff --git a/archive/src/logos/README.md b/archive/src/logos/README.md deleted file mode 100644 index 25b7bef..0000000 --- a/archive/src/logos/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Logos - -Logos is the namespace for threadpool & job system code. This is not a 'system' as it is underlying core unit of the engine. - -Threadpool currently gets initialised at core bringup with a set number of threads and results are processed once per frame -on the main thread. This is subject to change but multithreading is not the highest priority right now. \ No newline at end of file diff --git a/archive/src/logos/tasks.h b/archive/src/logos/tasks.h deleted file mode 100644 index 2e3dc53..0000000 --- a/archive/src/logos/tasks.h +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Common jobs that get run - */ -#pragma once -#include "defines.h" -#include "logos/threadpool.h" -#include "render_types.h" -#include "str.h" - -typedef enum TaskLifetime { - /** ephemeral tasks must be finished by the end of the frame and thus we use a leak and clear - allocation strategy */ - TASK_EPHEMERAL, - /** multi-frame tasks have a more complex lifetime and must be cleaned up by the caller or in a - separate cleanup callback */ - TASK_MULTIFRAME, - TASK_COUNT -} TaskLifetime; - -typedef enum TaskKind { - TASK_RENDER, - TASK_PHYSICS, - TASK_GAMEPLAY, - TASK_ASSET, - TASK_USERLAND, - TASKKIND_COUNT -} TaskKind; - -typedef struct Task { - char* debug_name; - void* params; - bool is_done; -} Task; - -// Macro : give Params and Result structs and it creates a function that knows -// correct sizes - -typedef struct Task_ModelLoad_Params { - Str8 filepath; // filepath to the model on disk -} Task_ModelLoad_Params; -typedef struct Task_ModelLoad_Result { - Model model; -} Task_ModelLoad_Result; - -// Internally it will allocate data for each - -static bool Task_ModelLoad_Typed(Task_ModelLoad_Params* params, Task_ModelLoad_Result* result, - tpool_task_start run_task, tpool_task_on_complete on_success, - tpool_task_on_complete on_failure) { - threadpool_add_task(pool, , tpool_task_on_complete on_success, tpool_task_on_complete on_fail, - bool buffer_result_for_main_thread, void* param_data, u32 param_data_size, - u32 result_data_size) -} - -// do task -// success -void model_load_success(task_globals* globals, void* result) { - Task_ModelLoad_Result* load_res = result; - - // push into render -> renderables ? -} -// fail - -// we can define our custom task here that wraps the more verbose function pointers -static Task Task_ModelLoad(Task_ModelLoad_Params* params, Task_ModelLoad_Result* result) { - Task task; - task.debug_name = "Load Model"; - task.params = params; - - Task_ModelLoad_Typed(params, result, tpool_task_start run_task, tpool_task_on_complete on_success, - tpool_task_on_complete on_failure) - - return task; -} diff --git a/archive/src/logos/threadpool.c b/archive/src/logos/threadpool.c deleted file mode 100644 index 0e82d98..0000000 --- a/archive/src/logos/threadpool.c +++ /dev/null @@ -1,141 +0,0 @@ -#include "threadpool.h" - -#include - -#include "defines.h" -#include "log.h" -#include "ring_queue.h" - -static void* worker_factory(void* arg) { - threadpool_worker* worker = arg; - // INFO("Starting job thread %d", worker->id); - - // Run forever, waiting for jobs. - while (true) { - pthread_mutex_lock(&worker->pool->mutex); - pthread_cond_wait(&worker->pool->has_tasks, &worker->pool->mutex); // wait for work to be ready - - task t; - if (ring_queue_dequeue(worker->pool->task_queue, &t)) { - DEBUG("Job thread %d picked up task %d", worker->id, t.task_id); - } else { - WARN("Job thread %d didnt pick up a task as queue was empty", worker->id); - pthread_mutex_unlock(&worker->pool->mutex); - break; - } - - pthread_mutex_unlock(&worker->pool->mutex); - - // Do the work - bool result = t.do_task(t.params, t.result_data); - - // INFO("Task result was %s", result ? "success" : "failure"); - if (result) { - pthread_mutex_lock(&worker->pool->mutex); - if (t.buffer_result_for_main_thread) { - deferred_task_result dtr = { .task_id = t.task_id, - .callback = t.on_success, - .result_data = t.result_data, - .result_data_size = t.result_data_size }; - deferred_task_result_darray_push(worker->pool->results, dtr); - } else { - // call on complete from here. - } - } else { - // TODO - } - pthread_mutex_unlock(&worker->pool->mutex); - } - - return NULL; -} - -bool threadpool_create(threadpool* pool, u8 thread_count, u32 queue_size) { - INFO("Threadpool init"); - pool->next_task_id = 0; - pool->context = NULL; - - u8 num_worker_threads = thread_count; - if (thread_count > MAX_NUM_THREADS) { - ERROR_EXIT("Threadpool has a hard limit of %d threads, you tried to start one with %d", - MAX_NUM_THREADS, thread_count) - num_worker_threads = MAX_NUM_THREADS; - } - - DEBUG("creating task queue with max length %d", queue_size); - pool->task_queue = ring_queue_new(sizeof(task), queue_size, NULL); - - DEBUG("creating mutex and condition"); - pthread_mutex_init(&pool->mutex, NULL); - pthread_cond_init(&pool->has_tasks, NULL); - - pool->results = deferred_task_result_darray_new(256); - - DEBUG("Spawning %d threads for the threadpool", thread_count); - for (u8 i = 0; i < num_worker_threads; i++) { - pool->workers[i].id = i; - pool->workers[i].pool = pool; - if (pthread_create(&pool->workers[i].thread, NULL, worker_factory, &pool->workers[i]) != 0) { - FATAL("OS error creating job thread"); - return false; - }; - } - - return true; -} - -bool threadpool_add_task(threadpool* pool, tpool_task_start do_task, - tpool_task_on_complete on_success, tpool_task_on_complete on_fail, - bool buffer_result_for_main_thread, void* param_data, u32 param_data_size, - u32 result_data_size) { - void* result_data = malloc(result_data_size); - - task* work_task = malloc(sizeof(task)); - work_task->task_id = 0; - work_task->do_task = do_task; - work_task->on_success = on_success; - work_task->on_failure = on_fail; - work_task->buffer_result_for_main_thread = buffer_result_for_main_thread; - work_task->param_size = param_data_size; - work_task->params = param_data; - work_task->result_data_size = result_data_size; - work_task->result_data = result_data; - - // START critical section - if (pthread_mutex_lock(&pool->mutex) != 0) { - ERROR("Unable to get threadpool lock."); - return false; - } - - work_task->task_id = pool->next_task_id; - pool->next_task_id++; - - ring_queue_enqueue(pool->task_queue, work_task); - DEBUG("Enqueued job"); - pthread_cond_broadcast(&pool->has_tasks); - - if (pthread_mutex_unlock(&pool->mutex) != 0) { - ERROR("couldnt unlock threadpool after adding task."); - return false; // ? - } - // END critical section - - return true; -} - -void threadpool_process_results(threadpool* pool, int _num_to_process) { - pthread_mutex_lock(&pool->mutex); - size_t num_results = deferred_task_result_darray_len(pool->results); - if (num_results > 0) { - u32 _size = ((deferred_task_result*)pool->results->data)[num_results].result_data_size; - deferred_task_result res; - deferred_task_result_darray_pop(pool->results, &res); - pthread_mutex_unlock(&pool->mutex); - task_globals globals = { .pool = pool, .ctx = pool->context }; - res.callback(&globals, res.result_data); - } else { - pthread_mutex_unlock(&pool->mutex); - } -} - -void threadpool_set_ctx(threadpool* pool, void* ctx) { pool->context = ctx; } \ No newline at end of file diff --git a/archive/src/logos/threadpool.h b/archive/src/logos/threadpool.h deleted file mode 100644 index 6390a38..0000000 --- a/archive/src/logos/threadpool.h +++ /dev/null @@ -1,96 +0,0 @@ -/** - A Threadpool has a number of "workers", each which process "tasks" -*/ -#pragma once - -#include - -#include "darray.h" -#include "defines.h" -#include "ring_queue.h" - -#define MAX_NUM_THREADS 16 - -struct threadpool; -typedef struct threadpool threadpool; - -typedef struct task_globals { - threadpool* pool; - void* ctx; -} task_globals; - -/* function pointer */ -typedef bool (*tpool_task_start)(void*, void*); - -/* function pointer */ -typedef void (*tpool_task_on_complete)(task_globals*, void*); - -typedef struct threadpool_worker { - u16 id; - pthread_t thread; - threadpool* pool; // pointer back to the pool so we can get the mutex and cond -} threadpool_worker; - -typedef enum tpool_task_status { - TASK_STATUS_READY, -} task_status; - -typedef struct tpool_task { - u64 task_id; - tpool_task_start do_task; - tpool_task_on_complete on_success; - tpool_task_on_complete on_failure; - bool buffer_result_for_main_thread; - /** @brief a pointer to the parameters data that will be passed into the task. */ - void* params; - u32 param_size; - void* result_data; - u32 result_data_size; -} task; - -typedef struct deferred_task_result { - u64 task_id; - tpool_task_on_complete callback; - u32 result_data_size; - // this gets passed to the void* argument of `tpool_task_on_complete` - void* result_data; -} deferred_task_result; - -#ifndef TYPED_TASK_RESULT_ARRAY -KITC_DECL_TYPED_ARRAY(deferred_task_result) // creates "deferred_task_result_darray" -#define TYPED_TASK_RESULT_ARRAY -#endif - -struct threadpool { - ring_queue* task_queue; - pthread_mutex_t mutex; - pthread_cond_t has_tasks; - threadpool_worker workers[MAX_NUM_THREADS]; - deferred_task_result_darray* results; - u64 next_task_id; - - void* context; -}; - -/** - * @param pool where to store the created threadpool - * @param thread_count how many threads to spawn - * @param queue_size max size of task queue - */ -bool threadpool_create(threadpool* pool, u8 thread_count, u32 queue_size); -void threadpool_destroy(threadpool* pool); - -/** @brief set a context variable for the threadpool that task data has access to */ -void threadpool_set_ctx(threadpool* pool, void* ctx); - -/** - * @brief Add a task to the threadpool - */ -bool threadpool_add_task(threadpool* pool, tpool_task_start do_task, - tpool_task_on_complete on_success, tpool_task_on_complete on_fail, - bool buffer_result_for_main_thread, void* param_data, u32 param_data_size, - u32 result_data_size); - -void threadpool_process_results(threadpool* pool, int num_to_process); - -u32 Tpool_GetNumWorkers(); // how many threads are we using \ No newline at end of file diff --git a/archive/src/maths/geometry.h b/archive/src/maths/geometry.h deleted file mode 100644 index 532651c..0000000 --- a/archive/src/maths/geometry.h +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @file geometry.h - * @author your name (you@domain.com) - * @brief Shapes and intersections between them - * @version 0.1 - * @date 2024-02-24 - * - * @copyright Copyright (c) 2024 - */ -#pragma once - -#include "maths.h" - -// typedef struct line_3d { -// vec3 start, end; -// } line_3d; - -// typedef struct plane { -// vec3 normal; -// } plane; - -typedef struct Cuboid { - Vec3 half_extents; -} Cuboid; - -typedef struct Sphere { - f32 radius; -} Sphere; - -// typedef struct cylinder { -// f32 radius; -// f32 half_height; -// } cylinder; - -// typedef struct cone { -// f32 radius; -// f32 half_height; -// } cone; - -// TODO: -// capsule -// torus -// ray -// frustum -// conical frustum -// wedge - -// 2d... -// line -// circle diff --git a/archive/src/maths/maths.c b/archive/src/maths/maths.c deleted file mode 100644 index 19052fe..0000000 --- a/archive/src/maths/maths.c +++ /dev/null @@ -1,35 +0,0 @@ -#include "maths.h" - -#define c_static_inline - -c_static_inline Vec3 vec3_create(f32 x, f32 y, f32 z) { return (Vec3){ x, y, z }; } -c_static_inline Vec3 vec3_add(Vec3 a, Vec3 b) { return (Vec3){ a.x + b.x, a.y + b.y, a.z + b.z }; } -c_static_inline Vec3 vec3_sub(Vec3 a, Vec3 b) { return (Vec3){ a.x - b.x, a.y - b.y, a.z - b.z }; } -c_static_inline Vec3 vec3_mult(Vec3 a, f32 s) { return (Vec3){ a.x * s, a.y * s, a.z * s }; } -c_static_inline Vec3 vec3_div(Vec3 a, f32 s) { return (Vec3){ a.x / s, a.y / s, a.z / s }; } - -c_static_inline f32 vec3_len_squared(Vec3 a) { return (a.x * a.x) + (a.y * a.y) + (a.z * a.z); } -c_static_inline f32 vec3_len(Vec3 a) { return sqrtf(vec3_len_squared(a)); } -c_static_inline Vec3 vec3_negate(Vec3 a) { return (Vec3){ -a.x, -a.y, -a.z }; } -PUB c_static_inline Vec3 vec3_normalise(Vec3 a) { - f32 length = vec3_len(a); - return vec3_div(a, length); -} - -c_static_inline f32 vec3_dot(Vec3 a, Vec3 b) { return a.x * b.x + a.y * b.y + a.z * b.z; } -c_static_inline Vec3 vec3_cross(Vec3 a, Vec3 b) { - return ( - Vec3){ .x = a.y * b.z - a.z * b.y, .y = a.z * b.x - a.x * b.z, .z = a.x * b.y - a.y * b.x }; -} - -Mat4 mat4_ident() { - return (Mat4){ .data = { 1.0, 0., 0., 0., 0., 1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 1.0 } }; -} - -Mat4 transform_to_mat(Transform* tf) { - Mat4 scale = mat4_scale(tf->scale); - Mat4 rotation = mat4_rotation(tf->rotation); - Mat4 translation = mat4_translation(tf->position); - // return mat4_mult(translation, mat4_mult(rotation, scale)); - return mat4_mult(mat4_mult(scale, rotation), translation); -} \ No newline at end of file diff --git a/archive/src/maths/maths.h b/archive/src/maths/maths.h deleted file mode 100644 index e77b81a..0000000 --- a/archive/src/maths/maths.h +++ /dev/null @@ -1,321 +0,0 @@ -/** - * @file maths.h - * @author your name (you@domain.com) - * @brief - * @version 0.1 - * @date 2024-02-24 - * @copyright Copyright (c) 2024 - */ -#pragma once - -#include -#include -#include "defines.h" -#include "maths_types.h" - -// #undef c_static_inline -// #define c_static_inline static - -// --- Helpers -#define deg_to_rad(x) (x * 3.14 / 180.0) -#define MIN(a, b) (a < b ? a : b) -#define MAX(a, b) (a > b ? a : b) - -// --- Vector Implementations - -// Dimension 3 -PUB c_static_inline Vec3 vec3_create(f32 x, f32 y, f32 z); -#define vec3(x, y, z) ((Vec3){ x, y, z }) -PUB c_static_inline Vec3 vec3_add(Vec3 a, Vec3 b); -PUB c_static_inline Vec3 vec3_sub(Vec3 a, Vec3 b); -PUB c_static_inline Vec3 vec3_mult(Vec3 a, f32 s); -PUB c_static_inline Vec3 vec3_div(Vec3 a, f32 s); - -PUB c_static_inline f32 vec3_len_squared(Vec3 a); -PUB c_static_inline f32 vec3_len(Vec3 a); -PUB c_static_inline Vec3 vec3_negate(Vec3 a); -PUB c_static_inline Vec3 vec3_normalise(Vec3 a); - -PUB c_static_inline f32 vec3_dot(Vec3 a, Vec3 b); -PUB c_static_inline Vec3 vec3_cross(Vec3 a, Vec3 b); - -static const Vec3 VEC3_X = vec3(1.0, 0.0, 0.0); -static const Vec3 VEC3_NEG_X = vec3(-1.0, 0.0, 0.0); -static const Vec3 VEC3_Y = vec3(0.0, 1.0, 0.0); -static const Vec3 VEC3_NEG_Y = vec3(0.0, -1.0, 0.0); -static const Vec3 VEC3_Z = vec3(0.0, 0.0, 1.0); -static const Vec3 VEC3_NEG_Z = vec3(0.0, 0.0, -1.0); -static const Vec3 VEC3_ZERO = vec3(0.0, 0.0, 0.0); -static const Vec3 VEC3_ONES = vec3(1.0, 1.0, 1.0); - -static void print_vec3(Vec3 v) { - printf("{ x: %f, y: %f, z: %f )\n", (f64)v.x, (f64)v.y, (f64)v.z); -} - -// TODO: Dimension 2 -static Vec2 vec2_create(f32 x, f32 y) { return (Vec2){ x, y }; } -#define vec2(x, y) ((Vec2){ x, y }) -static Vec2 vec2_div(Vec2 a, f32 s) { return (Vec2){ a.x / s, a.y / s }; } - -// TODO: Dimension 4 -static Vec4 vec4_create(f32 x, f32 y, f32 z, f32 w) { return (Vec4){ x, y, z, w }; } -#define vec4(x, y, z, w) (vec4_create(x, y, z, w)) -#define VEC4_ZERO ((Vec4){ .x = 0.0, .y = 0.0, .z = 0.0, .w = 0.0 }) - -// --- Quaternion Implementations - -static f32 quat_dot(Quat a, Quat b) { return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; } - -static Quat quat_normalise(Quat a) { - f32 length = sqrtf(quat_dot(a, a)); // same as len squared - - return (Quat){ a.x / length, a.y / length, a.z / length, a.w / length }; -} - -static Quat quat_ident() { return (Quat){ .x = 0.0, .y = 0.0, .z = 0.0, .w = 1.0 }; } - -static Quat quat_from_axis_angle(Vec3 axis, f32 angle, bool normalize) { - const f32 half_angle = 0.5f * angle; - f32 s = sinf(half_angle); - f32 c = cosf(half_angle); - - Quat q = (Quat){ s * axis.x, s * axis.y, s * axis.z, c }; - if (normalize) { - return quat_normalise(q); - } - return q; -} - -// TODO: grok this. -static Quat quat_slerp(Quat a, Quat b, f32 percentage) { - Quat out_quaternion; - - Quat q0 = quat_normalise(a); - Quat q1 = quat_normalise(b); - - // Compute the cosine of the angle between the two vectors. - f32 dot = quat_dot(q0, q1); - - // If the dot product is negative, slerp won't take - // the shorter path. Note that v1 and -v1 are equivalent when - // the negation is applied to all four components. Fix by - // reversing one quaternion. - if (dot < 0.0f) { - q1.x = -q1.x; - q1.y = -q1.y; - q1.z = -q1.z; - q1.w = -q1.w; - dot = -dot; - } - - const f32 DOT_THRESHOLD = 0.9995f; - if (dot > DOT_THRESHOLD) { - // If the inputs are too close for comfort, linearly interpolate - // and normalize the result. - out_quaternion = - (Quat){ q0.x + ((q1.x - q0.x) * percentage), q0.y + ((q1.y - q0.y) * percentage), - q0.z + ((q1.z - q0.z) * percentage), q0.w + ((q1.w - q0.w) * percentage) }; - - return quat_normalise(out_quaternion); - } - - // TODO: Are there math functions that take floats instead of doubles? - - // Since dot is in range [0, DOT_THRESHOLD], acos is safe - f64 theta_0 = cos((f64)dot); // theta_0 = angle between input vectors - f64 theta = theta_0 * (f64)percentage; // theta = angle between v0 and result - f64 sin_theta = sin((f64)theta); // compute this value only once - f64 sin_theta_0 = sin((f64)theta_0); // compute this value only once - - f32 s0 = - cos(theta) - (f64)dot * sin_theta / sin_theta_0; // == sin(theta_0 - theta) / sin(theta_0) - f32 s1 = sin_theta / sin_theta_0; - - return (Quat){ (q0.x * s0) + (q1.x * s1), (q0.y * s0) + (q1.y * s1), (q0.z * s0) + (q1.z * s1), - (q0.w * s0) + (q1.w * s1) }; -} - -// --- Matrix Implementations - -Mat4 mat4_ident(); - -static Mat4 mat4_translation(Vec3 position) { - Mat4 out_matrix = mat4_ident(); - out_matrix.data[12] = position.x; - out_matrix.data[13] = position.y; - out_matrix.data[14] = position.z; - return out_matrix; -} - -static Mat4 mat4_scale(Vec3 scale) { - Mat4 out_matrix = mat4_ident(); - out_matrix.data[0] = scale.x; - out_matrix.data[5] = scale.y; - out_matrix.data[10] = scale.z; - return out_matrix; -} - -// TODO: double check this -static Mat4 mat4_rotation(Quat rotation) { - Mat4 out_matrix = mat4_ident(); - Quat n = quat_normalise(rotation); - - out_matrix.data[0] = 1.0f - 2.0f * n.y * n.y - 2.0f * n.z * n.z; - out_matrix.data[1] = 2.0f * n.x * n.y - 2.0f * n.z * n.w; - out_matrix.data[2] = 2.0f * n.x * n.z + 2.0f * n.y * n.w; - - out_matrix.data[4] = 2.0f * n.x * n.y + 2.0f * n.z * n.w; - out_matrix.data[5] = 1.0f - 2.0f * n.x * n.x - 2.0f * n.z * n.z; - out_matrix.data[6] = 2.0f * n.y * n.z - 2.0f * n.x * n.w; - - out_matrix.data[8] = 2.0f * n.x * n.z - 2.0f * n.y * n.w; - out_matrix.data[9] = 2.0f * n.y * n.z + 2.0f * n.x * n.w; - out_matrix.data[10] = 1.0f - 2.0f * n.x * n.x - 2.0f * n.y * n.y; - - return out_matrix; -} - -static Mat4 mat4_mult(Mat4 lhs, Mat4 rhs) { - Mat4 out_matrix = mat4_ident(); - - const f32* m1_ptr = lhs.data; - const f32* m2_ptr = rhs.data; - f32* dst_ptr = out_matrix.data; - - for (i32 i = 0; i < 4; ++i) { - for (i32 j = 0; j < 4; ++j) { - *dst_ptr = m1_ptr[0] * m2_ptr[0 + j] + m1_ptr[1] * m2_ptr[4 + j] + m1_ptr[2] * m2_ptr[8 + j] + - m1_ptr[3] * m2_ptr[12 + j]; - dst_ptr++; - } - m1_ptr += 4; - } - - return out_matrix; -} - -static Mat4 mat4_transposed(Mat4 matrix) { - Mat4 out_matrix = mat4_ident(); - out_matrix.data[0] = matrix.data[0]; - out_matrix.data[1] = matrix.data[4]; - out_matrix.data[2] = matrix.data[8]; - out_matrix.data[3] = matrix.data[12]; - out_matrix.data[4] = matrix.data[1]; - out_matrix.data[5] = matrix.data[5]; - out_matrix.data[6] = matrix.data[9]; - out_matrix.data[7] = matrix.data[13]; - out_matrix.data[8] = matrix.data[2]; - out_matrix.data[9] = matrix.data[6]; - out_matrix.data[10] = matrix.data[10]; - out_matrix.data[11] = matrix.data[14]; - out_matrix.data[12] = matrix.data[3]; - out_matrix.data[13] = matrix.data[7]; - out_matrix.data[14] = matrix.data[11]; - out_matrix.data[15] = matrix.data[15]; - return out_matrix; -} - -#if defined(CEL_REND_BACKEND_VULKAN) -/** @brief Creates a perspective projection matrix compatible with Vulkan */ -c_static_inline Mat4 mat4_perspective(f32 fov_radians, f32 aspect_ratio, f32 near_clip, - f32 far_clip) { - f32 half_tan_fov = tanf(fov_radians * 0.5f); - Mat4 out_matrix = { .data = { 0 } }; - - out_matrix.data[0] = 1.0f / (aspect_ratio * half_tan_fov); - out_matrix.data[5] = -1.0f / half_tan_fov; // Flip Y-axis for Vulkan - out_matrix.data[10] = -((far_clip + near_clip) / (far_clip - near_clip)); - out_matrix.data[11] = -1.0f; - out_matrix.data[14] = -((2.0f * far_clip * near_clip) / (far_clip - near_clip)); - - return out_matrix; -} -#else -/** @brief Creates a perspective projection matrix */ -static inline Mat4 mat4_perspective(f32 fov_radians, f32 aspect_ratio, f32 near_clip, - f32 far_clip) { - f32 half_tan_fov = tanf(fov_radians * 0.5f); - Mat4 out_matrix = { .data = { 0 } }; - out_matrix.data[0] = 1.0f / (aspect_ratio * half_tan_fov); - out_matrix.data[5] = 1.0f / half_tan_fov; - out_matrix.data[10] = -((far_clip + near_clip) / (far_clip - near_clip)); - out_matrix.data[11] = -1.0f; - out_matrix.data[14] = -((2.0f * far_clip * near_clip) / (far_clip - near_clip)); - return out_matrix; -} -#endif - -/** @brief Creates an orthographic projection matrix */ -static inline Mat4 mat4_orthographic(f32 left, f32 right, f32 bottom, f32 top, f32 near_clip, - f32 far_clip) { - // source: kohi game engine. - Mat4 out_matrix = mat4_ident(); - - f32 lr = 1.0f / (left - right); - f32 bt = 1.0f / (bottom - top); - f32 nf = 1.0f / (near_clip - far_clip); - - out_matrix.data[0] = -2.0f * lr; - out_matrix.data[5] = -2.0f * bt; - out_matrix.data[10] = 2.0f * nf; - - out_matrix.data[12] = (left + right) * lr; - out_matrix.data[13] = (top + bottom) * bt; - out_matrix.data[14] = (far_clip + near_clip) * nf; - - return out_matrix; -} - -static inline Mat4 mat4_look_at(Vec3 position, Vec3 target, Vec3 up) { - Mat4 out_matrix; - Vec3 z_axis; - z_axis.x = target.x - position.x; - z_axis.y = target.y - position.y; - z_axis.z = target.z - position.z; - - z_axis = vec3_normalise(z_axis); - Vec3 x_axis = vec3_normalise(vec3_cross(z_axis, up)); - Vec3 y_axis = vec3_cross(x_axis, z_axis); - - out_matrix.data[0] = x_axis.x; - out_matrix.data[1] = y_axis.x; - out_matrix.data[2] = -z_axis.x; - out_matrix.data[3] = 0; - out_matrix.data[4] = x_axis.y; - out_matrix.data[5] = y_axis.y; - out_matrix.data[6] = -z_axis.y; - out_matrix.data[7] = 0; - out_matrix.data[8] = x_axis.z; - out_matrix.data[9] = y_axis.z; - out_matrix.data[10] = -z_axis.z; - out_matrix.data[11] = 0; - out_matrix.data[12] = -vec3_dot(x_axis, position); - out_matrix.data[13] = -vec3_dot(y_axis, position); - out_matrix.data[14] = vec3_dot(z_axis, position); - out_matrix.data[15] = 1.0f; - - return out_matrix; -} - -// ... - -// --- Transform Implementations - -#define TRANSFORM_DEFAULT \ - ((Transform){ .position = VEC3_ZERO, \ - .rotation = (Quat){ .x = 0., .y = 0., .z = 0., .w = 1. }, \ - .scale = 1.0, \ - .is_dirty = false }) - -static Transform transform_create(Vec3 pos, Quat rot, Vec3 scale) { - return (Transform){ .position = pos, .rotation = rot, .scale = scale, .is_dirty = true }; -} - -Mat4 transform_to_mat(Transform* tf); - -// --- Sizing asserts - -_Static_assert(alignof(Vec3) == 4, "Vec3 is 4 byte aligned"); -_Static_assert(sizeof(Vec3) == 12, "Vec3 is 12 bytes so has no padding"); - -_Static_assert(alignof(Vec4) == 4, "Vec4 is 4 byte aligned"); diff --git a/archive/src/maths/maths_types.h b/archive/src/maths/maths_types.h deleted file mode 100644 index c0ab8e0..0000000 --- a/archive/src/maths/maths_types.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @file maths_types.h - * @author Omniscient - * @brief Maths types - * @date 2024-02-24 - * @copyright Copyright (c) 2024 - */ -#pragma once - -#include "defines.h" - -// --- Types - - - -/** @brief Three dimensional bounding box */ -typedef struct Bbox_3D { - Vec3 min; // minimum point of the box - Vec3 max; // maximum point of the box -} Bbox_3D; - -/** @brief 3D Axis-aligned bounding box */ -typedef Bbox_3D Aabb_3D; - - - -typedef struct Vec4i { - i32 x, y, z, w; -} Vec4i; - -typedef struct Vec4u { - u32 x, y, z, w; -} Vec4u; diff --git a/archive/src/maths/primitives.c b/archive/src/maths/primitives.c deleted file mode 100644 index c24d1e2..0000000 --- a/archive/src/maths/primitives.c +++ /dev/null @@ -1,343 +0,0 @@ -#include "primitives.h" -#include "colours.h" -#include "log.h" -#include "maths.h" -#include "maths_types.h" -#include "ral_types.h" -#include "render_types.h" - -// --- Helpers - -void push_triangle(u32_darray* arr, u32 i0, u32 i1, u32 i2) { - u32_darray_push(arr, i0); - u32_darray_push(arr, i1); - u32_darray_push(arr, i2); -} - -Vec3 plane_vertex_positions[] = { - (Vec3){ -0.5, 0, -0.5 }, - (Vec3){ 0.5, 0, -0.5 }, - (Vec3){ -0.5, 0, 0.5 }, - (Vec3){ 0.5, 0, 0.5 }, -}; - -Geometry Geo_CreatePlane(f32x2 extents, u32 tiling_u, u32 tiling_v) { - CASSERT(tiling_u >= 1 && tiling_v >= 1); - Vertex_darray* vertices = Vertex_darray_new(4); - u32_darray* indices = u32_darray_new(vertices->len); - - Vec3 vert_pos[4]; - memcpy(&vert_pos, plane_vertex_positions, sizeof(plane_vertex_positions)); - for (int i = 0; i < 4; i++) { - vert_pos[i].x *= extents.x; - vert_pos[i].z *= extents.y; - } - VERT_3D(vertices, vert_pos[0], VEC3_Y, vec2(0, 0)); // back left - VERT_3D(vertices, vert_pos[1], VEC3_Y, vec2(1 * tiling_u, 0 * tiling_v)); // back right - VERT_3D(vertices, vert_pos[2], VEC3_Y, vec2(0, 1 * tiling_v)); // front left - VERT_3D(vertices, vert_pos[3], VEC3_Y, vec2(1 * tiling_u, 1 * tiling_v)); // front right - - // push_triangle(indices, 0, 1, 2); - // push_triangle(indices, 2, 1, 3); - push_triangle(indices, 2, 1, 0); - push_triangle(indices, 1, 2, 3); - - for (int i = 0; i < 4; i++) { - printf("Vertex %d: (%f, %f, %f)\n", i, vert_pos[i].x, vert_pos[i].y, vert_pos[i].z); - } - - Geometry geo = { .format = VERTEX_STATIC_3D, - .vertices = vertices, - .has_indices = true, - .index_count = indices->len, - .indices = indices }; - - return geo; -} - -Geometry Geo_CreateCuboid(f32x3 extents) { - Vertex_darray* vertices = Vertex_darray_new(36); - - // back faces - VERT_3D(vertices, BACK_TOP_RIGHT, VEC3_NEG_Z, vec2(1, 0)); - VERT_3D(vertices, BACK_BOT_LEFT, VEC3_NEG_Z, vec2(0, 1)); - VERT_3D(vertices, BACK_TOP_LEFT, VEC3_NEG_Z, vec2(0, 0)); - VERT_3D(vertices, BACK_TOP_RIGHT, VEC3_NEG_Z, vec2(1, 0)); - VERT_3D(vertices, BACK_BOT_RIGHT, VEC3_NEG_Z, vec2(1, 1)); - VERT_3D(vertices, BACK_BOT_LEFT, VEC3_NEG_Z, vec2(0, 1)); - - // front faces - VERT_3D(vertices, FRONT_BOT_LEFT, VEC3_Z, vec2(0, 1)); - VERT_3D(vertices, FRONT_TOP_RIGHT, VEC3_Z, vec2(1, 0)); - VERT_3D(vertices, FRONT_TOP_LEFT, VEC3_Z, vec2(0, 0)); - VERT_3D(vertices, FRONT_BOT_LEFT, VEC3_Z, vec2(0, 1)); - VERT_3D(vertices, FRONT_BOT_RIGHT, VEC3_Z, vec2(1, 1)); - VERT_3D(vertices, FRONT_TOP_RIGHT, VEC3_Z, vec2(1, 0)); - - // top faces - VERT_3D(vertices, BACK_TOP_LEFT, VEC3_Y, vec2(0, 0)); - VERT_3D(vertices, FRONT_TOP_LEFT, VEC3_Y, vec2(0, 1)); - VERT_3D(vertices, FRONT_TOP_RIGHT, VEC3_Y, vec2(1, 1)); - VERT_3D(vertices, BACK_TOP_LEFT, VEC3_Y, vec2(0, 0)); - VERT_3D(vertices, FRONT_TOP_RIGHT, VEC3_Y, vec2(1, 1)); - VERT_3D(vertices, BACK_TOP_RIGHT, VEC3_Y, vec2(1, 0)); - - // bottom faces - VERT_3D(vertices, BACK_BOT_LEFT, VEC3_NEG_Y, vec2(0, 1)); - VERT_3D(vertices, FRONT_BOT_RIGHT, VEC3_NEG_Y, vec2(1, 1)); - VERT_3D(vertices, FRONT_BOT_LEFT, VEC3_NEG_Y, vec2(0, 1)); - VERT_3D(vertices, BACK_BOT_LEFT, VEC3_NEG_Y, vec2(0, 1)); - VERT_3D(vertices, BACK_BOT_RIGHT, VEC3_NEG_Y, vec2(1, 1)); - VERT_3D(vertices, FRONT_BOT_RIGHT, VEC3_NEG_Y, vec2(0, 1)); - - // right faces - VERT_3D(vertices, FRONT_TOP_RIGHT, VEC3_X, vec2(0, 0)); - VERT_3D(vertices, BACK_BOT_RIGHT, VEC3_X, vec2(1, 1)); - VERT_3D(vertices, BACK_TOP_RIGHT, VEC3_X, vec2(1, 0)); - VERT_3D(vertices, BACK_BOT_RIGHT, VEC3_X, vec2(1, 1)); - VERT_3D(vertices, FRONT_TOP_RIGHT, VEC3_X, vec2(0, 0)); - VERT_3D(vertices, FRONT_BOT_RIGHT, VEC3_X, vec2(0, 1)); - - // left faces - VERT_3D(vertices, FRONT_TOP_LEFT, VEC3_NEG_X, vec2(0, 0)); - VERT_3D(vertices, BACK_TOP_LEFT, VEC3_NEG_X, vec2(0, 0)); - VERT_3D(vertices, BACK_BOT_LEFT, VEC3_NEG_X, vec2(0, 0)); - VERT_3D(vertices, BACK_BOT_LEFT, VEC3_NEG_X, vec2(0, 0)); - VERT_3D(vertices, FRONT_BOT_LEFT, VEC3_NEG_X, vec2(0, 0)); - VERT_3D(vertices, FRONT_TOP_LEFT, VEC3_NEG_X, vec2(0, 0)); - - u32_darray* indices = u32_darray_new(vertices->len); - - for (u32 i = 0; i < vertices->len; i++) { - u32_darray_push(indices, i); - vertices->data[i].static_3d.position = - vec3_sub(vertices->data[i].static_3d.position, - vec3(0.5, 0.5, 0.5)); // make center of the cube is the origin of mesh space - } - - Geometry geo = { - .format = VERTEX_STATIC_3D, - .vertices = vertices, - .has_indices = true, - .index_count = indices->len, - .indices = indices, // FIXME: make darray methods that return stack allocated struct - }; - - return geo; -} - -// --- Spheres - -Vec3 spherical_to_cartesian_coords(f32 rho, f32 theta, f32 phi) { - f32 x = rho * sin(phi) * cos(theta); - f32 y = rho * cos(phi); - f32 z = rho * sin(phi) * sin(theta); - return vec3(x, y, z); -} - -Geometry Geo_CreateUVsphere(f32 radius, u32 north_south_lines, u32 east_west_lines) { - assert(east_west_lines >= 3); // sphere will be degenerate and look gacked without at least 3 - assert(north_south_lines >= 3); - - Vertex_darray* vertices = Vertex_darray_new(2 + (east_west_lines - 1) * north_south_lines); - - // Create a UV sphere with spherical coordinates - // a point P on the unit sphere can be represented P(r, theta, phi) - // for each vertex we must convert that to a cartesian R3 coordinate - - // Top point - Vertex top = { .static_3d = { .position = vec3(0, radius, 0), - .normal = vec3_normalise(vec3(0, radius, 0)), - .tex_coords = vec2(0, 0) } }; - Vertex_darray_push(vertices, top); - - // parallels - for (u32 i = 0; i < (east_west_lines - 1); i++) { - // phi should range from 0 to pi - f32 phi = PI * (((f32)i + 1) / (f32)east_west_lines); - - // meridians - for (u32 j = 0; j < east_west_lines; j++) { - // theta should range from 0 to 2PI - f32 theta = TAU * ((f32)j / (f32)north_south_lines); - Vec3 position = spherical_to_cartesian_coords(radius, theta, phi); - // f32 d = vec3_len(position); - // print_vec3(position); - // printf("Phi %f Theta %f d %d\n", phi, theta, d); - // assert(d == radius); // all points on the sphere should be 'radius' away from the origin - Vertex v = { .static_3d = { - .position = position, - .normal = - vec3_normalise(position), // normal vector on sphere is same as position - .tex_coords = vec2(0, 0) // TODO - } }; - Vertex_darray_push(vertices, v); - } - } - - // Bottom point - Vertex bot = { .static_3d = { .position = vec3(0, -radius, 0), - .normal = vec3_normalise(vec3(0, -radius, 0)), - .tex_coords = vec2(0, 0) } }; - Vertex_darray_push(vertices, bot); - - u32_darray* indices = u32_darray_new(1); - - // top bottom rings - for (u32 i = 0; i < north_south_lines; i++) { - u32 i1 = i + 1; - u32 i2 = (i + 1) % north_south_lines + 1; - push_triangle(indices, 0, i2, i1); - /* TRACE("Push triangle (%.2f %.2f %.2f)->(%.2f %.2f %.2f)->(%.2f %.2f %.2f)\n", */ - /* vertices->data[0].static_3d.position.x, vertices->data[0].static_3d.position.y, */ - /* vertices->data[0].static_3d.position.z, vertices->data[i1].static_3d.position.x, */ - /* vertices->data[i1].static_3d.position.y, vertices->data[i1].static_3d.position.z, */ - /* vertices->data[i2].static_3d.position.x, vertices->data[i2].static_3d.position.y, */ - /* vertices->data[i2].static_3d.position.z); */ - u32 bot = vertices->len - 1; - u32 i3 = i + north_south_lines * (east_west_lines - 2) + 1; - u32 i4 = (i + 1) % north_south_lines + north_south_lines * (east_west_lines - 2) + 1; - push_triangle(indices, bot, i3, i4); - } - - // quads - for (u32 i = 0; i < east_west_lines - 2; i++) { - u32 ring_start = i * north_south_lines + 1; - u32 next_ring_start = (i + 1) * north_south_lines + 1; - /* printf("ring start %d next ring start %d\n", ring_start, next_ring_start); */ - /* print_vec3(vertices->data[ring_start].static_3d.position); */ - /* print_vec3(vertices->data[next_ring_start].static_3d.position); */ - for (u32 j = 0; j < north_south_lines; j++) { - u32 i0 = ring_start + j; - u32 i1 = next_ring_start + j; - u32 i2 = ring_start + (j + 1) % north_south_lines; - u32 i3 = next_ring_start + (j + 1) % north_south_lines; - push_triangle(indices, i0, i2, i1); - /* TRACE("Push triangle (%.2f %.2f %.2f)->(%.2f %.2f %.2f)->(%.2f %.2f %.2f)\n", */ - /* vertices->data[i0].static_3d.position.x, vertices->data[i0].static_3d.position.y, */ - /* vertices->data[i0].static_3d.position.z, vertices->data[i1].static_3d.position.x, */ - /* vertices->data[i1].static_3d.position.y, vertices->data[i1].static_3d.position.z, */ - /* vertices->data[i2].static_3d.position.x, vertices->data[i2].static_3d.position.y, */ - /* vertices->data[i2].static_3d.position.z); */ - push_triangle(indices, i1, i2, i3); - } - } - - Geometry geo = { - .format = VERTEX_STATIC_3D, - .vertices = vertices, - .has_indices = true, - .index_count = indices->len, - .indices = indices, - }; - - return geo; -} - -Geometry Geo_CreateCone(f32 radius, f32 height, u32 resolution) { - Vertex_darray* vertices = Vertex_darray_new((resolution + 1) * 2); - u32_darray* indices = u32_darray_new(resolution * 2 * 3); - - // TODO: decide how UVs are unwrapped - - // tip - VERT_3D(vertices, vec3(0.0, height, 0.0), VEC3_Y, vec2(0, 0)); - - // sides - f32 step = TAU / resolution; - - for (u32 i = 0; i < resolution; i++) { - f32 x = cos(step * i) * radius; - f32 z = sin(step * i) * radius; - Vec3 pos = vec3(x, 0.0, z); - Vec3 tip_to_vertex = vec3_sub(pos, vertices->data[0].static_3d.position); - Vec3 center_to_vertex = pos; - Vec3 tangent = vec3_cross(VEC3_Y, center_to_vertex); - Vec3 normal_dir = vec3_cross(tangent, tip_to_vertex); - Vec3 normal = vec3_normalise(normal_dir); - VERT_3D(vertices, pos, normal, vec2(0, 0)); - } - for (u32 i = 1; i < resolution; i++) { - push_triangle(indices, 0, i + 1, i); - } - push_triangle(indices, 0, 1, resolution); - - // base center - u32 center_idx = vertices->len; - VERT_3D(vertices, VEC3_ZERO, VEC3_NEG_Y, vec2(0, 0)); - - // base circle - for (u32 i = 0; i < resolution; i++) { - f32 x = cos(step * i) * radius; - f32 z = sin(step * i) * radius; - VERT_3D(vertices, vec3(x, 0.0, z), VEC3_NEG_Z, vec2(0, 0)); - } - for (u32 i = 1; i < resolution; i++) { - push_triangle(indices, center_idx, center_idx + i, center_idx + i + 1); - } - push_triangle(indices, center_idx, center_idx + resolution, center_idx + 1); - - Geometry geo = { - .format = VERTEX_STATIC_3D, - .vertices = vertices, - .has_indices = true, - .index_count = indices->len, - .indices = indices, - }; - return geo; -} - -Geometry Geo_CreateCylinder(f32 radius, f32 height, u32 resolution) { - Vertex_darray* vertices = Vertex_darray_new(1); - u32_darray* indices = u32_darray_new(1); - - f32 step = TAU / resolution; - - // bot cap - VERT_3D(vertices, VEC3_ZERO, VEC3_NEG_Y, vec2(0, 0)); - for (u32 i = 0; i < resolution; i++) { - VERT_3D(vertices, vec3(cos(step * i) * radius, 0.0, sin(step * i) * radius), VEC3_NEG_Y, - vec2(0, 0)); - } - for (u32 i = 1; i < resolution; i++) { - push_triangle(indices, 0, i, i + 1); - } - push_triangle(indices, 0, resolution, 1); - - // top cap - u32 center_idx = vertices->len; - VERT_3D(vertices, vec3(0.0, height, 0.0), VEC3_Y, vec2(0, 0)); - for (u32 i = 0; i < resolution; i++) { - VERT_3D(vertices, vec3(cos(step * i) * radius, height, sin(step * i) * radius), VEC3_Y, - vec2(0, 0)); - } - for (u32 i = 1; i < resolution; i++) { - push_triangle(indices, center_idx, center_idx + i + 1, center_idx + i); - } - push_triangle(indices, center_idx, center_idx + 1, center_idx + resolution); - - // sides - u32 sides_start = vertices->len; - for (u32 i = 0; i < resolution; i++) { - f32 x = cos(step * i) * radius; - f32 z = sin(step * i) * radius; - // top then bottom - VERT_3D(vertices, vec3(x, height, z), vec3_normalise(vec3(x, 0.0, z)), vec2(0, 0)); - VERT_3D(vertices, vec3(x, 0.0, z), vec3_normalise(vec3(x, 0.0, z)), vec2(0, 0)); - } - for (u32 i = 0; i < resolution; i++) { - u32 current = sides_start + i * 2; - u32 next = sides_start + ((i + 1) % resolution) * 2; - push_triangle(indices, current, next, current + 1); - push_triangle(indices, current + 1, next, next + 1); - } - - Geometry geo = { - .format = VERTEX_STATIC_3D, - .vertices = vertices, - .has_indices = true, - .index_count = indices->len, - .indices = indices, - }; - return geo; -} diff --git a/archive/src/maths/primitives.h b/archive/src/maths/primitives.h deleted file mode 100644 index 4965545..0000000 --- a/archive/src/maths/primitives.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include -#include -#include "core.h" -#include "maths_types.h" -#include "render_types.h" - -Geometry Geo_CreatePlane(f32x2 extents, u32 tiling_u, u32 tiling_v); -Geometry Geo_CreateCuboid(f32x3 extents); -Geometry Geo_CreateCylinder(f32 radius, f32 height, u32 resolution); -Geometry Geo_CreateCone(f32 radius, f32 height, u32 resolution); -Geometry Geo_CreateUVsphere(f32 radius, u32 north_south_lines, u32 east_west_lines); -Geometry Geo_CreateIcosphere(f32 radius, f32 n_subdivisions); - -static const Vec3 BACK_BOT_LEFT = (Vec3){ 0, 0, 0 }; -static const Vec3 BACK_BOT_RIGHT = (Vec3){ 1, 0, 0 }; -static const Vec3 BACK_TOP_LEFT = (Vec3){ 0, 1, 0 }; -static const Vec3 BACK_TOP_RIGHT = (Vec3){ 1, 1, 0 }; -static const Vec3 FRONT_BOT_LEFT = (Vec3){ 0, 0, 1 }; -static const Vec3 FRONT_BOT_RIGHT = (Vec3){ 1, 0, 1 }; -static const Vec3 FRONT_TOP_LEFT = (Vec3){ 0, 1, 1 }; -static const Vec3 FRONT_TOP_RIGHT = (Vec3){ 1, 1, 1 }; - -#define VERT_3D(arr, pos, norm, uv) \ - { \ - Vertex v = { .static_3d = { .position = pos, .normal = norm, .tex_coords = uv } }; \ - Vertex_darray_push(arr, v); \ - } \ No newline at end of file diff --git a/archive/src/physics.h b/archive/src/physics.h deleted file mode 100644 index 134f08b..0000000 --- a/archive/src/physics.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include "geometry.h" -#include "maths_types.h" - -// 'system' means that it gets called per frame - -typedef struct physics_settings { - f32 gravity_strength; -} physics_settings; - -// What else do I need? -// intersection methods - -typedef struct physics_world { - physics_settings settings; -} physics_world; - -physics_world physics_init(physics_settings settings); -void physics_shutdown(physics_world* phys_world); - -/** @brief perform one or more simulation steps */ -void physics_system_update(physics_world* phys_world, f64 deltatime); - -// enum ColliderType { -// CuboidCollider, -// SphereCollider, -// }; - -/** @brief Oriented Bounding Box */ -typedef struct OBB { - Vec3 center; - Bbox_3D bbox; - Quat rotation; -} OBB; - -PUB void Debug_DrawOBB(OBB obb); - -/** @brief generic collider structure */ -typedef struct Collider { - u64 id; // ? Replace with handle? - OBB shape; // NOTE: We're only supporting the one collider type for now - bool on_ground; -} Collider; diff --git a/archive/src/platform/file.c b/archive/src/platform/file.c deleted file mode 100644 index 91daa4f..0000000 --- a/archive/src/platform/file.c +++ /dev/null @@ -1,93 +0,0 @@ -#include "file.h" - -#include -#include -#include -#include -#include - -#include "log.h" -#include "mem.h" -#include "str.h" - -const char* string_from_file(const char* path) { - FILE* f = fopen(path, "rb"); - if (f == NULL) { - ERROR("Error reading file: %s. errno: %d", path, errno); - return NULL; - } - if (ferror(f)) { - ERROR("Error reading file: %s. errno: %d", path, errno); - return NULL; - } - fseek(f, 0, SEEK_END); - long fsize = ftell(f); - rewind(f); - - char* string = malloc(fsize + 1); - fread(string, fsize, 1, f); - fclose(f); - - string[fsize] = '\0'; - - return string; -} - -str8_opt str8_from_file(arena* a, Str8 path) { - char* p = cstr(a, path); - str8_opt result = { .has_value = false }; - - FILE* f = fopen(p, "rb"); - if (f == NULL) { - ERROR("Error reading file: %s. errno: %d", path, errno); - return result; - } - if (ferror(f)) { - ERROR("Error reading file: %s. errno: %d", path, errno); - return result; - } - fseek(f, 0, SEEK_END); - long fsize = ftell(f); - rewind(f); - - u8* raw = arena_alloc(a, fsize + 1); - Str8 contents = Str8_create(raw, fsize); - contents.buf[contents.len] = '\0'; - - fread(raw, fsize, 1, f); - fclose(f); - result.contents = contents; - result.has_value = true; - - return result; -} - -FileData load_spv_file(const char* path) { - FILE* f = fopen(path, "rb"); - if (f == NULL) { - perror("Error opening file"); - return (FileData){ NULL, 0 }; - } - - fseek(f, 0, SEEK_END); - long fsize = ftell(f); - rewind(f); - - char* data = (char*)malloc(fsize); - if (data == NULL) { - perror("Memory allocation failed"); - fclose(f); - return (FileData){ NULL, 0 }; - } - - size_t bytesRead = fread(data, 1, fsize, f); - if (bytesRead < fsize) { - perror("Failed to read the entire file"); - free(data); - fclose(f); - return (FileData){ NULL, 0 }; - } - - fclose(f); - return (FileData){ data, bytesRead }; -} diff --git a/archive/src/platform/file.h b/archive/src/platform/file.h deleted file mode 100644 index 5e5e1e1..0000000 --- a/archive/src/platform/file.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * @file file.h - * @brief File I/O utilities - * @date 2024-02-24 - * @copyright Copyright (c) 2024 - */ -#pragma once - -#include "defines.h" -#include "str.h" - -typedef struct str8_opt { - Str8 contents; - bool has_value; -} str8_opt; - -const char* string_from_file(const char* path); - -str8_opt str8_from_file(arena* a, Str8 path); - -typedef struct { - char* data; - size_t size; -} FileData; - -FileData load_spv_file(const char* path); diff --git a/archive/src/platform/platform.h b/archive/src/platform/platform.h deleted file mode 100644 index c2be630..0000000 --- a/archive/src/platform/platform.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include "defines.h" -#include "str.h" - -// -- Paths -typedef struct path_opt { - Str8 path; - bool has_value; -} path_opt; - -// TODO: convert to using str8 -// TODO: use uppercase code style -path_opt path_parent(arena* a, const char* path); - -// --- Threads -typedef struct CelThread CelThread; - -CelThread Thread_Create(); -void Thread_Destroy(CelThread* thread); - -// --- Mutexes -typedef struct CelMutex CelMutex; - -CelMutex Mutex_Create(); -void Mutex_Destroy(CelMutex* mutex); - -/** @brief Blocks until the mutex can be acquired. if returns false then an error occurred and can - * be checked (TODO) */ -bool Mutex_Lock(CelMutex* mutex); - -/** @brief Tries to acquire the mutex like `mutex_lock` but returns immediately if the mutex has - * already been locked */ -bool Mutex_TryLock(CelMutex* mutex); - -/** @brief Releases a mutex. If it is already unlocked then does nothing */ -void Mutex_Unlock(CelMutex* mutex); diff --git a/archive/src/platform/platform_unix.c b/archive/src/platform/platform_unix.c deleted file mode 100644 index 86ac170..0000000 --- a/archive/src/platform/platform_unix.c +++ /dev/null @@ -1,16 +0,0 @@ -#include "platform.h" - -#if defined(CEL_PLATFORM_LINUX) || defined(CEL_PLATFORM_MAC) - -#include -#include - -path_opt path_parent(arena* a, const char* path) { - // Duplicate the string because dirname doesnt like const literals - char* path_copy = arena_alloc(a, strlen(path) + 1); - strcpy(path_copy, path); - char* path_dirname = dirname(path_copy); - return (path_opt){ .path = Str8_cstr_view(path_dirname), .has_value = true }; -} - -#endif diff --git a/archive/src/platform/platform_windows.c b/archive/src/platform/platform_windows.c deleted file mode 100644 index 21ef359..0000000 --- a/archive/src/platform/platform_windows.c +++ /dev/null @@ -1,22 +0,0 @@ -#include "platform.h" - -#if defined(CEL_PLATFORM_WINDOWS) - -#include -#include -#pragma comment(lib, "Shlwapi.lib") - -path_opt path_parent(arena* a, const char* path) { - // Duplicate the string because PathRemoveFileSpec mutates in-place - size_t len = strlen(path) + 1; - char* path_copy = arena_alloc(a, len); - strcpy_s(path_copy, len, path); - - if (PathRemoveFileSpecA(path_copy)) { - return (path_opt){ .path = Str8_cstr_view(path_copy), .has_value = true }; - } else { - return (path_opt){ .has_value = false }; - } -} - -#endif diff --git a/archive/src/ral/README.md b/archive/src/ral/README.md deleted file mode 100644 index f66b95a..0000000 --- a/archive/src/ral/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# RAL - -**Render Abstraction Layer** is a thin abstraction over graphics APIs. Everything in `render` builds on top of the code in -this folder in order to be API-agnostic. It also makes writing graphics code easier as it smooths over some of the discrepancies -between APIs like texture/buffer creation and updating shader values. \ No newline at end of file diff --git a/archive/src/ral/backends/metal/backend_metal.h b/archive/src/ral/backends/metal/backend_metal.h deleted file mode 100644 index e69de29..0000000 diff --git a/archive/src/ral/backends/opengl/backend_opengl.c b/archive/src/ral/backends/opengl/backend_opengl.c deleted file mode 100644 index 613d7e1..0000000 --- a/archive/src/ral/backends/opengl/backend_opengl.c +++ /dev/null @@ -1,449 +0,0 @@ -#include "backend_opengl.h" -#include "colours.h" -#include "maths_types.h" -#if defined(CEL_REND_BACKEND_OPENGL) -#include -#include "log.h" -#include "mem.h" -#include "opengl_helpers.h" -#include "ral_common.h" -#include "ral_impl.h" -#include "ral_types.h" - -#include -#include - -typedef struct OpenglCtx { - GLFWwindow* window; - arena pool_arena; - GPU_Swapchain swapchain; - GPU_CmdEncoder main_encoder; - GPU_BackendPools gpu_pools; - ResourcePools* resource_pools; -} OpenglCtx; - -static OpenglCtx context; - -bool GPU_Backend_Init(const char* window_name, struct GLFWwindow* window, - struct ResourcePools* res_pools) { - INFO("loading OpenGL backend"); - - memset(&context, 0, sizeof(context)); - context.window = window; - - size_t pool_buffer_size = 1024 * 1024; - context.pool_arena = arena_create(malloc(pool_buffer_size), pool_buffer_size); - - BackendPools_Init(&context.pool_arena, &context.gpu_pools); - context.resource_pools = res_pools; - - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); - - // glad: load all opengl function pointers - if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { - ERROR("Failed to initialise GLAD \n"); - return false; - } - - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); - - context.swapchain = (GPU_Swapchain){ .dimensions = u32x2(1000, 1000) }; - - return true; -} - -// All of these are no-ops in OpenGL -void GPU_Backend_Shutdown() { /* TODO */ } -bool GPU_Device_Create(GPU_Device* out_device) { return true; } -void GPU_Device_Destroy(GPU_Device* device) {} -bool GPU_Swapchain_Create(GPU_Swapchain* out_swapchain) { return true; } -void GPU_Swapchain_Destroy(GPU_Swapchain* swapchain) {} -void GPU_CmdEncoder_Destroy(GPU_CmdEncoder* encoder) {} - -void GPU_CmdEncoder_BeginRender(GPU_CmdEncoder* encoder, GPU_Renderpass* renderpass) { - glBindFramebuffer(GL_FRAMEBUFFER, renderpass->fbo); - // rgba clear_colour = STONE_800; - // glClearColor(clear_colour.r, clear_colour.g, clear_colour.b, 1.0f); - // if (renderpass->description.has_depth_stencil) { - // glClear(GL_DEPTH_BUFFER_BIT); - // } else { - // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // } -} - -void GPU_CmdEncoder_EndRender(GPU_CmdEncoder* encoder) { glBindFramebuffer(GL_FRAMEBUFFER, 0); } - -GPU_CmdEncoder* GPU_GetDefaultEncoder() { return &context.main_encoder; } -void GPU_QueueSubmit(GPU_CmdBuffer* cmd_buffer) {} - -void GPU_Swapchain_Resize(i32 new_width, i32 new_height) { - context.swapchain.dimensions = u32x2(new_width, new_height); -} - -u32x2 GPU_Swapchain_GetDimensions() { return context.swapchain.dimensions; } - -GPU_Renderpass* GPU_Renderpass_Create(GPU_RenderpassDesc description) { - // allocate new pass - GPU_Renderpass* renderpass = Renderpass_pool_alloc(&context.gpu_pools.renderpasses, NULL); - renderpass->description = description; - - if (!description.default_framebuffer) { - // If we're not using the default framebuffer we need to generate a new one - GLuint gl_fbo_id; - glGenFramebuffers(1, &gl_fbo_id); - renderpass->fbo = gl_fbo_id; - } else { - renderpass->fbo = OPENGL_DEFAULT_FRAMEBUFFER; - assert(!description.has_color_target); - assert(!description.has_depth_stencil); - } - glBindFramebuffer(GL_FRAMEBUFFER, renderpass->fbo); - - if (description.has_color_target && !description.default_framebuffer) { - GPU_Texture* colour_attachment = TEXTURE_GET(description.color_target); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - colour_attachment->id, 0); - } - if (description.has_depth_stencil && !description.default_framebuffer) { - GPU_Texture* depth_attachment = TEXTURE_GET(description.depth_stencil); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_attachment->id, - 0); - } - - if (description.has_depth_stencil && !description.has_color_target) { - glDrawBuffer(GL_NONE); - glReadBuffer(GL_NONE); - } - - glBindFramebuffer(GL_FRAMEBUFFER, 0); // reset to default framebuffer - - return renderpass; -} - -void GPU_Renderpass_Destroy(GPU_Renderpass* pass) { glDeleteFramebuffers(1, &pass->fbo); } - -GPU_Pipeline* GPU_GraphicsPipeline_Create(GraphicsPipelineDesc description, - GPU_Renderpass* renderpass) { - GPU_Pipeline* pipeline = Pipeline_pool_alloc(&context.gpu_pools.pipelines, NULL); - - // Create shader program - u32 shader_id = shader_create_separate(description.vs.filepath.buf, description.fs.filepath.buf); - pipeline->shader_id = shader_id; - - // Vertex format - pipeline->vertex_desc = description.vertex_desc; - - // Allocate uniform buffers if needed - u32 ubo_count = 0; - // printf("data layouts %d\n", description.data_layouts_count); - for (u32 layout_i = 0; layout_i < description.data_layouts_count; layout_i++) { - ShaderDataLayout sdl = description.data_layouts[layout_i]; - TRACE("Got shader data layout %d's bindings! . found %d", layout_i, sdl.binding_count); - - for (u32 binding_j = 0; binding_j < sdl.binding_count; binding_j++) { - u32 binding_id = binding_j; - assert(binding_id < MAX_PIPELINE_UNIFORM_BUFFERS); - ShaderBinding binding = sdl.bindings[binding_j]; - // Do I want Buffer vs Bytes? - if (binding.kind == BINDING_BYTES) { - static u32 s_binding_point = 0; - BufferHandle ubo_handle = GPU_BufferCreate(binding.data.bytes.size, BUFFER_UNIFORM, - BUFFER_FLAG_GPU, NULL); // no data right now - pipeline->uniform_bindings[ubo_count++] = ubo_handle; - GPU_Buffer* ubo_buf = BUFFER_GET(ubo_handle); - - i32 blockIndex = glGetUniformBlockIndex(pipeline->shader_id, binding.label); - printf("Block index for %s: %d", binding.label, blockIndex); - if (blockIndex < 0) { - WARN("Couldn't retrieve block index for uniform block '%s'", binding.label); - } else { - // DEBUG("Retrived block index %d for %s", blockIndex, binding.label); - } - u32 blocksize; - glGetActiveUniformBlockiv(pipeline->shader_id, blockIndex, GL_UNIFORM_BLOCK_DATA_SIZE, - &blocksize); - printf("\t with size %d bytes\n", blocksize); - - glBindBufferBase(GL_UNIFORM_BUFFER, s_binding_point, ubo_buf->id.ubo); - if (blockIndex != GL_INVALID_INDEX) { - glUniformBlockBinding(pipeline->shader_id, blockIndex, s_binding_point); - } - ubo_buf->ubo_binding_point = s_binding_point++; - ubo_buf->name = binding.label; - assert(s_binding_point < GL_MAX_UNIFORM_BUFFER_BINDINGS); - } - } - } - pipeline->uniform_count = ubo_count; - - pipeline->renderpass = renderpass; - pipeline->wireframe = description.wireframe; - - return pipeline; -} - -void GraphicsPipeline_Destroy(GPU_Pipeline* pipeline) {} - -GPU_CmdEncoder GPU_CmdEncoder_Create() { - GPU_CmdEncoder encoder = { 0 }; - return encoder; -} - -BufferHandle GPU_BufferCreate(u64 size, GPU_BufferType buf_type, GPU_BufferFlags flags, - const void* data) { - // "allocating" the cpu-side buffer struct - BufferHandle handle; - GPU_Buffer* buffer = Buffer_pool_alloc(&context.resource_pools->buffers, &handle); - buffer->size = size; - buffer->vao = 0; - - // Opengl buffer - GLuint gl_buffer_id; - glGenBuffers(1, &gl_buffer_id); - - GLenum gl_buf_type; - GLenum gl_buf_usage = GL_STATIC_DRAW; - - switch (buf_type) { - case BUFFER_UNIFORM: - DEBUG("Creating Uniform buffer"); - gl_buf_type = GL_UNIFORM_BUFFER; - /* gl_buf_usage = GL_DYNAMIC_DRAW; */ - buffer->id.ubo = gl_buffer_id; - break; - case BUFFER_DEFAULT: - case BUFFER_VERTEX: - DEBUG("Creating Vertex buffer"); - gl_buf_type = GL_ARRAY_BUFFER; - buffer->id.vbo = gl_buffer_id; - break; - case BUFFER_INDEX: - DEBUG("Creating Index buffer"); - gl_buf_type = GL_ELEMENT_ARRAY_BUFFER; - buffer->id.ibo = gl_buffer_id; - break; - default: - WARN("Unimplemented gpu_buffer_type provided %s", buffer_type_names[buf_type]); - break; - } - // bind buffer - glBindBuffer(gl_buf_type, gl_buffer_id); - - if (data) { - TRACE("Upload data (%d bytes) as part of buffer creation", size); - glBufferData(gl_buf_type, buffer->size, data, gl_buf_usage); - } else { - TRACE("Allocating but not uploading (%d bytes)", size); - glBufferData(gl_buf_type, buffer->size, NULL, gl_buf_usage); - } - - glBindBuffer(gl_buf_type, 0); - - return handle; -} - -void GPU_BufferDestroy(BufferHandle handle) { glDeleteBuffers(1, &handle.raw); } - -TextureHandle GPU_TextureCreate(TextureDesc desc, bool create_view, const void* data) { - // "allocating" the cpu-side struct - TextureHandle handle; - GPU_Texture* texture = Texture_pool_alloc(&context.resource_pools->textures, &handle); - DEBUG("Allocated texture with handle %d", handle.raw); - - GLuint gl_texture_id; - glGenTextures(1, &gl_texture_id); - texture->id = gl_texture_id; - - GLenum gl_tex_type = opengl_tex_type(desc.tex_type); - texture->type = desc.tex_type; - printf("Creating texture of type %s\n", texture_type_names[desc.tex_type]); - glBindTexture(gl_tex_type, gl_texture_id); - - GLint internal_format; - if (desc.format == TEXTURE_FORMAT_DEPTH_DEFAULT) { - internal_format = GL_DEPTH_COMPONENT; - } else if (desc.format == TEXTURE_FORMAT_8_8_8_8_RGBA_UNORM) { - internal_format = GL_RGBA; - } else { - internal_format = GL_RGB; - } - - GLint format = internal_format; - // FIXME: GLint format = desc.format == TEXTURE_FORMAT_DEPTH_DEFAULT ? GL_DEPTH_COMPONENT : - // GL_RGBA; - GLenum data_type = desc.format == TEXTURE_FORMAT_DEPTH_DEFAULT ? GL_FLOAT : GL_UNSIGNED_BYTE; - - if (desc.format == TEXTURE_FORMAT_DEPTH_DEFAULT) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - } else { - // set the texture wrapping parameters - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, - GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - // set texture filtering parameters - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } - - if (data) { - glTexImage2D(GL_TEXTURE_2D, 0, internal_format, desc.extents.x, desc.extents.y, 0, format, - data_type, data); - if (desc.tex_type == TEXTURE_TYPE_2D) { - glGenerateMipmap(GL_TEXTURE_2D); - } - } else { - WARN("No image data provided"); - glTexImage2D(GL_TEXTURE_2D, 0, internal_format, desc.extents.x, desc.extents.y, 0, format, - data_type, NULL); - } - - glBindTexture(GL_TEXTURE_2D, 0); - - return handle; -} - -GPU_Texture* GPU_TextureAlloc(TextureHandle* out_handle) { - TextureHandle handle; - GPU_Texture* texture = Texture_pool_alloc(&context.resource_pools->textures, &handle); - DEBUG("Allocated texture with handle %d", handle.raw); - - GLuint gl_texture_id; - glGenTextures(1, &gl_texture_id); - texture->id = gl_texture_id; - - if (out_handle != NULL) { - *out_handle = handle; - } - - return texture; -} - -void GPU_TextureDestroy(TextureHandle handle) { glDeleteTextures(1, &handle.raw); } - -// TODO: void GPU_TextureUpload(TextureHandle handle, size_t n_bytes, const void* data) - -void GPU_EncodeBindPipeline(GPU_CmdEncoder* encoder, GPU_Pipeline* pipeline) { - encoder->pipeline = pipeline; - - // In OpenGL binding a pipeline is more or less equivalent to just setting the shader - glUseProgram(pipeline->shader_id); - - if (pipeline->wireframe) { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - } else { - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } -} - -void GPU_EncodeBindShaderData(GPU_CmdEncoder* encoder, u32 group, ShaderDataLayout layout) { - for (u32 binding_i = 0; binding_i < layout.binding_count; binding_i++) { - ShaderBinding binding = layout.bindings[binding_i]; - - switch (binding.kind) { - case BINDING_BYTES: { -#ifdef RAL_ASSERTS - CASSERT_MSG(binding.data.bytes.data, "void* data pointer should be non null"); - CASSERT_MSG(binding.data.bytes.size > 0, "size should be greater than 0 bytes"); -#endif - BufferHandle b; - GPU_Buffer* ubo_buf; - bool found = false; - for (u32 i = 0; i < encoder->pipeline->uniform_count; i++) { - b = encoder->pipeline->uniform_bindings[i]; - ubo_buf = BUFFER_GET(b); - assert(ubo_buf->name != NULL); - if (strcmp(ubo_buf->name, binding.label) == 0) { - found = true; - break; - } - } - if (!found) { - ERROR("Couldnt find uniform buffer object for %s!!", binding.label); - break; - } - - i32 blockIndex = glGetUniformBlockIndex(encoder->pipeline->shader_id, binding.label); - if (blockIndex < 0) { - WARN("Couldn't retrieve block index for uniform block '%s'", binding.label); - break; - } - - glBindBuffer(GL_UNIFORM_BUFFER, ubo_buf->id.ubo); - glBufferSubData(GL_UNIFORM_BUFFER, 0, ubo_buf->size, binding.data.bytes.data); - break; - } - case BINDING_TEXTURE: { - GPU_Texture* tex = TEXTURE_GET(binding.data.texture.handle); - GLint tex_slot = glGetUniformLocation(encoder->pipeline->shader_id, binding.label); - if (tex_slot == GL_INVALID_VALUE || tex_slot < 0) { - WARN("Invalid binding label for texture %s - couldn't fetch texture slot uniform", - binding.label); - } - glUniform1i(tex_slot, binding_i); - glActiveTexture(GL_TEXTURE0 + binding_i); - glBindTexture(opengl_tex_type(tex->type), tex->id); - break; - } - default: - WARN("Unsupported binding kind"); - } - } -} - -void GPU_EncodeSetDefaults(GPU_CmdEncoder* encoder) {} - -void GPU_EncodeSetVertexBuffer(GPU_CmdEncoder* encoder, BufferHandle buf) { - GPU_Buffer* buffer = BUFFER_GET(buf); - if (buffer->vao == 0) { // if no VAO for this vertex buffer, create it - INFO("Setting up VAO"); - buffer->vao = opengl_bindcreate_vao(buffer, encoder->pipeline->vertex_desc); - } - glBindVertexArray(buffer->vao); -} -void GPU_EncodeSetIndexBuffer(GPU_CmdEncoder* encoder, BufferHandle buf) { - GPU_Buffer* buffer = BUFFER_GET(buf); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer->id.ibo); -} -void GPU_EncodeDrawTris(GPU_CmdEncoder* encoder, u64 count) { - glDrawArrays(GL_TRIANGLES, 0, count); -} -void GPU_EncodeDrawIndexedTris(GPU_CmdEncoder* encoder, u64 index_count) { - glDrawElements(GL_TRIANGLES, index_count, GL_UNSIGNED_INT, 0); -} - -PUB void GPU_EncodeDraw(GPU_CmdEncoder* encoder, PrimitiveTopology topology, u64 count) { - glDrawArrays(opengl_prim_topology(topology), 0, count); -} -PUB void GPU_EncodeDrawIndexed(GPU_CmdEncoder* encoder, PrimitiveTopology topology, - u64 index_count) { - glDrawElements(opengl_prim_topology(topology), index_count, GL_UNSIGNED_INT, 0); -} - -PUB void GPU_WriteTextureRegion(GPU_CmdEncoder* encoder, TextureHandle dst, u32 x_offset, - u32 y_offset, u32 width, u32 height, const void* data) { - CASSERT_MSG(data, "const void* data must not be NULL"); - - GPU_Texture* tex = TEXTURE_GET(dst); - - glBindTexture(GL_TEXTURE_2D, tex->id); - glTexSubImage2D(GL_TEXTURE_2D, 0, x_offset, y_offset, width, height, GL_RGBA, GL_UNSIGNED_BYTE, - data); -} - -bool GPU_Backend_BeginFrame() { - glViewport(0, 0, context.swapchain.dimensions.x * 2, context.swapchain.dimensions.y * 2); - glClearColor(0.1f, 0.1f, 0.1f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - return true; -} - -void GPU_Backend_EndFrame() { glfwSwapBuffers(context.window); } - -#endif diff --git a/archive/src/ral/backends/opengl/backend_opengl.h b/archive/src/ral/backends/opengl/backend_opengl.h deleted file mode 100644 index 7bd1b81..0000000 --- a/archive/src/ral/backends/opengl/backend_opengl.h +++ /dev/null @@ -1,109 +0,0 @@ -#pragma once -#include "defines.h" - -#if defined(CEL_REND_BACKEND_OPENGL) - -#include "maths_types.h" -#include "ral_impl.h" -#include "ral_types.h" - -#define MAX_PIPELINE_UNIFORM_BUFFERS 32 - -#define OPENGL_DEFAULT_FRAMEBUFFER 0 - -typedef struct GPU_Swapchain { - u32x2 dimensions; -} GPU_Swapchain; - -typedef struct GPU_Device { - u32 pad; -} GPU_Device; - -typedef struct GPU_PipelineLayout { - void* pad; -} GPU_PipelineLayout; - -typedef struct GPU_Pipeline { - u32 shader_id; - GPU_Renderpass* renderpass; - VertexDescription vertex_desc; - BufferHandle uniform_bindings[MAX_PIPELINE_UNIFORM_BUFFERS]; - u32 uniform_count; - bool wireframe; -} GPU_Pipeline; - -typedef struct GPU_Renderpass { - u32 fbo; - GPU_RenderpassDesc description; -} GPU_Renderpass; - -typedef struct GPU_CmdEncoder { - GPU_Pipeline* pipeline; -} GPU_CmdEncoder; // Recording - -typedef struct GPU_CmdBuffer { - void* pad; -} GPU_CmdBuffer; // Ready for submission - -typedef struct GPU_Buffer { - union { - u32 vbo; - u32 ibo; - u32 ubo; - } id; - union { - u32 vao; - u32 ubo_binding_point; - }; // Optional - char* name; - u64 size; -} GPU_Buffer; - -typedef struct GPU_Texture { - u32 id; - GPU_TextureType type; -} GPU_Texture; - -typedef struct opengl_support { - u32 pad; -} opengl_support; - -void uniform_vec3f(u32 program_id, const char* uniform_name, Vec3* value); -void uniform_f32(u32 program_id, const char* uniform_name, f32 value); -void uniform_i32(u32 program_id, const char* uniform_name, i32 value); -void uniform_mat4f(u32 program_id, const char* uniform_name, Mat4* value); - -typedef enum GlCommandType { - GLCMD_DRAW, - GLCMD_DRAW_INDEXED, - GLCMD_BIND_VBUF, - GLCMD_BIND_IBUF, - GLCMD_SET_PROGRAM, -} GlCommandType; - -typedef struct GlCommand { - GlCommandType cmd_type; - union { - struct { - PrimitiveTopology topology; - u32 start_vertex; - u32 vertex_count; - // TODO: instance - } draw; - struct { - PrimitiveTopology topology; - u32 index_count; - } draw_indexed; - struct { - u32 buffer_id; - } bind_vbuf; - struct { - u32 buffer_id; - } bind_ibuf; - struct { - u32 program_id; - } set_program; - } data; -} GlCommand; - -#endif diff --git a/archive/src/ral/backends/opengl/opengl_helpers.h b/archive/src/ral/backends/opengl/opengl_helpers.h deleted file mode 100644 index 706e2a0..0000000 --- a/archive/src/ral/backends/opengl/opengl_helpers.h +++ /dev/null @@ -1,159 +0,0 @@ -#pragma once -#include "defines.h" -#include "ral_common.h" -#include "ral_impl.h" -#if defined(CEL_REND_BACKEND_OPENGL) -#include "backend_opengl.h" -#include "file.h" -#include "log.h" -#include "ral_types.h" - -#include -#include -#include "ral_types.h" - -typedef struct opengl_vertex_attr { - u32 count; - GLenum data_type; -} opengl_vertex_attr; - -static opengl_vertex_attr format_from_vertex_attr(VertexAttribType attr) { - switch (attr) { - case ATTR_F32: - return (opengl_vertex_attr){ .count = 1, .data_type = GL_FLOAT }; - case ATTR_U32: - return (opengl_vertex_attr){ .count = 1, .data_type = GL_UNSIGNED_INT }; - case ATTR_I32: - return (opengl_vertex_attr){ .count = 1, .data_type = GL_INT }; - case ATTR_F32x2: - return (opengl_vertex_attr){ .count = 2, .data_type = GL_FLOAT }; - case ATTR_U32x2: - // return VK_FORMAT_R32G32_UINT; - case ATTR_I32x2: - // return VK_FORMAT_R32G32_UINT; - case ATTR_F32x3: - return (opengl_vertex_attr){ .count = 3, .data_type = GL_FLOAT }; - case ATTR_U32x3: - // return VK_FORMAT_R32G32B32_UINT; - case ATTR_I32x3: - // return VK_FORMAT_R32G32B32_SINT; - case ATTR_F32x4: - return (opengl_vertex_attr){ .count = 4, .data_type = GL_FLOAT }; - case ATTR_U32x4: - // return VK_FORMAT_R32G32B32A32_UINT; - case ATTR_I32x4: - return (opengl_vertex_attr){ .count = 4, .data_type = GL_INT }; - } -} - -static u32 opengl_bindcreate_vao(GPU_Buffer* buf, VertexDescription desc) { - DEBUG("Vertex format name %s", desc.debug_label); - // 1. Bind the buffer - glBindBuffer(GL_ARRAY_BUFFER, buf->id.vbo); - // 2. Create new VAO - u32 vao; - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); - - // Attributes - u32 attr_count = desc.attributes_count; - // printf("N attributes %d\n", attr_count); - u64 offset = 0; - size_t vertex_size = desc.use_full_vertex_size ? sizeof(Vertex) : VertexDesc_CalcStride(&desc); - for (u32 i = 0; i < desc.attributes_count; i++) { - opengl_vertex_attr format = format_from_vertex_attr(desc.attributes[i]); - glVertexAttribPointer(i, format.count, format.data_type, GL_FALSE, vertex_size, (void*)offset); - TRACE(" %d %d %d %d %d %s", i, format.count, format.data_type, vertex_size, offset, - desc.attr_names[i]); - glEnableVertexAttribArray(i); // nth index - size_t this_offset = VertexAttribSize(desc.attributes[i]); - // printf("offset total %lld this attr %zu\n", offset, this_offset); - offset += this_offset; - } - glBindBuffer(GL_ARRAY_BUFFER, 0); - - return vao; -} - -static u32 shader_create_separate(const char* vert_shader, const char* frag_shader) { - INFO("Load shaders at %s and %s", vert_shader, frag_shader); - int success; - char info_log[512]; - - u32 vertex = glCreateShader(GL_VERTEX_SHADER); - const char* vertex_shader_src = string_from_file(vert_shader); - if (vertex_shader_src == NULL) { - ERROR("EXIT: couldnt load shader"); - exit(-1); - } - glShaderSource(vertex, 1, &vertex_shader_src, NULL); - glCompileShader(vertex); - glGetShaderiv(vertex, GL_COMPILE_STATUS, &success); - if (!success) { - glGetShaderInfoLog(vertex, 512, NULL, info_log); - printf("%s\n", info_log); - ERROR("EXIT: vertex shader compilation failed"); - exit(-1); - } - - // fragment shader - u32 fragment = glCreateShader(GL_FRAGMENT_SHADER); - const char* fragment_shader_src = string_from_file(frag_shader); - if (fragment_shader_src == NULL) { - ERROR("EXIT: couldnt load shader"); - exit(-1); - } - glShaderSource(fragment, 1, &fragment_shader_src, NULL); - glCompileShader(fragment); - glGetShaderiv(fragment, GL_COMPILE_STATUS, &success); - if (!success) { - glGetShaderInfoLog(fragment, 512, NULL, info_log); - printf("%s\n", info_log); - ERROR("EXIT: fragment shader compilation failed"); - exit(-1); - } - - u32 shader_prog; - shader_prog = glCreateProgram(); - - glAttachShader(shader_prog, vertex); - glAttachShader(shader_prog, fragment); - glLinkProgram(shader_prog); - glDeleteShader(vertex); - glDeleteShader(fragment); - free((char*)vertex_shader_src); - free((char*)fragment_shader_src); - - return shader_prog; -} - -static GLenum opengl_tex_type(GPU_TextureType tex_type) { - switch (tex_type) { - case TEXTURE_TYPE_2D: - return GL_TEXTURE_2D; - case TEXTURE_TYPE_CUBE_MAP: - return GL_TEXTURE_CUBE_MAP; - default: - return GL_TEXTURE_2D; - } -} - -static GLenum opengl_prim_topology(PrimitiveTopology t) { - switch (t) { - case CEL_POINT: - return GL_POINT; - case CEL_LINE: - return GL_LINES; - case CEL_LINE_STRIP: - return GL_LINE_STRIP; - case CEL_TRI: - return GL_TRIANGLES; - case CEL_TRI_STRIP: - return GL_TRIANGLE_STRIP; - case PRIMITIVE_TOPOLOGY_COUNT: - WARN("Invalid PrimitiveTopology value"); - break; - } -} - -#endif diff --git a/archive/src/ral/backends/vulkan/backend_vulkan.c b/archive/src/ral/backends/vulkan/backend_vulkan.c deleted file mode 100644 index e69de29..0000000 diff --git a/archive/src/ral/backends/vulkan/backend_vulkan.h b/archive/src/ral/backends/vulkan/backend_vulkan.h deleted file mode 100644 index f31bed2..0000000 --- a/archive/src/ral/backends/vulkan/backend_vulkan.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#ifdef CEL_REND_BACKEND_VULKAN -#include "defines.h" -#include "maths_types.h" -#include "ral.h" -#include "ral_impl.h" -#include "ral_types.h" - -#include -#include -#include - -// Provide definitions for RAL structs - -struct GPU_Swapchain { - VkSwapchainKHR handle; -}; - -struct GPU_Device { - VkPhysicalDevice physical_device; - VkDevice logical_device; -}; - -struct GPU_PipelineLayout {}; -struct GPU_Pipeline {}; -struct GPU_Renderpass {}; -struct GPU_CmdEncoder {}; -struct GPU_CmdBuffer {}; -struct GPU_Buffer { - VkBuffer handle; - VkDeviceMemory memory; - u64 size; -}; -struct GPU_Texture { - VkImage handle; - VkDeviceMemory memory; - u64 size; - VkImageView view; - VkSampler sampler; - char* debug_label; -}; - -#endif diff --git a/archive/src/ral/backends/vulkan/vulkan_glossary.md b/archive/src/ral/backends/vulkan/vulkan_glossary.md deleted file mode 100644 index 4214f9d..0000000 --- a/archive/src/ral/backends/vulkan/vulkan_glossary.md +++ /dev/null @@ -1,18 +0,0 @@ -# Vulkan Glossary - -*from https://vkguide.dev/docs/introduction/vulkan_execution/* - -- **VkInstance**: The Vulkan context, used to access drivers. -- **VkPhysicalDevice**: A GPU. Used to query physical GPU details, like features, capabilities, memory size, etc. -- **VkDevice**: The “logical” GPU context that you actually execute things on. -- **VkBuffer**: A chunk of GPU visible memory. -- **VkImage**: A texture you can write to and read from. -- **VkPipeline**: Holds the state of the gpu needed to draw. For example: shaders, rasterization options, depth settings. -- **VkRenderPass**: Holds information about the images you are rendering into. All drawing commands have to be done inside a renderpass. Only used in legacy vkguide. -- **VkFrameBuffer**: Holds the target images for a renderpass. Only used in legacy vkguide. -- **VkCommandBuffer**: Encodes GPU commands. All execution that is performed on the GPU itself (not in the driver) has to be encoded in a VkCommandBuffer. -- **VkQueue**: Execution “port” for commands. GPUs will have a set of queues with different properties. Some allow only graphics commands, others only allow memory commands, etc. Command buffers are executed by submitting them into a queue, which will copy the rendering commands onto the GPU for execution. -- **VkDescriptorSet**: Holds the binding information that connects shader inputs to data such as VkBuffer resources and VkImage textures. Think of it as a set of gpu-side pointers that you bind once. -- **VkSwapchainKHR**: Holds the images for the screen. It allows you to render things into a visible window. The KHR suffix shows that it comes from an extension, which in this case is VK_KHR_swapchain. -- **VkSemaphore**: Synchronizes GPU to GPU execution of commands. Used for syncing multiple command buffer submissions one after another. -- **VkFence**: Synchronizes GPU to CPU execution of commands. Used to know if a command buffer has finished being executed on the GPU. diff --git a/archive/src/ral/backends/vulkan/vulkan_helpers.h b/archive/src/ral/backends/vulkan/vulkan_helpers.h deleted file mode 100644 index 23666c6..0000000 --- a/archive/src/ral/backends/vulkan/vulkan_helpers.h +++ /dev/null @@ -1,199 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "darray.h" -#include "defines.h" -#include "log.h" -#include "str.h" - -#define VULKAN_PHYS_DEVICE_MAX_EXTENSION_NAMES 36 - -DECL_TYPED_ARRAY(const char*, cstr) - -static void plat_get_required_extension_names(cstr_darray* extensions) { -#ifdef CEL_PLATFORM_LINUX - cstr_darray_push(extensions, "VK_KHR_xcb_surface"); -#endif -} - -// TODO(omni): port to using internal assert functions -#define VK_CHECK(vulkan_expr) \ - do { \ - VkResult res = vulkan_expr; \ - if (res != VK_SUCCESS) { \ - ERROR_EXIT("Vulkan error: %u (%s:%d)", res, __FILE__, __LINE__); \ - } \ - } while (0) - -// TODO: typedef struct vk_debugger {} vk_debugger; - -typedef struct vulkan_physical_device_requirements { - bool graphics; - bool present; - bool compute; - bool transfer; - str8 device_ext_names[VULKAN_PHYS_DEVICE_MAX_EXTENSION_NAMES]; - size_t device_ext_name_count; - bool sampler_anistropy; - bool discrete_gpu; -} vulkan_physical_device_requirements; - -#define VULKAN_MAX_DEFAULT 32 - -typedef struct vulkan_swapchain_support_info { - VkSurfaceCapabilitiesKHR capabilities; - VkSurfaceFormatKHR formats[VULKAN_MAX_DEFAULT]; - u32 format_count; - VkPresentModeKHR present_modes[VULKAN_MAX_DEFAULT]; - u32 mode_count; -} vulkan_swapchain_support_info; - -VKAPI_ATTR VkBool32 VKAPI_CALL vk_debug_callback( - VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT flags, - const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* user_data); - -static void vulkan_device_query_swapchain_support(VkPhysicalDevice device, VkSurfaceKHR surface, - vulkan_swapchain_support_info* out_support_info) { - // TODO: add VK_CHECK to these calls! - - // Surface capabilities - vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &out_support_info->capabilities); - - // Surface formats - vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &out_support_info->format_count, - 0); // Get number of formats - if (out_support_info->format_count > 0) { - vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &out_support_info->format_count, - out_support_info->formats); - } - - // Present Modes - vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &out_support_info->mode_count, - 0); // Get number of formats - if (out_support_info->mode_count > 0) { - vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &out_support_info->mode_count, - out_support_info->present_modes); - } -} - -static VkSurfaceFormatKHR choose_swapchain_format( - vulkan_swapchain_support_info* swapchain_support) { - assert(swapchain_support->format_count > 0); - // find a format - for (u32 i = 0; i < swapchain_support->format_count; i++) { - VkSurfaceFormatKHR format = swapchain_support->formats[i]; - if (format.format == VK_FORMAT_B8G8R8A8_SRGB && - format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - return format; - } - } - return swapchain_support->formats[0]; -} - -// static bool physical_device_meets_requirements( -// VkPhysicalDevice device, VkSurfaceKHR surface, const VkPhysicalDeviceProperties* properties, -// const VkPhysicalDeviceFeatures* features, -// const vulkan_physical_device_requirements* requirements, -// vulkan_physical_device_queue_family_info* out_queue_info, -// vulkan_swapchain_support_info* out_swapchain_support) { -// // TODO: pass in an arena - -// out_queue_info->graphics_family_index = -1; -// out_queue_info->present_family_index = -1; -// out_queue_info->compute_family_index = -1; -// out_queue_info->transfer_family_index = -1; - -// if (requirements->discrete_gpu) { -// if (properties->deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) { -// TRACE("Device is not a physical GPU. Skipping."); -// return false; -// } -// } - -// u32 queue_family_count = 0; -// vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, 0); -// VkQueueFamilyProperties queue_families[queue_family_count]; -// vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, queue_families); - -// INFO("Graphics | Present | Compute | Transfer | Name"); -// u8 min_transfer_score = 255; -// for (u32 i = 0; i < queue_family_count; i++) { -// u8 current_transfer_score = 0; - -// // Graphics queue -// if (queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { -// out_queue_info->graphics_family_index = i; -// current_transfer_score++; -// } - -// // Compute queue -// if (queue_families[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { -// out_queue_info->compute_family_index = i; -// current_transfer_score++; -// } - -// // Transfer queue -// if (queue_families[i].queueFlags & VK_QUEUE_TRANSFER_BIT) { -// // always take the lowest score transfer index -// if (current_transfer_score <= min_transfer_score) { -// min_transfer_score = current_transfer_score; -// out_queue_info->transfer_family_index = i; -// } -// } - -// // Present Queue -// VkBool32 supports_present = VK_FALSE; -// vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &supports_present); -// if (supports_present) { -// out_queue_info->present_family_index = i; -// } -// } - -// INFO(" %d | %d | %d | %d | %s", -// out_queue_info->graphics_family_index != -1, out_queue_info->present_family_index != -1, -// out_queue_info->compute_family_index != -1, out_queue_info->transfer_family_index != -1, -// properties->deviceName); -// TRACE("Graphics Family queue index: %d", out_queue_info->graphics_family_index); -// TRACE("Present Family queue index: %d", out_queue_info->present_family_index); -// TRACE("Compute Family queue index: %d", out_queue_info->compute_family_index); -// TRACE("Transfer Family queue index: %d", out_queue_info->transfer_family_index); - -// if ((!requirements->graphics || -// (requirements->graphics && out_queue_info->graphics_family_index != -1))) { -// INFO("Physical device meets our requirements! Proceed."); - -// vulkan_device_query_swapchain_support( -// device, surface, out_swapchain_support - -// // TODO: error handling i.e. format count = 0 or present mode = 0 - -// ); -// return true; -// } - -// return false; -// } - -VKAPI_ATTR VkBool32 VKAPI_CALL vk_debug_callback( - VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT flags, - const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* user_data) { - switch (severity) { - default: - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: - ERROR("%s", callback_data->pMessage); - break; - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: - WARN("%s", callback_data->pMessage); - break; - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: - INFO("%s", callback_data->pMessage); - break; - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: - TRACE("%s", callback_data->pMessage); - break; - } - return VK_FALSE; -} \ No newline at end of file diff --git a/archive/src/ral/ral.h b/archive/src/ral/ral.h deleted file mode 100644 index fdbadd3..0000000 --- a/archive/src/ral/ral.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include "ral_common.h" -#include "ral_impl.h" -#include "ral_types.h" \ No newline at end of file diff --git a/archive/src/ral/ral_common.c b/archive/src/ral/ral_common.c deleted file mode 100644 index d921ac4..0000000 --- a/archive/src/ral/ral_common.c +++ /dev/null @@ -1,70 +0,0 @@ -#include "ral_common.h" -#include "ral_impl.h" - -void BackendPools_Init(arena* a, GPU_BackendPools* backend_pools) { - PipelineLayout_pool pipeline_layout_pool = - PipelineLayout_pool_create(a, MAX_PIPELINES, sizeof(GPU_PipelineLayout)); - backend_pools->pipeline_layouts = pipeline_layout_pool; - Pipeline_pool pipeline_pool = Pipeline_pool_create(a, MAX_PIPELINES, sizeof(GPU_Pipeline)); - backend_pools->pipelines = pipeline_pool; - Renderpass_pool rpass_pool = Renderpass_pool_create(a, MAX_RENDERPASSES, sizeof(GPU_Renderpass)); - backend_pools->renderpasses = rpass_pool; -} - -void ResourcePools_Init(arena* a, struct ResourcePools* res_pools) { - Buffer_pool buf_pool = Buffer_pool_create(a, MAX_BUFFERS, sizeof(GPU_Buffer)); - res_pools->buffers = buf_pool; - Texture_pool tex_pool = Texture_pool_create(a, MAX_TEXTURES, sizeof(GPU_Texture)); - res_pools->textures = tex_pool; -} - -VertexDescription static_3d_vertex_description() { - VertexDescription builder = { .debug_label = "Standard static 3d vertex format" }; - VertexDesc_AddAttr(&builder, "inPosition", ATTR_F32x3); - VertexDesc_AddAttr(&builder, "inNormal", ATTR_F32x3); - VertexDesc_AddAttr(&builder, "inTexCoords", ATTR_F32x2); - builder.use_full_vertex_size = true; - return builder; -} - -void VertexDesc_AddAttr(VertexDescription* builder, const char* name, VertexAttribType type) { - u32 i = builder->attributes_count; - - size_t size = VertexAttribSize(type); - builder->attributes[i] = type; - // builder->stride += size; - builder->attr_names[i] = name; - - builder->attributes_count++; -} - -size_t VertexAttribSize(VertexAttribType attr) { - switch (attr) { - case ATTR_F32: - case ATTR_U32: - case ATTR_I32: - return 4; - case ATTR_F32x2: - case ATTR_U32x2: - case ATTR_I32x2: - return 8; - case ATTR_F32x3: - case ATTR_U32x3: - case ATTR_I32x3: - return 12; - case ATTR_F32x4: - case ATTR_U32x4: - case ATTR_I32x4: - return 16; - break; - } -} - -size_t VertexDesc_CalcStride(VertexDescription* desc) { - size_t stride = 0; - for (int i = 0; i < desc->attributes_count; i++) { - size_t size = VertexAttribSize(desc->attributes[i]); - stride += size; - } - return stride; -} diff --git a/archive/src/ral/ral_common.h b/archive/src/ral/ral_common.h deleted file mode 100644 index 5a797e5..0000000 --- a/archive/src/ral/ral_common.h +++ /dev/null @@ -1,61 +0,0 @@ -/** - * @brief Common functions that don't actually depend on the specific backend - */ -#pragma once -#include "buf.h" -#include "defines.h" -#include "mem.h" -#include "ral_types.h" -// #include "ral_impl.h" - -// Concrete implementation -#if defined(CEL_REND_BACKEND_OPENGL) -#include "backend_opengl.h" -#endif - -TYPED_POOL(GPU_Buffer, Buffer); -TYPED_POOL(GPU_Texture, Texture); -TYPED_POOL(GPU_PipelineLayout, PipelineLayout); -TYPED_POOL(GPU_Pipeline, Pipeline); -TYPED_POOL(GPU_Renderpass, Renderpass); - -// --- Handy macros -#define BUFFER_GET(h) (Buffer_pool_get(&context.resource_pools->buffers, h)) -#define TEXTURE_GET(h) (Texture_pool_get(&context.resource_pools->textures, h)) - -// --- Views -typedef struct GPU_BufferView { - BufferHandle buf; - size_t offset; - size_t bytes; -} GPU_BufferView; - -// --- Pools -typedef struct GPU_BackendPools { - Pipeline_pool pipelines; - PipelineLayout_pool pipeline_layouts; - Renderpass_pool renderpasses; -} GPU_BackendPools; -void BackendPools_Init(arena* a, GPU_BackendPools* backend_pools); - -struct ResourcePools { - Buffer_pool buffers; - Texture_pool textures; -}; -typedef struct ResourcePools ResourcePools; -void ResourcePools_Init(arena* a, struct ResourcePools* res_pools); - -PUB GPU_Renderpass* GPU_GetDefaultRenderpass(); // returns a renderpass that draws directly to - // default framebuffer with default depth - -// -- -// window resize callback -void GPU_WindowResizedCallback(u32 x, u32 y); - -// --- Vertex formats -VertexDescription static_3d_vertex_description(); - -void VertexDesc_AddAttr(VertexDescription* builder, const char* name, VertexAttribType type); -size_t VertexDesc_CalcStride(VertexDescription* desc); - -size_t VertexAttribSize(VertexAttribType attr); diff --git a/archive/src/ral/ral_impl.h b/archive/src/ral/ral_impl.h deleted file mode 100644 index 16c9767..0000000 --- a/archive/src/ral/ral_impl.h +++ /dev/null @@ -1,102 +0,0 @@ -/** - * @brief - */ -#pragma once -#include "buf.h" -#include "defines.h" -#include "ral_types.h" - -struct GLFWwindow; -struct ResourcePools; - -// Forward declare structs - these must be defined in the backend implementation -typedef struct GPU_Swapchain GPU_Swapchain; -typedef struct GPU_Device GPU_Device; -typedef struct GPU_PipelineLayout GPU_PipelineLayout; -typedef struct GPU_Pipeline GPU_Pipeline; -typedef struct GPU_Renderpass GPU_Renderpass; -typedef struct GPU_CmdEncoder GPU_CmdEncoder; // Recording -typedef struct GPU_CmdBuffer GPU_CmdBuffer; // Ready for submission -typedef struct GPU_Buffer GPU_Buffer; -typedef struct GPU_Texture GPU_Texture; - -bool GPU_Backend_Init(const char* window_name, struct GLFWwindow* window, - struct ResourcePools* res_pools); -void GPU_Backend_Shutdown(); - -bool GPU_Device_Create(GPU_Device* out_device); -void GPU_Device_Destroy(GPU_Device* device); - -bool GPU_Swapchain_Create(GPU_Swapchain* out_swapchain); -void GPU_Swapchain_Destroy(GPU_Swapchain* swapchain); -void GPU_Swapchain_Resize(i32 new_width, i32 new_height); -u32x2 GPU_Swapchain_GetDimensions(); - -PUB GPU_Renderpass* GPU_Renderpass_Create(GPU_RenderpassDesc description); -PUB void GPU_Renderpass_Destroy(GPU_Renderpass* pass); - -PUB GPU_Pipeline* GPU_GraphicsPipeline_Create(GraphicsPipelineDesc description, - GPU_Renderpass* renderpass); -PUB void GraphicsPipeline_Destroy(GPU_Pipeline* pipeline); - -// --- Command buffer -PUB GPU_CmdEncoder GPU_CmdEncoder_Create(); -PUB void GPU_CmdEncoder_Destroy(GPU_CmdEncoder* encoder); -PUB void GPU_CmdEncoder_Begin(GPU_CmdEncoder* encoder); -PUB void GPU_CmdEncoder_Finish(GPU_CmdEncoder* encoder); -PUB void GPU_CmdEncoder_BeginRender(GPU_CmdEncoder* encoder, GPU_Renderpass* renderpass); -PUB void GPU_CmdEncoder_EndRender(GPU_CmdEncoder* encoder); -PUB GPU_CmdEncoder* GPU_GetDefaultEncoder(); -PUB void GPU_QueueSubmit(GPU_CmdBuffer* cmd_buffer); - -// --- Buffers -PUB BufferHandle GPU_BufferCreate(u64 size, GPU_BufferType buf_type, GPU_BufferFlags flags, - const void* data); -PUB void GPU_BufferDestroy(BufferHandle handle); -PUB void GPU_BufferUpload(BufferHandle buffer, size_t n_bytes, const void* data); - -// --- Textures -PUB TextureHandle GPU_TextureCreate(TextureDesc desc, bool create_view, const void* data); -PUB GPU_Texture* GPU_TextureAlloc(TextureHandle* out_handle); -PUB void GPU_TextureDestroy(TextureHandle handle); -PUB void GPU_TextureUpload(TextureHandle handle, size_t n_bytes, const void* data); - -// --- Data copy commands -PUB void GPU_EncodeCopyBufToBuf(GPU_CmdEncoder* encoder, BufferHandle src, u64 src_offset, - BufferHandle dst, u64 dst_offset, u64 copy_size); - -// PUB void GPU_EncodeCopyBufToTex(GPU_CmdEncoder* encoder, BufferHandle src, TextureHandle dst, -// u32 x_offset, u32 y_offset, u32 width, u32 height, const void* data); -/** @brief Convenience method for writing data directly into a texture. Staging memory is handled - * internally. */ -PUB void GPU_WriteTextureRegion(GPU_CmdEncoder* encoder, TextureHandle dst, u32 x_offset, - u32 y_offset, u32 width, u32 height, const void* data); -PUB void GPU_WriteBuffer(GPU_CmdEncoder* encoder, BufferHandle buf, u64 offset, u64 size, - const void* data); - -// --- Render commands -PUB void GPU_EncodeBindPipeline(GPU_CmdEncoder* encoder, GPU_Pipeline* pipeline); -PUB void GPU_EncodeBindShaderData(GPU_CmdEncoder* encoder, u32 group, ShaderDataLayout layout); -void GPU_EncodeSetDefaults(GPU_CmdEncoder* encoder); -PUB void GPU_EncodeSetVertexBuffer(GPU_CmdEncoder* encoder, BufferHandle buf); -PUB void GPU_EncodeSetIndexBuffer(GPU_CmdEncoder* encoder, BufferHandle buf); - -PUB void GPU_EncodeDraw(GPU_CmdEncoder* encoder, PrimitiveTopology topology, u64 count); -PUB void GPU_EncodeDrawIndexed(GPU_CmdEncoder* encoder, PrimitiveTopology topology, - u64 index_count); -// convenience versions of the above -PUB void GPU_EncodeDrawTris(GPU_CmdEncoder* encoder, u64 count); -PUB void GPU_EncodeDrawIndexedTris(GPU_CmdEncoder* encoder, u64 index_count); -PUB void GPU_EncodeDrawInstanced(GPU_CmdEncoder* encoder, u64 index_count, - u64 instance_count); // TODO: implement instanced rendering - -// --- Frame cycle -PUB bool GPU_Backend_BeginFrame(); -PUB void GPU_Backend_EndFrame(); - -// Concrete implementation -#if defined(CEL_REND_BACKEND_OPENGL) -#include "backend_opengl.h" -#elif defined(CEL_REND_BACKEND_VULKAN) -#include "backend_vulkan.h" -#endif diff --git a/archive/src/ral/ral_types.h b/archive/src/ral/ral_types.h deleted file mode 100644 index fde3bed..0000000 --- a/archive/src/ral/ral_types.h +++ /dev/null @@ -1,168 +0,0 @@ -#pragma once -#include "darray.h" -#include "defines.h" -#include "maths_types.h" -#include "str.h" - -// --- Max size constants -#define MAX_SHADER_DATA_LAYOUTS 8 -#define MAX_SHADER_BINDINGS 8 -#define MAX_BUFFERS 256 -#define MAX_TEXTURES 256 -#define MAX_PIPELINES 128 -#define MAX_RENDERPASSES 128 -#define MAX_VERTEX_ATTRIBUTES 16 - -// --- Handle types -CORE_DEFINE_HANDLE(BufferHandle); -CORE_DEFINE_HANDLE(TextureHandle); -CORE_DEFINE_HANDLE(SamplerHandle); -CORE_DEFINE_HANDLE(ShaderHandle); -CORE_DEFINE_HANDLE(PipelineLayoutHandle); -CORE_DEFINE_HANDLE(PipelineHandle); -CORE_DEFINE_HANDLE(RenderpassHandle); -#define INVALID_TEX_HANDLE ((TextureHandle){ .raw = 9999981 }) - -// --- Buffers -typedef enum GPU_BufferType { - BUFFER_DEFAULT, // on Vulkan this would be a storage buffer? - BUFFER_VERTEX, - BUFFER_INDEX, - BUFFER_UNIFORM, - BUFFER_COUNT -} GPU_BufferType; - -static const char* buffer_type_names[] = { - "RAL Buffer Default", "RAL Buffer Vertex", "RAL Buffer Index", - "RAL Buffer Uniform", "RAL Buffer Count", -}; - -typedef enum GPU_BufferFlag { - BUFFER_FLAG_CPU = 1 << 0, - BUFFER_FLAG_GPU = 1 << 1, - BUFFER_FLAG_STORAGE = 1 << 2, - BUFFER_FLAG_COUNT -} GPU_BufferFlag; -typedef u32 GPU_BufferFlags; - -static const char* texture_type_names[] = { - "RAL Texture 2D", "RAL Texture 3D", "RAL Texture 2D Array", - "RAL Texture Cubemap", "RAL Texture Count", -}; - -typedef enum GPU_TextureFormat { - TEXTURE_FORMAT_8_8_8_8_RGBA_UNORM, - TEXTURE_FORMAT_8_8_8_RGB_UNORM, - TEXTURE_FORMAT_DEPTH_DEFAULT, - TEXTURE_FORMAT_COUNT -} GPU_TextureFormat; - -// --- Vertices - -typedef enum VertexFormat { - VERTEX_STATIC_3D, - VERTEX_SPRITE, - VERTEX_SKINNED, - VERTEX_COLOURED_STATIC_3D, - VERTEX_RAW_POS_COLOUR, - VERTEX_POS_ONLY, - VERTEX_COUNT -} VertexFormat; - -#ifndef TYPED_VERTEX_ARRAY -KITC_DECL_TYPED_ARRAY(Vertex); -KITC_DECL_TYPED_ARRAY(u32) -#define TYPED_VERTEX_ARRAY -#endif - -/// @strip_prefix(ATTR_) -typedef enum VertexAttribType { - ATTR_F32, - ATTR_F32x2, - ATTR_F32x3, - ATTR_F32x4, - ATTR_U32, - ATTR_U32x2, - ATTR_U32x3, - ATTR_U32x4, - ATTR_I32, - ATTR_I32x2, - ATTR_I32x3, - ATTR_I32x4, -} VertexAttribType; - -typedef struct VertexDescription { - const char* debug_label; - const char* attr_names[MAX_VERTEX_ATTRIBUTES]; - VertexAttribType attributes[MAX_VERTEX_ATTRIBUTES]; - u32 attributes_count; - // size_t stride; - bool use_full_vertex_size; -} VertexDescription; - -// --- Shaders -typedef enum PipelineKind { - PIPELINE_GRAPHICS, - PIPELINE_COMPUTE, -} PipelineKind; - -typedef struct ShaderDesc { - const char* debug_name; - Str8 filepath; // Where it came from - Str8 code; // Either GLSL or SPIRV bytecode - bool is_spirv; - bool is_combined_vert_frag; // Contains both vertex and fragment stages -} ShaderDesc; - -typedef ShaderDataLayout (*FN_GetBindingLayout)(void* data); - -/** @brief takes a `ShaderDataLayout` without data, and puts the correct data into each binding */ -typedef void (*FN_BindShaderData)(ShaderDataLayout* layout, const void* data); - -// typedef struct ShaderData { -// FN_GetBindingLayout get_layout; -// void* data; -// } ShaderData; - -typedef enum PrimitiveTopology { -#ifdef TOPOLOGY_SHORT_NAMES - CEL_POINT, - CEL_LINE, - CEL_LINE_STRIP, - CEL_TRI, - CEL_TRI_STRIP, - PRIMITIVE_TOPOLOGY_COUNT -#else - PRIMITIVE_TOPOLOGY_POINT, - PRIMITIVE_TOPOLOGY_LINE, - PRIMITIVE_TOPOLOGY_LINE_STRIP, - PRIMITIVE_TOPOLOGY_TRIANGLE, - PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, - PRIMITIVE_TOPOLOGY_COUNT -#endif -} PrimitiveTopology; - -typedef enum Winding { WINDING_CCW, WINDING_CW } Winding; - -// based on https://registry.khronos.org/OpenGL-Refpages/gl4/html/glDepthFunc.xhtml -typedef enum CompareFunc { - COMPARE_NEVER, - COMPARE_LESS, - COMPARE_EQUAL, - COMPARE_LESS_EQUAL, - COMPARE_GREATER, - COMPARE_NOT_EQUAL, - COMPARE_GREATER_EQUAL, - COMPARE_ALWAYS, - COMPARE_COUNT -} CompareFunc; - -bool GraphicsPipelineDesc_AddShaderDataLayout(GraphicsPipelineDesc* desc, ShaderDataLayout layout); - -typedef struct GPU_RenderpassDesc { - bool default_framebuffer; - bool has_color_target; - TextureHandle color_target; // for now only support one - bool has_depth_stencil; - TextureHandle depth_stencil; -} GPU_RenderpassDesc; diff --git a/archive/src/render/archive/backends/backend_test.c b/archive/src/render/archive/backends/backend_test.c deleted file mode 100644 index 6347e27..0000000 --- a/archive/src/render/archive/backends/backend_test.c +++ /dev/null @@ -1 +0,0 @@ -// #FUTURE \ No newline at end of file diff --git a/archive/src/render/archive/backends/metal/README.md b/archive/src/render/archive/backends/metal/README.md deleted file mode 100644 index f87f5c1..0000000 --- a/archive/src/render/archive/backends/metal/README.md +++ /dev/null @@ -1 +0,0 @@ -# TODO \ No newline at end of file diff --git a/archive/src/render/archive/backends/metal/backend_metal.h b/archive/src/render/archive/backends/metal/backend_metal.h deleted file mode 100644 index 9561bb6..0000000 --- a/archive/src/render/archive/backends/metal/backend_metal.h +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once -// #define CEL_REND_BACKEND_METAL -#if defined(CEL_REND_BACKEND_METAL) - -#include "defines.h" -#include "maths_types.h" -#ifdef __OBJC__ -#import -#import -#import -#import -#else -typedef void* id; -#endif - -typedef struct gpu_swapchain { - u32x2 dimensions; -#ifdef __OBJC__ - CAMetalLayer* swapchain; -#else - void* swapchain; -#endif -} gpu_swapchain; -typedef struct gpu_device { -/** @brief `device` gives us access to our GPU */ -#ifdef __OBJC__ - id id; -#else - void* id; -#endif -} gpu_device; -typedef struct gpu_pipeline_layout { - void* pad; -} gpu_pipeline_layout; -typedef struct gpu_pipeline { -#ifdef __OBJC__ - id pipeline_state; -#else - void* pipeline_state; -#endif -} gpu_pipeline; -typedef struct gpu_renderpass { -#ifdef __OBJC__ - MTLRenderPassDescriptor* rpass_descriptor; -#else - void* rpass_descriptor; -#endif -} gpu_renderpass; -typedef struct gpu_cmd_encoder { -#ifdef __OBJC__ - id cmd_buffer; - id render_encoder; -#else - void* cmd_buffer; - void* render_encoder; -#endif -} gpu_cmd_encoder; -typedef struct gpu_cmd_buffer { - void* pad; -} gpu_cmd_buffer; - -typedef struct gpu_buffer { -#ifdef __OBJC__ - id id; -#else - void* id; -#endif - u64 size; -} gpu_buffer; -typedef struct gpu_texture { - void* pad; -} gpu_texture; - -#endif \ No newline at end of file diff --git a/archive/src/render/archive/backends/metal/backend_metal.m b/archive/src/render/archive/backends/metal/backend_metal.m deleted file mode 100644 index 0e9399e..0000000 --- a/archive/src/render/archive/backends/metal/backend_metal.m +++ /dev/null @@ -1,285 +0,0 @@ -#include -#define CEL_REND_BACKEND_METAL -#if defined(CEL_REND_BACKEND_METAL) -#include -#include "ral_types.h" -#include "colours.h" -#include -#include "camera.h" -#include "defines.h" -#include "file.h" -#include "log.h" -#include "maths_types.h" -#include "ral.h" - -#define GLFW_INCLUDE_NONE -#define GLFW_EXPOSE_NATIVE_COCOA - -#include -#include - -#import -#import -#import -#import -#include "backend_metal.h" - -// --- Handy macros -#define BUFFER_GET(h) (buffer_pool_get(&context.resource_pools->buffers, h)) -#define TEXTURE_GET(h) (texture_pool_get(&context.resource_pools->textures, h)) - -typedef struct metal_context { - GLFWwindow* window; - NSWindow* metal_window; - arena pool_arena; - - gpu_device* device; - gpu_swapchain* swapchain; - id surface; - - id command_queue; - gpu_cmd_encoder main_command_buf; - gpu_backend_pools gpu_pools; - struct resource_pools* resource_pools; -} metal_context; - -static metal_context context; - -struct GLFWwindow; - -bool gpu_backend_init(const char *window_name, struct GLFWwindow *window) { - INFO("loading Metal backend"); - - memset(&context, 0, sizeof(metal_context)); - context.window = window; - - size_t pool_buffer_size = 1024 * 1024; - context.pool_arena = arena_create(malloc(pool_buffer_size), pool_buffer_size); - - backend_pools_init(&context.pool_arena, &context.gpu_pools); - context.resource_pools = malloc(sizeof(struct resource_pools)); - resource_pools_init(&context.pool_arena, context.resource_pools); - - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - - glfwMakeContextCurrent(window); - // FIXME: glfwSetFramebufferSizeCallback(ren->window, framebuffer_size_callback); - - // get a NSWindow pointer from GLFWwindow - NSWindow *nswindow = glfwGetCocoaWindow(window); - context.metal_window = nswindow; - - // const id queue = [gpu newCommandQueue]; - // CAMetalLayer *swapchain = [CAMetalLayer layer]; - // swapchain.device = gpu; - // swapchain.opaque = YES; - - // // set swapchain for the window - // nswindow.contentView.layer = swapchain; - // nswindow.contentView.wantsLayer = YES; - - // MTLClearColor color = MTLClearColorMake(0.7, 0.1, 0.2, 1.0); - - // // set all our state properties - // state->device = gpu; - // state->cmd_queue = queue; - // state->swapchain = swapchain; - // state->clear_color = color; - - // NSError *err = 0x0; // TEMPORARY - - // WARN("About to try loading metallib"); - // id defaultLibrary = [state->device newLibraryWithFile: @"build/gfx.metallib" error:&err]; - // CASSERT(defaultLibrary); - // state->default_lib = defaultLibrary; - // if (!state->default_lib) { - // NSLog(@"Failed to load library"); - // exit(0); - // } - - // create_render_pipeline(state); - - return true; -} - -void gpu_backend_shutdown() {} - -bool gpu_device_create(gpu_device* out_device) { - TRACE("GPU Device creation"); - const id gpu = MTLCreateSystemDefaultDevice(); - out_device->id = gpu; - context.device = out_device; - - const id queue = [gpu newCommandQueue]; - context.command_queue = queue; - - return true; -} -void gpu_device_destroy() {} - -// --- Render Pipeline -gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc description) { - TRACE("GPU Graphics Pipeline creation"); - // Allocate - // gpu_pipeline_layout* layout = - // pipeline_layout_pool_alloc(&context.gpu_pools.pipeline_layouts, NULL); - gpu_pipeline* pipeline = pipeline_pool_alloc(&context.gpu_pools.pipelines, NULL); - - WARN("About to try loading metallib"); - assert(description.vs.is_combined_vert_frag); - // Ignore fragment shader data, as vert shader data contains both - NSError *err = 0x0; // TEMPORARY - NSString *myNSString = [NSString stringWithUTF8String:(char*)description.vs.filepath.buf]; - id default_library = [context.device->id newLibraryWithFile:myNSString error:&err]; - assert(default_library); - - // setup vertex and fragment shaders - id ren_vert = [default_library newFunctionWithName:@"basic_vertex"]; - assert(ren_vert); - id ren_frag = [default_library newFunctionWithName:@"basic_fragment"]; - assert(ren_frag); - - // create pipeline descriptor - @autoreleasepool { - NSError *err = 0x0; - MTLRenderPipelineDescriptor *pld = [[MTLRenderPipelineDescriptor alloc] init]; - NSString *pipeline_name = [NSString stringWithUTF8String: description.debug_name]; - pld.label = pipeline_name; - pld.vertexFunction = ren_vert; - pld.fragmentFunction = ren_frag; - pld.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm; - pld.colorAttachments[0].blendingEnabled = YES; - - MTLDepthStencilDescriptor *depthStencilDescriptor = [MTLDepthStencilDescriptor new]; - depthStencilDescriptor.depthCompareFunction = MTLCompareFunctionLess; - depthStencilDescriptor.depthWriteEnabled = YES; - pld.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8; - - id depth_descriptor = [context.device->id newDepthStencilStateWithDescriptor:depthStencilDescriptor]; - // FIXME: state->depth_state = depth_descriptor; - - id pipeline_state = [context.device->id newRenderPipelineStateWithDescriptor:pld error:&err]; - TRACE("created renderpipelinestate"); - pipeline->pipeline_state = pipeline_state; - - } - - return pipeline; -} -void gpu_pipeline_destroy(gpu_pipeline* pipeline) {} - -// --- Renderpass -gpu_renderpass* gpu_renderpass_create(const gpu_renderpass_desc* description) { - gpu_renderpass* renderpass = renderpass_pool_alloc(&context.gpu_pools.renderpasses, NULL); - - // TODO: Configure based on description - // set up render pass - context.surface = [context.swapchain->swapchain nextDrawable]; - MTLRenderPassDescriptor *renderPassDescriptor = [[MTLRenderPassDescriptor alloc] init]; - MTLRenderPassColorAttachmentDescriptor *cd = renderPassDescriptor.colorAttachments[0]; - [cd setTexture:context.surface.texture]; - [cd setLoadAction:MTLLoadActionClear]; - MTLClearColor clearColor = MTLClearColorMake(0.1, 0.1, 0.0, 1.0); - [cd setClearColor:clearColor]; - [cd setStoreAction:MTLStoreActionStore]; - - renderpass->rpass_descriptor = renderPassDescriptor; - - return renderpass; -} - -void gpu_renderpass_destroy(gpu_renderpass* pass) {} - -// --- Swapchain -bool gpu_swapchain_create(gpu_swapchain* out_swapchain) { - TRACE("GPU Swapchain creation"); - CAMetalLayer *swapchain = [CAMetalLayer layer]; - swapchain.device = context.device->id; - swapchain.opaque = YES; - out_swapchain->swapchain = swapchain; - - // set swapchain for the window - context.metal_window.contentView.layer = swapchain; - context.metal_window.contentView.wantsLayer = YES; - - context.swapchain = out_swapchain; - return true; -} -void gpu_swapchain_destroy(gpu_swapchain* swapchain) {} - -// --- Command buffer -gpu_cmd_encoder gpu_cmd_encoder_create() { - id cmd_buffer = [context.command_queue commandBuffer]; - - return (gpu_cmd_encoder) { - .cmd_buffer = cmd_buffer - }; -} -void gpu_cmd_encoder_destroy(gpu_cmd_encoder* encoder) {} -void gpu_cmd_encoder_begin(gpu_cmd_encoder encoder) { /* no-op */ } -void gpu_cmd_encoder_begin_render(gpu_cmd_encoder* encoder, gpu_renderpass* renderpass) { - DEBUG("Create Render Command Encoder"); - id render_encoder = [encoder->cmd_buffer renderCommandEncoderWithDescriptor:renderpass->rpass_descriptor]; - encoder->render_encoder = render_encoder; - // [encoder setDepthStencilState:state->depth_state]; -} -void gpu_cmd_encoder_end_render(gpu_cmd_encoder* encoder) {} -void gpu_cmd_encoder_begin_compute() {} -gpu_cmd_encoder* gpu_get_default_cmd_encoder() { - return &context.main_command_buf; -} - -/** @brief Finish recording and return a command buffer that can be submitted to a queue */ -gpu_cmd_buffer gpu_cmd_encoder_finish(gpu_cmd_encoder* encoder) {} - -void gpu_queue_submit(gpu_cmd_buffer* buffer) {} - -void encode_buffer_copy(gpu_cmd_encoder* encoder, buffer_handle src, u64 src_offset, - buffer_handle dst, u64 dst_offset, u64 copy_size); -void buffer_upload_bytes(buffer_handle gpu_buf, bytebuffer cpu_buf, u64 offset, u64 size); - -void copy_buffer_to_buffer_oneshot(buffer_handle src, u64 src_offset, buffer_handle dst, - u64 dst_offset, u64 copy_size); -void copy_buffer_to_image_oneshot(buffer_handle src, texture_handle dst); - -void encode_bind_pipeline(gpu_cmd_encoder* encoder, pipeline_kind kind, gpu_pipeline* pipeline) {} -void encode_bind_shader_data(gpu_cmd_encoder* encoder, u32 group, shader_data* data) {} -void encode_set_default_settings(gpu_cmd_encoder* encoder) { - [encoder->render_encoder setCullMode:MTLCullModeBack]; -} -void encode_set_vertex_buffer(gpu_cmd_encoder* encoder, buffer_handle buf) { - gpu_buffer* vertex_buf = BUFFER_GET(buf); - [encoder->render_encoder setVertexBuffer:vertex_buf->id offset:0 atIndex:0]; -} -void encode_set_index_buffer(gpu_cmd_encoder* encoder, buffer_handle buf) {} -void encode_set_bind_group() {} -void encode_draw(gpu_cmd_encoder* encoder) {} -void encode_draw_indexed(gpu_cmd_encoder* encoder, u64 index_count) {} -void encode_clear_buffer(gpu_cmd_encoder* encoder, buffer_handle buf) {} - -buffer_handle gpu_buffer_create(u64 size, gpu_buffer_type buf_type, gpu_buffer_flags flags, - const void* data) { - buffer_handle handle; - gpu_buffer* buffer = buffer_pool_alloc(&context.resource_pools->buffers, &handle); - buffer->size = size; - - id mtl_vert_buf = [context.device->id newBufferWithBytes:data - length: size - options:MTLResourceStorageModeShared]; - return handle; -} -void gpu_buffer_destroy(buffer_handle buffer) {} -void gpu_buffer_upload(const void* data) {} - -texture_handle gpu_texture_create(texture_desc desc, bool create_view, const void* data) {} -void gpu_texture_destroy(texture_handle) {} -void gpu_texture_upload(texture_handle texture, const void* data) {} - -bool gpu_backend_begin_frame() { - context.main_command_buf.cmd_buffer = [context.command_queue commandBuffer]; - return true; - } -void gpu_backend_end_frame() {} -void gpu_temp_draw(size_t n_verts) {} - -#endif \ No newline at end of file diff --git a/archive/src/render/archive/backends/opengl/backend_opengl.c b/archive/src/render/archive/backends/opengl/backend_opengl.c deleted file mode 100644 index 43105e2..0000000 --- a/archive/src/render/archive/backends/opengl/backend_opengl.c +++ /dev/null @@ -1,521 +0,0 @@ -#include -#include -#include -#include "colours.h" -#include "maths.h" -#include "opengl_helpers.h" -#include "ral_types.h" -#define CEL_REND_BACKEND_OPENGL -#if defined(CEL_REND_BACKEND_OPENGL) -#include -#include - -#include "backend_opengl.h" -#include "defines.h" -#include "file.h" -#include "log.h" -#include "maths_types.h" -#include "ral.h" - -#include -#include - -typedef struct opengl_context { - GLFWwindow* window; - arena pool_arena; - gpu_cmd_encoder command_buffer; - gpu_backend_pools gpu_pools; - struct resource_pools* resource_pools; -} opengl_context; - -static opengl_context context; - -struct GLFWwindow; - -bool gpu_backend_init(const char* window_name, struct GLFWwindow* window) { - INFO("loading OpenGL backend"); - - memset(&context, 0, sizeof(opengl_context)); - context.window = window; - - size_t pool_buffer_size = 1024 * 1024; - context.pool_arena = arena_create(malloc(pool_buffer_size), pool_buffer_size); - - backend_pools_init(&context.pool_arena, &context.gpu_pools); - context.resource_pools = malloc(sizeof(struct resource_pools)); - resource_pools_init(&context.pool_arena, context.resource_pools); - - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); - - // glad: load all opengl function pointers - if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { - ERROR("Failed to initialise GLAD \n"); - return false; - } - - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); - - return true; -} - -// --- Render Pipeline -gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc description) { - gpu_pipeline* pipeline = pipeline_pool_alloc(&context.gpu_pools.pipelines, NULL); - - // Create shader program - u32 shader_id = shader_create_separate(description.vs.filepath.buf, description.fs.filepath.buf); - pipeline->shader_id = shader_id; - - // Vertex format - pipeline->vertex_desc = description.vertex_desc; - - // Allocate uniform buffers if needed - u32 ubo_count = 0; - // printf("data layouts %d\n", description.data_layouts_count); - for (u32 layout_i = 0; layout_i < description.data_layouts_count; layout_i++) { - shader_data_layout sdl = description.data_layouts[layout_i].shader_data_get_layout(NULL); - TRACE("Got shader data layout %d's bindings! . found %d", layout_i, sdl.bindings_count); - - for (u32 binding_j = 0; binding_j < sdl.bindings_count; binding_j++) { - u32 binding_id = binding_j; - assert(binding_id < MAX_PIPELINE_UNIFORM_BUFFERS); - shader_binding binding = sdl.bindings[binding_j]; - if (binding.type == SHADER_BINDING_BYTES) { - static u32 s_binding_point = 0; - buffer_handle ubo_handle = - gpu_buffer_create(binding.data.bytes.size, CEL_BUFFER_UNIFORM, CEL_BUFFER_FLAG_GPU, - NULL); // no data right now - pipeline->uniform_bindings[ubo_count++] = ubo_handle; - gpu_buffer* ubo_buf = BUFFER_GET(ubo_handle); - - i32 blockIndex = glGetUniformBlockIndex(pipeline->shader_id, binding.label); - printf("Block index for %s: %d", binding.label, blockIndex); - if (blockIndex < 0) { - WARN("Couldn't retrieve block index for uniform block '%s'", binding.label); - } else { - // DEBUG("Retrived block index %d for %s", blockIndex, binding.label); - } - u32 blocksize; - glGetActiveUniformBlockiv(pipeline->shader_id, blockIndex, GL_UNIFORM_BLOCK_DATA_SIZE, - &blocksize); - printf("\t with size %d bytes\n", blocksize); - - glBindBufferBase(GL_UNIFORM_BUFFER, s_binding_point, ubo_buf->id.ubo); - if (blockIndex != GL_INVALID_INDEX) { - glUniformBlockBinding(pipeline->shader_id, blockIndex, s_binding_point); - } - ubo_buf->ubo_binding_point = s_binding_point++; - ubo_buf->name = binding.label; - assert(s_binding_point < GL_MAX_UNIFORM_BUFFER_BINDINGS); - } - } - } - pipeline->uniform_count = ubo_count; - - pipeline->renderpass = description.renderpass; - pipeline->wireframe = description.wireframe; - - return pipeline; -} -void gpu_pipeline_destroy(gpu_pipeline* pipeline) {} - -// --- Renderpass -gpu_renderpass* gpu_renderpass_create(const gpu_renderpass_desc* description) { - gpu_renderpass* renderpass = renderpass_pool_alloc(&context.gpu_pools.renderpasses, NULL); - memcpy(&renderpass->description, description, sizeof(gpu_renderpass_desc)); - bool default_framebuffer = description->default_framebuffer; - - if (!default_framebuffer) { - GLuint gl_fbo_id; - glGenFramebuffers(1, &gl_fbo_id); - renderpass->fbo = gl_fbo_id; - } else { - renderpass->fbo = OPENGL_DEFAULT_FRAMEBUFFER; - assert(!description->has_color_target); - assert(!description->has_depth_stencil); - } - glBindFramebuffer(GL_FRAMEBUFFER, renderpass->fbo); - - if (description->has_color_target && !default_framebuffer) { - gpu_texture* colour_attachment = TEXTURE_GET(description->color_target); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - colour_attachment->id, 0); - } - if (description->has_depth_stencil && !default_framebuffer) { - gpu_texture* depth_attachment = TEXTURE_GET(description->depth_stencil); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_attachment->id, - 0); - } - - if (description->has_depth_stencil && !description->has_color_target) { - glDrawBuffer(GL_NONE); - glReadBuffer(GL_NONE); - } - - glBindFramebuffer(GL_FRAMEBUFFER, 0); // reset to default framebuffer - - return renderpass; -} -void gpu_renderpass_destroy(gpu_renderpass* pass) { glDeleteFramebuffers(1, &pass->fbo); } - -// --- Command buffer -gpu_cmd_encoder gpu_cmd_encoder_create() { - gpu_cmd_encoder encoder = { 0 }; - return encoder; -} -void gpu_cmd_encoder_destroy(gpu_cmd_encoder* encoder) {} -void gpu_cmd_encoder_begin(gpu_cmd_encoder encoder) {} -void gpu_cmd_encoder_begin_render(gpu_cmd_encoder* encoder, gpu_renderpass* renderpass) { - glBindFramebuffer(GL_FRAMEBUFFER, renderpass->fbo); - rgba clear_colour = STONE_800; - glClearColor(clear_colour.r, clear_colour.g, clear_colour.b, 1.0f); - if (renderpass->description.has_depth_stencil) { - glClear(GL_DEPTH_BUFFER_BIT); - } else { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } -} -void gpu_cmd_encoder_end_render(gpu_cmd_encoder* encoder) { glBindFramebuffer(GL_FRAMEBUFFER, 0); } -void gpu_cmd_encoder_begin_compute() {} -gpu_cmd_encoder* gpu_get_default_cmd_encoder() { return &context.command_buffer; } - -/** @brief Finish recording and return a command buffer that can be submitted to a queue */ -gpu_cmd_buffer gpu_cmd_encoder_finish(gpu_cmd_encoder* encoder) {} - -void gpu_queue_submit(gpu_cmd_buffer* buffer) {} - -// --- Data copy commands -/** @brief Copy data from one buffer to another */ -void encode_buffer_copy(gpu_cmd_encoder* encoder, buffer_handle src, u64 src_offset, - buffer_handle dst, u64 dst_offset, u64 copy_size) {} -/** @brief Upload CPU-side data as array of bytes to a GPU buffer */ -void buffer_upload_bytes(buffer_handle gpu_buf, bytebuffer cpu_buf, u64 offset, u64 size) { - // TODO: finish implementing this - gpu_buffer* buf = BUFFER_GET(gpu_buf); -} - -/** @brief Copy data from buffer to buffer using a one time submit command buffer and a wait */ -void copy_buffer_to_buffer_oneshot(buffer_handle src, u64 src_offset, buffer_handle dst, - u64 dst_offset, u64 copy_size) {} -/** @brief Copy data from buffer to an image using a one time submit command buffer */ -void copy_buffer_to_image_oneshot(buffer_handle src, texture_handle dst) {} - -// --- Render commands -void encode_bind_pipeline(gpu_cmd_encoder* encoder, pipeline_kind kind, gpu_pipeline* pipeline) { - encoder->pipeline = pipeline; - - if (pipeline->wireframe) { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - } else { - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } - - // In OpenGL binding a pipeline is more or less equivalent to just setting the shader - glUseProgram(pipeline->shader_id); -} -void encode_bind_shader_data(gpu_cmd_encoder* encoder, u32 group, shader_data* data) { - shader_data_layout sdl = data->shader_data_get_layout(data->data); - // printf("Binding %s shader data\n", sdl.name); - - for (u32 i = 0; i < sdl.bindings_count; i++) { - shader_binding binding = sdl.bindings[i]; - /* print_shader_binding(binding); */ - - if (binding.type == SHADER_BINDING_BYTES) { - buffer_handle b; - gpu_buffer* ubo_buf; - bool found = false; - for (u32 i = 0; i < encoder->pipeline->uniform_count; i++) { - b = encoder->pipeline->uniform_bindings[i]; - ubo_buf = BUFFER_GET(b); - assert(ubo_buf->name != NULL); - if (strcmp(ubo_buf->name, binding.label) == 0) { - found = true; - break; - } - } - if (!found) { - ERROR("Couldnt find uniform buffer object!!"); - } - - i32 blockIndex = glGetUniformBlockIndex(encoder->pipeline->shader_id, binding.label); - if (blockIndex < 0) { - WARN("Couldn't retrieve block index for uniform block '%s'", binding.label); - } else { - // DEBUG("Retrived block index %d for %s", blockIndex, binding.label); - } - - glBindBuffer(GL_UNIFORM_BUFFER, ubo_buf->id.ubo); - glBufferSubData(GL_UNIFORM_BUFFER, 0, ubo_buf->size, binding.data.bytes.data); - - } else if (binding.type == SHADER_BINDING_TEXTURE) { - gpu_texture* tex = TEXTURE_GET(binding.data.texture.handle); - GLint tex_slot = glGetUniformLocation(encoder->pipeline->shader_id, binding.label); - // printf("%d slot \n", tex_slot); - if (tex_slot == GL_INVALID_VALUE || tex_slot < 0) { - WARN("Invalid binding label for texture %s - couldn't fetch texture slot uniform", - binding.label); - } - glUniform1i(tex_slot, i); - glActiveTexture(GL_TEXTURE0 + i); - glBindTexture(GL_TEXTURE_2D, tex->id); - } - } -} -void encode_set_default_settings(gpu_cmd_encoder* encoder) {} -void encode_set_vertex_buffer(gpu_cmd_encoder* encoder, buffer_handle buf) { - gpu_buffer* buffer = BUFFER_GET(buf); - if (buffer->vao == 0) { // if no VAO for this vertex buffer, create it - INFO("Setting up VAO"); - buffer->vao = opengl_bindcreate_vao(buffer, encoder->pipeline->vertex_desc); - } - glBindVertexArray(buffer->vao); -} -void encode_set_index_buffer(gpu_cmd_encoder* encoder, buffer_handle buf) { - gpu_buffer* buffer = BUFFER_GET(buf); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer->id.ibo); -} -void encode_draw(gpu_cmd_encoder* encoder, u64 count) { glDrawArrays(GL_TRIANGLES, 0, count); } -void encode_draw_indexed(gpu_cmd_encoder* encoder, u64 index_count) { - /* printf("Draw %ld indices\n", index_count); */ - glDrawElements(GL_TRIANGLES, index_count, GL_UNSIGNED_INT, 0); -} -void encode_clear_buffer(gpu_cmd_encoder* encoder, buffer_handle buf) {} - -// --- Buffers -buffer_handle gpu_buffer_create(u64 size, gpu_buffer_type buf_type, gpu_buffer_flags flags, - const void* data) { - // "allocating" the cpu-side buffer struct - buffer_handle handle; - gpu_buffer* buffer = buffer_pool_alloc(&context.resource_pools->buffers, &handle); - buffer->size = size; - buffer->vao = 0; // When we create a new buffer, there will be no VAO. - - // Opengl buffer - GLuint gl_buffer_id; - glGenBuffers(1, &gl_buffer_id); - - GLenum gl_buf_type; - GLenum gl_buf_usage = GL_STATIC_DRAW; - - switch (buf_type) { - case CEL_BUFFER_UNIFORM: - DEBUG("Creating Uniform buffer"); - gl_buf_type = GL_UNIFORM_BUFFER; - /* gl_buf_usage = GL_DYNAMIC_DRAW; */ - buffer->id.ubo = gl_buffer_id; - break; - case CEL_BUFFER_DEFAULT: - case CEL_BUFFER_VERTEX: - DEBUG("Creating Vertex buffer"); - gl_buf_type = GL_ARRAY_BUFFER; - buffer->id.vbo = gl_buffer_id; - break; - case CEL_BUFFER_INDEX: - DEBUG("Creating Index buffer"); - gl_buf_type = GL_ELEMENT_ARRAY_BUFFER; - buffer->id.ibo = gl_buffer_id; - break; - default: - WARN("Unimplemented gpu_buffer_type provided %s", buffer_type_names[buf_type]); - break; - } - // bind buffer - glBindBuffer(gl_buf_type, gl_buffer_id); - - if (data) { - TRACE("Upload data (%d bytes) as part of buffer creation", size); - glBufferData(gl_buf_type, buffer->size, data, gl_buf_usage); - } else { - TRACE("Allocating but not uploading (%d bytes)", size); - glBufferData(gl_buf_type, buffer->size, NULL, gl_buf_usage); - } - - glBindBuffer(gl_buf_type, 0); - - return handle; -} - -texture_handle gpu_texture_create(texture_desc desc, bool create_view, const void* data) { - // "allocating" the cpu-side struct - texture_handle handle; - gpu_texture* texture = texture_pool_alloc(&context.resource_pools->textures, &handle); - DEBUG("Allocated texture with handle %d", handle.raw); - - GLuint gl_texture_id; - glGenTextures(1, &gl_texture_id); - texture->id = gl_texture_id; - - glBindTexture(GL_TEXTURE_2D, gl_texture_id); - - GLint internal_format = - desc.format == CEL_TEXTURE_FORMAT_DEPTH_DEFAULT ? GL_DEPTH_COMPONENT : GL_RGB; - GLenum format = desc.format == CEL_TEXTURE_FORMAT_DEPTH_DEFAULT ? GL_DEPTH_COMPONENT : GL_RGBA; - GLenum data_type = desc.format == CEL_TEXTURE_FORMAT_DEPTH_DEFAULT ? GL_FLOAT : GL_UNSIGNED_BYTE; - - if (desc.format == CEL_TEXTURE_FORMAT_DEPTH_DEFAULT) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - } else { - // set the texture wrapping parameters - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, - GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - // set texture filtering parameters - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } - - if (data) { - glTexImage2D(GL_TEXTURE_2D, 0, internal_format, desc.extents.x, desc.extents.y, 0, format, - data_type, data); - glGenerateMipmap(GL_TEXTURE_2D); - } else { - WARN("No image data provided"); - glTexImage2D(GL_TEXTURE_2D, 0, internal_format, desc.extents.x, desc.extents.y, 0, format, - data_type, NULL); - } - - glBindTexture(GL_TEXTURE_2D, 0); - - return handle; -} - -void gpu_texture_destroy(texture_handle) {} -void gpu_texture_upload(texture_handle texture, const void* data) {} - -// --- Vertex formats -bytebuffer vertices_as_bytebuffer(arena* a, vertex_format format, vertex_darray* vertices) {} - -// --- TEMP -bool gpu_backend_begin_frame() { - glClearColor(0.1f, 0.1f, 0.1f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - return true; -} -void gpu_backend_end_frame() { - // TODO: Reset all bindings - glfwSwapBuffers(context.window); -} -void gpu_temp_draw(size_t n_verts) {} - -u32 shader_create_separate(const char* vert_shader, const char* frag_shader) { - INFO("Load shaders at %s and %s", vert_shader, frag_shader); - int success; - char info_log[512]; - - u32 vertex = glCreateShader(GL_VERTEX_SHADER); - const char* vertex_shader_src = string_from_file(vert_shader); - if (vertex_shader_src == NULL) { - ERROR("EXIT: couldnt load shader"); - exit(-1); - } - glShaderSource(vertex, 1, &vertex_shader_src, NULL); - glCompileShader(vertex); - glGetShaderiv(vertex, GL_COMPILE_STATUS, &success); - if (!success) { - glGetShaderInfoLog(vertex, 512, NULL, info_log); - printf("%s\n", info_log); - ERROR("EXIT: vertex shader compilation failed"); - exit(-1); - } - - // fragment shader - u32 fragment = glCreateShader(GL_FRAGMENT_SHADER); - const char* fragment_shader_src = string_from_file(frag_shader); - if (fragment_shader_src == NULL) { - ERROR("EXIT: couldnt load shader"); - exit(-1); - } - glShaderSource(fragment, 1, &fragment_shader_src, NULL); - glCompileShader(fragment); - glGetShaderiv(fragment, GL_COMPILE_STATUS, &success); - if (!success) { - glGetShaderInfoLog(fragment, 512, NULL, info_log); - printf("%s\n", info_log); - ERROR("EXIT: fragment shader compilation failed"); - exit(-1); - } - - u32 shader_prog; - shader_prog = glCreateProgram(); - - glAttachShader(shader_prog, vertex); - glAttachShader(shader_prog, fragment); - glLinkProgram(shader_prog); - glDeleteShader(vertex); - glDeleteShader(fragment); - free((char*)vertex_shader_src); - free((char*)fragment_shader_src); - - return shader_prog; -} - -inline void uniform_vec3f(u32 program_id, const char* uniform_name, vec3* value) { - glUniform3fv(glGetUniformLocation(program_id, uniform_name), 1, &value->x); -} -inline void uniform_f32(u32 program_id, const char* uniform_name, f32 value) { - glUniform1f(glGetUniformLocation(program_id, uniform_name), value); -} -inline void uniform_i32(u32 program_id, const char* uniform_name, i32 value) { - glUniform1i(glGetUniformLocation(program_id, uniform_name), value); -} -inline void uniform_mat4f(u32 program_id, const char* uniform_name, mat4* value) { - glUniformMatrix4fv(glGetUniformLocation(program_id, uniform_name), 1, GL_FALSE, value->data); -} - -// void clear_screen(vec3 colour) { -// glClearColor(colour.x, colour.y, colour.z, 1.0f); -// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -// } - -// void texture_data_upload(texture *tex) { -// printf("Texture name %s\n", tex->name); -// TRACE("Upload texture data"); -// u32 texture_id; -// glGenTextures(1, &texture_id); -// glBindTexture(GL_TEXTURE_2D, texture_id); -// tex->texture_id = texture_id; - -// // set the texture wrapping parameters -// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, -// GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method) -// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); -// // set texture filtering parameters -// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); -// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - -// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex->width, tex->height, 0, tex->channel_type, -// GL_UNSIGNED_BYTE, tex->image_data); -// glGenerateMipmap(GL_TEXTURE_2D); -// DEBUG("Freeing texture image data after uploading to GPU"); -// // stbi_image_free(tex->image_data); // data is on gpu now so we dont need it around -// } - -// void bind_texture(shader s, texture *tex, u32 slot) { -// // printf("bind texture slot %d with texture id %d \n", slot, tex->texture_id); -// glActiveTexture(GL_TEXTURE0 + slot); -// glBindTexture(GL_TEXTURE_2D, tex->texture_id); -// } - -// void bind_mesh_vertex_buffer(void *_backend, mesh *mesh) { glBindVertexArray(mesh->vao); } - -// static inline GLenum to_gl_prim_topology(enum cel_primitive_topology primitive) { -// switch (primitive) { -// case CEL_PRIMITIVE_TOPOLOGY_TRIANGLE: -// return GL_TRIANGLES; -// case CEL_PRIMITIVE_TOPOLOGY_POINT: -// case CEL_PRIMITIVE_TOPOLOGY_LINE: -// case CEL_PRIMITIVE_TOPOLOGY_LINE_STRIP: -// case CEL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: -// case CEL_PRIMITIVE_TOPOLOGY_COUNT: -// break; -// } -// } -#endif diff --git a/archive/src/render/archive/backends/opengl/backend_opengl.h b/archive/src/render/archive/backends/opengl/backend_opengl.h deleted file mode 100644 index 14b44af..0000000 --- a/archive/src/render/archive/backends/opengl/backend_opengl.h +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once - -#ifdef CEL_REND_BACKEND_OPENGL - -#include "defines.h" -#include "maths_types.h" -#include "ral.h" -#include "ral_types.h" - -#define MAX_PIPELINE_UNIFORM_BUFFERS 32 - -#define OPENGL_DEFAULT_FRAMEBUFFER 0 - -typedef struct gpu_swapchain { - u32x2 dimensions; -} gpu_swapchain; -typedef struct gpu_device { -} gpu_device; -typedef struct gpu_pipeline_layout { - void* pad -} gpu_pipeline_layout; -typedef struct gpu_pipeline { - u32 shader_id; - gpu_renderpass* renderpass; - vertex_description vertex_desc; - buffer_handle uniform_bindings[MAX_PIPELINE_UNIFORM_BUFFERS]; - u32 uniform_count; - bool wireframe; -} gpu_pipeline; -typedef struct gpu_renderpass { - u32 fbo; - gpu_renderpass_desc description; -} gpu_renderpass; -typedef struct gpu_cmd_encoder { - gpu_pipeline* pipeline; -} gpu_cmd_encoder; // Recording -typedef struct gpu_cmd_buffer { - void* pad; -} gpu_cmd_buffer; // Ready for submission - -typedef struct gpu_buffer { - union { - u32 vbo; - u32 ibo; - u32 ubo; - } id; - union { - u32 vao; - u32 ubo_binding_point - }; // Optional - char* name; - u64 size; -} gpu_buffer; -typedef struct gpu_texture { - u32 id; - void* pad; -} gpu_texture; - -typedef struct opengl_support { -} opengl_support; - -u32 shader_create_separate(const char* vert_shader, const char* frag_shader); - -void uniform_vec3f(u32 program_id, const char* uniform_name, vec3* value); -void uniform_f32(u32 program_id, const char* uniform_name, f32 value); -void uniform_i32(u32 program_id, const char* uniform_name, i32 value); -void uniform_mat4f(u32 program_id, const char* uniform_name, mat4* value); -#endif diff --git a/archive/src/render/archive/backends/vulkan/README.md b/archive/src/render/archive/backends/vulkan/README.md deleted file mode 100644 index 220ed64..0000000 --- a/archive/src/render/archive/backends/vulkan/README.md +++ /dev/null @@ -1 +0,0 @@ -# Vulkan Backend Overview \ No newline at end of file diff --git a/archive/src/render/archive/backends/vulkan/backend_vulkan.c b/archive/src/render/archive/backends/vulkan/backend_vulkan.c deleted file mode 100644 index 8801230..0000000 --- a/archive/src/render/archive/backends/vulkan/backend_vulkan.c +++ /dev/null @@ -1,1705 +0,0 @@ -#include "defines.h" -#if defined(CEL_REND_BACKEND_VULKAN) - -#define GLFW_INCLUDE_VULKAN -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "backend_vulkan.h" -#include "buf.h" -#include "darray.h" -#include "maths_types.h" -#include "mem.h" -#include "ral_types.h" -#include "str.h" -#include "vulkan_helpers.h" - -#include "file.h" -#include "log.h" -#include "ral.h" -#include "utils.h" - -// TEMP -#define SCREEN_WIDTH 1000 -#define SCREEN_HEIGHT 1000 -#define VULKAN_QUEUES_COUNT 2 -#define MAX_DESCRIPTOR_SETS 10 - -const char* queue_names[VULKAN_QUEUES_COUNT] = { "GRAPHICS", "TRANSFER" }; - -KITC_DECL_TYPED_ARRAY(VkDescriptorSet) - -typedef struct vulkan_context { - VkInstance instance; - VkAllocationCallbacks* allocator; - VkSurfaceKHR surface; - vulkan_swapchain_support_info swapchain_support; - - arena temp_arena; - arena pool_arena; - gpu_device* device; - gpu_swapchain* swapchain; - u32 framebuffer_count; - VkFramebuffer* - swapchain_framebuffers; // TODO: Move this data into the swapchain as its own struct - - u32 current_img_index; - u32 current_frame; // super important - gpu_cmd_encoder main_cmd_bufs[MAX_FRAMES_IN_FLIGHT]; - VkSemaphore image_available_semaphores[MAX_FRAMES_IN_FLIGHT]; - VkSemaphore render_finished_semaphores[MAX_FRAMES_IN_FLIGHT]; - VkFence in_flight_fences[MAX_FRAMES_IN_FLIGHT]; - - // HACK - VkRenderPass main_renderpass; - - u32 screen_width; - u32 screen_height; - bool is_resizing; - GLFWwindow* window; - - // Storage - gpu_buffer buffers[1024]; - size_t buffer_count; - VkDescriptorSet_darray* free_set_queue; - struct resource_pools* resource_pools; - gpu_backend_pools gpu_pools; - - VkDebugUtilsMessengerEXT vk_debugger; -} vulkan_context; - -static vulkan_context context; - -// --- Function forward declarations - -void backend_pools_init(arena* a, gpu_backend_pools* backend_pools); - -/** @brief Enumerates and selects the most appropriate graphics device */ -bool select_physical_device(gpu_device* out_device); - -bool is_physical_device_suitable(VkPhysicalDevice device); - -queue_family_indices find_queue_families(VkPhysicalDevice device); - -bool create_logical_device(gpu_device* out_device); -void create_swapchain_framebuffers(); -void create_sync_objects(); -void create_descriptor_pools(); -size_t vertex_attrib_size(vertex_attrib_type attr); - -VkShaderModule create_shader_module(str8 spirv); - -/** @brief Helper function for creating array of all extensions we want */ -cstr_darray* get_all_extensions(); - -VkImage vulkan_image_create(u32x2 dimensions, VkImageType image_type, VkFormat format, - VkImageUsageFlags usage); -void vulkan_transition_image_layout(gpu_texture* texture, VkFormat format, VkImageLayout old_layout, - VkImageLayout new_layout); - -// --- Handy macros -#define BUFFER_GET(h) (buffer_pool_get(&context.resource_pools->buffers, h)) -#define TEXTURE_GET(h) (texture_pool_get(&context.resource_pools->textures, h)) - -bool gpu_backend_init(const char* window_name, GLFWwindow* window) { - memset(&context, 0, sizeof(vulkan_context)); - context.allocator = 0; // TODO: use an allocator - context.screen_width = SCREEN_WIDTH; - context.screen_height = SCREEN_HEIGHT; - context.window = window; - context.current_img_index = 0; - context.current_frame = 0; - context.free_set_queue = VkDescriptorSet_darray_new(100); - - // Create an allocator - size_t temp_arena_size = 1024 * 1024; - context.temp_arena = arena_create(malloc(temp_arena_size), temp_arena_size); - - size_t pool_buffer_size = 1024 * 1024; - context.pool_arena = arena_create(malloc(pool_buffer_size), pool_buffer_size); - - backend_pools_init(&context.pool_arena, &context.gpu_pools); - - // Setup Vulkan instance - VkApplicationInfo app_info = { VK_STRUCTURE_TYPE_APPLICATION_INFO }; - app_info.apiVersion = VK_API_VERSION_1_2; - app_info.pApplicationName = window_name; - app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0); - app_info.pEngineName = "Celeritas Engine"; - app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0); - - VkInstanceCreateInfo create_info = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO }; - create_info.pApplicationInfo = &app_info; - - // Extensions - cstr_darray* required_extensions = cstr_darray_new(2); - // cstr_darray_push(required_extensions, VK_KHR_SURFACE_EXTENSION_NAME); - - uint32_t count; - const char** extensions = glfwGetRequiredInstanceExtensions(&count); - for (u32 i = 0; i < count; i++) { - cstr_darray_push(required_extensions, extensions[i]); - } - - cstr_darray_push(required_extensions, VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - - DEBUG("Required extensions:"); - for (u32 i = 0; i < cstr_darray_len(required_extensions); i++) { - DEBUG(" %s", required_extensions->data[i]); - } - - create_info.enabledExtensionCount = cstr_darray_len(required_extensions); - create_info.ppEnabledExtensionNames = required_extensions->data; - - // TODO: Validation layers - create_info.enabledLayerCount = 0; - create_info.ppEnabledLayerNames = NULL; - - INFO("Validation layers enabled"); - cstr_darray* desired_validation_layers = cstr_darray_new(1); - cstr_darray_push(desired_validation_layers, "VK_LAYER_KHRONOS_validation"); - - u32 n_available_layers = 0; - VK_CHECK(vkEnumerateInstanceLayerProperties(&n_available_layers, 0)); - TRACE("%d available layers", n_available_layers); - VkLayerProperties* available_layers = - arena_alloc(&context.temp_arena, n_available_layers * sizeof(VkLayerProperties)); - VK_CHECK(vkEnumerateInstanceLayerProperties(&n_available_layers, available_layers)); - - for (int i = 0; i < cstr_darray_len(desired_validation_layers); i++) { - // look through layers to make sure we can find the ones we want - bool found = false; - for (int j = 0; j < n_available_layers; j++) { - if (str8_equals(str8_cstr_view(desired_validation_layers->data[i]), - str8_cstr_view(available_layers[j].layerName))) { - found = true; - TRACE("Found layer %s", desired_validation_layers->data[i]); - break; - } - } - - if (!found) { - FATAL("Required validation is missing %s", desired_validation_layers->data[i]); - return false; - } - } - INFO("All validation layers are present"); - create_info.enabledLayerCount = cstr_darray_len(desired_validation_layers); - create_info.ppEnabledLayerNames = desired_validation_layers->data; - - VkResult result = vkCreateInstance(&create_info, NULL, &context.instance); - if (result != VK_SUCCESS) { - ERROR("vkCreateInstance failed with result: %u", result); - return false; - } - TRACE("Vulkan Instance created"); - - DEBUG("Creating Vulkan debugger"); - u32 log_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; - VkDebugUtilsMessengerCreateInfoEXT debug_create_info = { - VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT - }; - debug_create_info.messageSeverity = log_severity; - debug_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; - debug_create_info.pfnUserCallback = vk_debug_callback; - - PFN_vkCreateDebugUtilsMessengerEXT func = - (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(context.instance, - "vkCreateDebugUtilsMessengerEXT"); - assert(func); - VK_CHECK(func(context.instance, &debug_create_info, context.allocator, &context.vk_debugger)); - DEBUG("Vulkan Debugger created"); - - // Surface creation - VkSurfaceKHR surface; - VK_CHECK(glfwCreateWindowSurface(context.instance, window, NULL, &surface)); - context.surface = surface; - TRACE("Vulkan Surface created"); - - return true; -} - -void gpu_backend_shutdown() { - gpu_swapchain_destroy(context.swapchain); - - vkDestroySurfaceKHR(context.instance, context.surface, context.allocator); - vkDestroyInstance(context.instance, context.allocator); - arena_free_storage(&context.temp_arena); -} - -bool gpu_device_create(gpu_device* out_device) { - // First things first store this poitner from the renderer - context.device = out_device; - - arena_save savept = arena_savepoint(&context.temp_arena); - // Physical device - if (!select_physical_device(out_device)) { - return false; - } - TRACE("Physical device selected"); - - // Logical device & Queues - create_logical_device(out_device); - - // Create the command pool - VkCommandPoolCreateInfo pool_create_info = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO }; - pool_create_info.queueFamilyIndex = out_device->queue_family_indicies.graphics_family_index; - pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - vkCreateCommandPool(out_device->logical_device, &pool_create_info, context.allocator, - &out_device->pool); - TRACE("Command Pool created"); - - // Synchronisation objects - create_sync_objects(); - TRACE("Synchronisation primitives created"); - - arena_rewind(savept); // Free any temp data - return true; -} - -bool gpu_swapchain_create(gpu_swapchain* out_swapchain) { - context.swapchain = out_swapchain; - - out_swapchain->swapchain_arena = arena_create(malloc(1024), 1024); - - vulkan_device_query_swapchain_support(context.device->physical_device, context.surface, - &context.swapchain_support); - vulkan_swapchain_support_info swapchain_support = context.swapchain_support; - - // TODO: custom swapchain extents VkExtent2D swapchain_extent = { width, height }; - - VkSurfaceFormatKHR image_format = choose_swapchain_format(&swapchain_support); - out_swapchain->image_format = image_format; - VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR; // guaranteed to be implemented - out_swapchain->present_mode = present_mode; - - u32 image_count = swapchain_support.capabilities.minImageCount + 1; - out_swapchain->image_count = image_count; - - VkSwapchainCreateInfoKHR swapchain_create_info = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR }; - swapchain_create_info.surface = context.surface; - swapchain_create_info.minImageCount = image_count; - swapchain_create_info.imageFormat = image_format.format; - swapchain_create_info.imageColorSpace = image_format.colorSpace; - swapchain_create_info.imageExtent = swapchain_support.capabilities.currentExtent; - swapchain_create_info.imageArrayLayers = 1; - swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - swapchain_create_info.queueFamilyIndexCount = 0; - swapchain_create_info.pQueueFamilyIndices = NULL; - - swapchain_create_info.preTransform = swapchain_support.capabilities.currentTransform; - swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - swapchain_create_info.presentMode = present_mode; - swapchain_create_info.clipped = VK_TRUE; - swapchain_create_info.oldSwapchain = VK_NULL_HANDLE; - - out_swapchain->extent = swapchain_support.capabilities.currentExtent; - - VK_CHECK(vkCreateSwapchainKHR(context.device->logical_device, &swapchain_create_info, - context.allocator, &out_swapchain->handle)); - TRACE("Vulkan Swapchain created"); - - // Retrieve Images - // out_swapchain->images = - // arena_alloc(&out_swapchain->swapchain_arena, image_count * sizeof(VkImage)); - out_swapchain->images = malloc(image_count * sizeof(VkImage)); - VK_CHECK(vkGetSwapchainImagesKHR(context.device->logical_device, out_swapchain->handle, - &image_count, out_swapchain->images)); - - // Create ImageViews - // TODO: Move this to a separate function - out_swapchain->image_views = malloc(image_count * sizeof(VkImageView)); - // arena_alloc(&out_swapchain->swapchain_arena, image_count * sizeof(VkImageView)); - for (u32 i = 0; i < image_count; i++) { - VkImageViewCreateInfo view_create_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; - view_create_info.image = out_swapchain->images[i]; - view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; - view_create_info.format = image_format.format; - view_create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; - view_create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; - view_create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; - view_create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; - view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - view_create_info.subresourceRange.baseMipLevel = 0; - view_create_info.subresourceRange.levelCount = 1; - view_create_info.subresourceRange.baseArrayLayer = 0; - view_create_info.subresourceRange.layerCount = 1; - vkCreateImageView(context.device->logical_device, &view_create_info, context.allocator, - &out_swapchain->image_views[i]); - } - - return true; -} - -void gpu_swapchain_destroy(gpu_swapchain* swapchain) { - // Destroy Framebuffers - DEBUG("Image count %d", swapchain->image_count); - for (u32 i = 0; i < swapchain->image_count; i++) { - DEBUG("Framebuffer handle %d", context.swapchain_framebuffers[i]); - vkDestroyFramebuffer(context.device->logical_device, context.swapchain_framebuffers[i], - context.allocator); - } - for (u32 i = 0; i < swapchain->image_count; i++) { - vkDestroyImageView(context.device->logical_device, swapchain->image_views[i], - context.allocator); - } - arena_free_all(&swapchain->swapchain_arena); - vkDestroySwapchainKHR(context.device->logical_device, swapchain->handle, context.allocator); - TRACE("Vulkan Swapchain destroyed"); -} - -static void recreate_swapchain(gpu_swapchain* swapchain) { - int width = 0, height = 0; - glfwGetFramebufferSize(context.window, &width, &height); - while (width == 0 || height == 0) { - glfwGetFramebufferSize(context.window, &width, &height); - glfwWaitEvents(); - } - DEBUG("Recreating swapchain..."); - vkDeviceWaitIdle(context.device->logical_device); - - gpu_swapchain_destroy(swapchain); - gpu_swapchain_create(swapchain); - create_swapchain_framebuffers(); -} - -VkFormat format_from_vertex_attr(vertex_attrib_type attr) { - switch (attr) { - case ATTR_F32: - return VK_FORMAT_R32_SFLOAT; - case ATTR_U32: - return VK_FORMAT_R32_UINT; - case ATTR_I32: - return VK_FORMAT_R32_SINT; - case ATTR_F32x2: - return VK_FORMAT_R32G32_SFLOAT; - case ATTR_U32x2: - return VK_FORMAT_R32G32_UINT; - case ATTR_I32x2: - return VK_FORMAT_R32G32_UINT; - case ATTR_F32x3: - return VK_FORMAT_R32G32B32_SFLOAT; - case ATTR_U32x3: - return VK_FORMAT_R32G32B32_UINT; - case ATTR_I32x3: - return VK_FORMAT_R32G32B32_SINT; - case ATTR_F32x4: - return VK_FORMAT_R32G32B32A32_SFLOAT; - case ATTR_U32x4: - return VK_FORMAT_R32G32B32A32_UINT; - case ATTR_I32x4: - return VK_FORMAT_R32G32B32A32_SINT; - } -} - -gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc description) { - TRACE("GPU Graphics Pipeline creation"); - // Allocate - gpu_pipeline_layout* layout = - pipeline_layout_pool_alloc(&context.gpu_pools.pipeline_layouts, NULL); - gpu_pipeline* pipeline = pipeline_pool_alloc(&context.gpu_pools.pipelines, NULL); - - // Shaders - printf("Vertex shader: %s\n", description.vs.filepath.buf); - printf("Fragment shader: %s\n", description.fs.filepath.buf); - VkShaderModule vertex_shader = create_shader_module(description.vs.code); - VkShaderModule fragment_shader = create_shader_module(description.fs.code); - - // Vertex - VkPipelineShaderStageCreateInfo vert_shader_stage_info = { - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO - }; - vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; - vert_shader_stage_info.module = vertex_shader; - vert_shader_stage_info.pName = "main"; - // Fragment - VkPipelineShaderStageCreateInfo frag_shader_stage_info = { - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO - }; - frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; - frag_shader_stage_info.module = fragment_shader; - frag_shader_stage_info.pName = "main"; - - VkPipelineShaderStageCreateInfo shader_stages[2] = { vert_shader_stage_info, - frag_shader_stage_info }; - - // Attributes - u32 attr_count = description.vertex_desc.attributes_count; - printf("N attributes %d\n", attr_count); - VkVertexInputAttributeDescription attribute_descs[attr_count]; - memset(attribute_descs, 0, attr_count * sizeof(VkVertexInputAttributeDescription)); - u32 offset = 0; - for (u32 i = 0; i < description.vertex_desc.attributes_count; i++) { - attribute_descs[i].binding = 0; - attribute_descs[i].location = i; - attribute_descs[i].format = format_from_vertex_attr(description.vertex_desc.attributes[i]); - attribute_descs[i].offset = offset; - size_t this_offset = vertex_attrib_size(description.vertex_desc.attributes[i]); - printf("offset total %d this attr %ld\n", offset, this_offset); - printf("sizeof vertex %ld\n", sizeof(vertex)); - offset += this_offset; - } - - // Vertex input - // TODO: Generate this from descroiption now - VkVertexInputBindingDescription binding_desc; - binding_desc.binding = 0; - binding_desc.stride = description.vertex_desc.use_full_vertex_size - ? sizeof(vertex) - : description.vertex_desc.stride; - binding_desc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - - VkPipelineVertexInputStateCreateInfo vertex_input_info = { - VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO - }; - vertex_input_info.vertexBindingDescriptionCount = 1; - vertex_input_info.pVertexBindingDescriptions = &binding_desc; - vertex_input_info.vertexAttributeDescriptionCount = - attr_count; // description.vertex_desc.attributes_count; - vertex_input_info.pVertexAttributeDescriptions = attribute_descs; - - // Input Assembly - VkPipelineInputAssemblyStateCreateInfo input_assembly = { - VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO - }; - input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - input_assembly.primitiveRestartEnable = VK_FALSE; - - // Viewport - VkViewport viewport = { .x = 0, - .y = 0, - .width = (f32)context.swapchain->extent.width, - .height = (f32)context.swapchain->extent.height, - .minDepth = 0.0, - .maxDepth = 1.0 }; - VkRect2D scissor = { .offset = { .x = 0, .y = 0 }, .extent = context.swapchain->extent }; - VkPipelineViewportStateCreateInfo viewport_state = { - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO - }; - viewport_state.viewportCount = 1; - // viewport_state.pViewports = &viewport; - viewport_state.scissorCount = 1; - // viewport_state.pScissors = &scissor; - - // Rasterizer - VkPipelineRasterizationStateCreateInfo rasterizer_create_info = { - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO - }; - rasterizer_create_info.depthClampEnable = VK_FALSE; - rasterizer_create_info.rasterizerDiscardEnable = VK_FALSE; - rasterizer_create_info.polygonMode = - description.wireframe ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL; - rasterizer_create_info.lineWidth = 1.0f; - rasterizer_create_info.cullMode = VK_CULL_MODE_BACK_BIT; - rasterizer_create_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; - /* rasterizer_create_info.frontFace = VK_FRONT_FACE_CLOCKWISE; */ - rasterizer_create_info.depthBiasEnable = VK_FALSE; - rasterizer_create_info.depthBiasConstantFactor = 0.0; - rasterizer_create_info.depthBiasClamp = 0.0; - rasterizer_create_info.depthBiasSlopeFactor = 0.0; - - // Multisampling - VkPipelineMultisampleStateCreateInfo ms_create_info = { - VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO - }; - ms_create_info.sampleShadingEnable = VK_FALSE; - ms_create_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - ms_create_info.minSampleShading = 1.0; - ms_create_info.pSampleMask = 0; - ms_create_info.alphaToCoverageEnable = VK_FALSE; - ms_create_info.alphaToOneEnable = VK_FALSE; - - // TODO: Depth and stencil testing - // VkPipelineDepthStencilStateCreateInfo depth_stencil = { - // VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO - // }; - // depth_stencil.depthTestEnable = description.depth_test ? VK_TRUE : VK_FALSE; - // depth_stencil.depthWriteEnable = description.depth_test ? VK_TRUE : VK_FALSE; - // depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS; - // depth_stencil.depthBoundsTestEnable = VK_FALSE; - // depth_stencil.stencilTestEnable = VK_FALSE; - // depth_stencil.pNext = 0; - - // Blending - VkPipelineColorBlendAttachmentState color_blend_attachment_state; - color_blend_attachment_state.blendEnable = VK_FALSE; - color_blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; - color_blend_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - color_blend_attachment_state.colorBlendOp = VK_BLEND_OP_ADD; - color_blend_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; - color_blend_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - color_blend_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD; - color_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | - VK_COLOR_COMPONENT_G_BIT | - VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - - VkPipelineColorBlendStateCreateInfo color_blend = { - VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO - }; - color_blend.logicOpEnable = VK_FALSE; - color_blend.logicOp = VK_LOGIC_OP_COPY; - color_blend.attachmentCount = 1; - color_blend.pAttachments = &color_blend_attachment_state; - -// Dynamic state -#define DYNAMIC_STATE_COUNT 2 - VkDynamicState dynamic_states[DYNAMIC_STATE_COUNT] = { - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR, - }; - - VkPipelineDynamicStateCreateInfo dynamic_state = { - VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO - }; - dynamic_state.dynamicStateCount = DYNAMIC_STATE_COUNT; - dynamic_state.pDynamicStates = dynamic_states; - - // Descriptor Set layouts - - VkDescriptorSetLayout* desc_set_layouts = - malloc(description.data_layouts_count * sizeof(VkDescriptorSetLayout)); - pipeline->desc_set_layouts = desc_set_layouts; - pipeline->desc_set_layouts_count = description.data_layouts_count; - if (description.data_layouts_count > 0) { - pipeline->uniform_pointers = - malloc(description.data_layouts_count * sizeof(desc_set_uniform_buffer)); - } else { - pipeline->uniform_pointers = NULL; - } - - // assert(description.data_layouts_count == 1); - printf("data layouts %d\n", description.data_layouts_count); - for (u32 layout_i = 0; layout_i < description.data_layouts_count; layout_i++) { - shader_data_layout sdl = description.data_layouts[layout_i].shader_data_get_layout(NULL); - TRACE("Got shader data layout %d's bindings! . found %d", layout_i, sdl.bindings_count); - - VkDescriptorSetLayoutBinding desc_set_bindings[sdl.bindings_count]; - - // Bindings - assert(sdl.bindings_count == 2); - for (u32 binding_j = 0; binding_j < sdl.bindings_count; binding_j++) { - desc_set_bindings[binding_j].binding = binding_j; - desc_set_bindings[binding_j].descriptorCount = 1; - switch (sdl.bindings[binding_j].type) { - case SHADER_BINDING_BUFFER: - case SHADER_BINDING_BYTES: - desc_set_bindings[binding_j].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - desc_set_bindings[binding_j].stageFlags = - VK_SHADER_STAGE_VERTEX_BIT; // FIXME: dont hardcode - - u64 buffer_size = sdl.bindings[binding_j].data.bytes.size; - VkDeviceSize uniform_buf_size = buffer_size; - // TODO: Create backing buffer - - VkBuffer buffers[MAX_FRAMES_IN_FLIGHT]; - VkDeviceMemory uniform_buf_memorys[MAX_FRAMES_IN_FLIGHT]; - void* uniform_buf_mem_mappings[MAX_FRAMES_IN_FLIGHT]; - // void* s? - for (size_t frame_i = 0; frame_i < MAX_FRAMES_IN_FLIGHT; frame_i++) { - buffer_handle uniform_buf_handle = - gpu_buffer_create(buffer_size, CEL_BUFFER_UNIFORM, CEL_BUFFER_FLAG_CPU, NULL); - - gpu_buffer* created_gpu_buffer = - BUFFER_GET(uniform_buf_handle); // context.buffers[uniform_buf_handle.raw]; - buffers[frame_i] = created_gpu_buffer->handle; - uniform_buf_memorys[frame_i] = created_gpu_buffer->memory; - vkMapMemory(context.device->logical_device, uniform_buf_memorys[frame_i], 0, - uniform_buf_size, 0, &uniform_buf_mem_mappings[frame_i]); - // now we have a pointer in unifrom_buf_mem_mappings we can write to - } - - desc_set_uniform_buffer uniform_data; - memcpy(&uniform_data.buffers, &buffers, sizeof(buffers)); - memcpy(&uniform_data.uniform_buf_memorys, &uniform_buf_memorys, - sizeof(uniform_buf_memorys)); - memcpy(&uniform_data.uniform_buf_mem_mappings, &uniform_buf_mem_mappings, - sizeof(uniform_buf_mem_mappings)); - uniform_data.size = buffer_size; - - pipeline->uniform_pointers[binding_j] = uniform_data; - - break; - case SHADER_BINDING_TEXTURE: - desc_set_bindings[binding_j].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - desc_set_bindings[binding_j].stageFlags = - VK_SHADER_STAGE_FRAGMENT_BIT; // FIXME: dont hardcode - desc_set_bindings[binding_j].pImmutableSamplers = NULL; - - break; - default: - ERROR_EXIT("Unimplemented binding type!! in backend_vulkan"); - } - switch (sdl.bindings[binding_j].vis) { - case VISIBILITY_VERTEX: - desc_set_bindings[binding_j].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - break; - case VISIBILITY_FRAGMENT: - desc_set_bindings[binding_j].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - break; - case VISIBILITY_COMPUTE: - WARN("Compute is not implemented yet"); - break; - } - } - - VkDescriptorSetLayoutCreateInfo desc_set_layout_info = { - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO - }; - desc_set_layout_info.bindingCount = sdl.bindings_count; - desc_set_layout_info.pBindings = desc_set_bindings; - - VK_CHECK(vkCreateDescriptorSetLayout(context.device->logical_device, &desc_set_layout_info, - context.allocator, &desc_set_layouts[layout_i])); - } - printf("Descriptor set layouts\n"); - - // Layout - VkPipelineLayoutCreateInfo pipeline_layout_create_info = { - VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO - }; - pipeline_layout_create_info.setLayoutCount = description.data_layouts_count; - pipeline_layout_create_info.pSetLayouts = desc_set_layouts; - pipeline_layout_create_info.pushConstantRangeCount = 0; - pipeline_layout_create_info.pPushConstantRanges = NULL; - VK_CHECK(vkCreatePipelineLayout(context.device->logical_device, &pipeline_layout_create_info, - context.allocator, &layout->handle)); - pipeline->layout_handle = layout->handle; // keep a copy of the layout on the pipeline object - - VkGraphicsPipelineCreateInfo pipeline_create_info = { - VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO - }; - - pipeline_create_info.stageCount = 2; - pipeline_create_info.pStages = shader_stages; - pipeline_create_info.pVertexInputState = &vertex_input_info; - pipeline_create_info.pInputAssemblyState = &input_assembly; - - pipeline_create_info.pViewportState = &viewport_state; - pipeline_create_info.pRasterizationState = &rasterizer_create_info; - pipeline_create_info.pMultisampleState = &ms_create_info; - pipeline_create_info.pDepthStencilState = NULL; // &depth_stencil; - pipeline_create_info.pColorBlendState = &color_blend; - pipeline_create_info.pDynamicState = &dynamic_state; - pipeline_create_info.pTessellationState = 0; - - pipeline_create_info.layout = layout->handle; - - pipeline_create_info.renderPass = description.renderpass->handle; - pipeline_create_info.subpass = 0; - pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE; - pipeline_create_info.basePipelineIndex = -1; - - printf("About to create graphics pipeline\n"); - - VkResult result = - vkCreateGraphicsPipelines(context.device->logical_device, VK_NULL_HANDLE, 1, - &pipeline_create_info, context.allocator, &pipeline->handle); - if (result != VK_SUCCESS) { - FATAL("graphics pipeline creation failed. its fked mate"); - ERROR_EXIT("Doomed"); - } - TRACE("Vulkan Graphics pipeline created"); - - // once the pipeline has been created we can destroy these - vkDestroyShaderModule(context.device->logical_device, vertex_shader, context.allocator); - vkDestroyShaderModule(context.device->logical_device, fragment_shader, context.allocator); - - // Framebuffers - create_swapchain_framebuffers(); - TRACE("Swapchain Framebuffers created"); - - for (u32 frame_i = 0; frame_i < MAX_FRAMES_IN_FLIGHT; frame_i++) { - context.main_cmd_bufs[frame_i] = gpu_cmd_encoder_create(); - } - TRACE("main Command Buffer created"); - - TRACE("Graphics pipeline created"); - return pipeline; -} - -void gpu_pipeline_destroy(gpu_pipeline* pipeline) { - vkDestroyPipeline(context.device->logical_device, pipeline->handle, context.allocator); - vkDestroyPipelineLayout(context.device->logical_device, pipeline->layout_handle, - context.allocator); -} - -gpu_cmd_encoder* gpu_get_default_cmd_encoder() { - return &context.main_cmd_bufs[context.current_frame]; -} - -gpu_renderpass* gpu_renderpass_create(const gpu_renderpass_desc* description) { - gpu_renderpass* renderpass = renderpass_pool_alloc(&context.gpu_pools.renderpasses, NULL); - - // attachments - u32 attachment_desc_count = 2; - VkAttachmentDescription attachment_descriptions[2]; - - // Colour attachment - VkAttachmentDescription color_attachment; - color_attachment.format = context.swapchain->image_format.format; - color_attachment.samples = VK_SAMPLE_COUNT_1_BIT; - color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - color_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - color_attachment.flags = 0; - - attachment_descriptions[0] = color_attachment; - - VkAttachmentReference color_attachment_reference; - color_attachment_reference.attachment = 0; - color_attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - // Depth attachment - u32x2 ext = { .x = context.swapchain_support.capabilities.currentExtent.width, - .y = context.swapchain_support.capabilities.currentExtent.height }; - texture_desc depth_desc = { .extents = ext, - .format = CEL_TEXTURE_FORMAT_DEPTH_DEFAULT, - .tex_type = CEL_TEXTURE_TYPE_2D }; - texture_handle depth_texture_handle = gpu_texture_create(depth_desc, true, NULL); - gpu_texture* depth = TEXTURE_GET(depth_texture_handle); - - VkAttachmentDescription depth_attachment; - depth_attachment.format = // TODO: context->device.depth_format; - depth_attachment.samples = VK_SAMPLE_COUNT_1_BIT; - depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - depth_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - depth_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - depth_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - depth_attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - depth_attachment.flags = 0; - - attachment_descriptions[1] = depth_attachment; - - VkAttachmentReference depth_attachment_reference; - depth_attachment_reference.attachment = 1; - depth_attachment_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - // main subpass - VkSubpassDescription subpass = { 0 }; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &color_attachment_reference; - - // sets everything up - // renderpass dependencies - VkSubpassDependency dependency; - dependency.srcSubpass = VK_SUBPASS_EXTERNAL; - dependency.dstSubpass = 0; - dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependency.srcAccessMask = 0; - dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependency.dstAccessMask = - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dependency.dependencyFlags = 0; - - // Finally, create the RenderPass - VkRenderPassCreateInfo render_pass_create_info = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO }; - render_pass_create_info.attachmentCount = 1; - render_pass_create_info.pAttachments = &color_attachment; - render_pass_create_info.subpassCount = 1; - render_pass_create_info.pSubpasses = &subpass; - render_pass_create_info.dependencyCount = 1; - render_pass_create_info.pDependencies = &dependency; - render_pass_create_info.flags = 0; - render_pass_create_info.pNext = 0; - - VK_CHECK(vkCreateRenderPass(context.device->logical_device, &render_pass_create_info, - context.allocator, &renderpass->handle)); - - // HACK - context.main_renderpass = renderpass->handle; - - return renderpass; -} - -gpu_cmd_encoder gpu_cmd_encoder_create() { - // gpu_cmd_encoder* encoder = malloc(sizeof(gpu_cmd_encoder)); // TODO: fix leaking mem - gpu_cmd_encoder encoder = { 0 }; - - VkCommandBufferAllocateInfo allocate_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; - allocate_info.commandPool = context.device->pool; - allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - allocate_info.commandBufferCount = 1; - allocate_info.pNext = NULL; - - VK_CHECK(vkAllocateCommandBuffers(context.device->logical_device, &allocate_info, - &encoder.cmd_buffer);); - - VkDescriptorPoolSize pool_sizes[2]; - // Uniforms pool - pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - pool_sizes[0].descriptorCount = MAX_FRAMES_IN_FLIGHT * MAX_DESCRIPTOR_SETS; - // Samplers pool - pool_sizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - pool_sizes[1].descriptorCount = MAX_FRAMES_IN_FLIGHT * MAX_DESCRIPTOR_SETS; - - VkDescriptorPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; - pool_info.poolSizeCount = 2; - pool_info.pPoolSizes = pool_sizes; - pool_info.maxSets = 100; - - VK_CHECK(vkCreateDescriptorPool(context.device->logical_device, &pool_info, context.allocator, - &encoder.descriptor_pool)); - - return encoder; -} -void gpu_cmd_encoder_destroy(gpu_cmd_encoder* encoder) { - vkFreeCommandBuffers(context.device->logical_device, context.device->pool, 1, - &encoder->cmd_buffer); -} - -void gpu_cmd_encoder_begin(gpu_cmd_encoder encoder) { - VK_CHECK(vkResetDescriptorPool(context.device->logical_device, encoder.descriptor_pool, 0)); - - VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; - VK_CHECK(vkBeginCommandBuffer(encoder.cmd_buffer, &begin_info)); -} - -void gpu_cmd_encoder_begin_render(gpu_cmd_encoder* encoder, gpu_renderpass* renderpass) { - VkRenderPassBeginInfo begin_info = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO }; - begin_info.renderPass = renderpass->handle; - /* printf("Current img: %d Current frame %d\n", context.current_img_index, context.current_frame); - */ - begin_info.framebuffer = context.swapchain_framebuffers[context.current_img_index]; - begin_info.renderArea.offset = (VkOffset2D){ 0, 0 }; - begin_info.renderArea.extent = context.swapchain->extent; - - // VkClearValue clear_values[2]; - VkClearValue clear_color = { { { 0.02f, 0.02f, 0.02f, 1.0f } } }; - // clear_values[1].depthStencil.depth = renderpass->depth; - // clear_values[1].depthStencil.stencil = renderpass->stencil; - - begin_info.clearValueCount = 1; - begin_info.pClearValues = &clear_color; - - vkCmdBeginRenderPass(encoder->cmd_buffer, &begin_info, VK_SUBPASS_CONTENTS_INLINE); - // command_buffer->state = COMMAND_BUFFER_STATE_IN_RENDER_PASS; -} - -void gpu_cmd_encoder_end_render(gpu_cmd_encoder* encoder) { - vkCmdEndRenderPass(encoder->cmd_buffer); -} - -gpu_cmd_buffer gpu_cmd_encoder_finish(gpu_cmd_encoder* encoder) { - vkEndCommandBuffer(encoder->cmd_buffer); - - // TEMP: submit - return (gpu_cmd_buffer){ .cmd_buffer = encoder->cmd_buffer }; -} - -// --- Binding -void encode_bind_pipeline(gpu_cmd_encoder* encoder, pipeline_kind kind, gpu_pipeline* pipeline) { - vkCmdBindPipeline(encoder->cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->handle); - encoder->pipeline = pipeline; -} - -void encode_bind_shader_data(gpu_cmd_encoder* encoder, u32 group, shader_data* data) { - arena tmp = arena_create(malloc(1024), 1024); - - assert(data->data != NULL); - - // Update the local buffer - desc_set_uniform_buffer ubo = encoder->pipeline->uniform_pointers[group]; - memcpy(ubo.uniform_buf_mem_mappings[context.current_frame], data->data, ubo.size); - - VkDescriptorSetAllocateInfo alloc_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; - alloc_info.descriptorPool = encoder->descriptor_pool; - alloc_info.descriptorSetCount = 1; - alloc_info.pSetLayouts = &encoder->pipeline->desc_set_layouts[group]; - - shader_data_layout sdl = data->shader_data_get_layout(data->data); - size_t binding_count = sdl.bindings_count; - assert(binding_count == 2); - - VkDescriptorSet sets[0]; - VK_CHECK(vkAllocateDescriptorSets(context.device->logical_device, &alloc_info, sets)); - // FIXME: hardcoded - VkDescriptorSet_darray_push(context.free_set_queue, sets[0]); - /* VkDescriptorSet_darray_push(context.free_set_queue, sets[1]); */ - - VkWriteDescriptorSet write_sets[binding_count]; - memset(&write_sets, 0, binding_count * sizeof(VkWriteDescriptorSet)); - - for (u32 i = 0; i < sdl.bindings_count; i++) { - shader_binding binding = sdl.bindings[i]; - - if (binding.type == SHADER_BINDING_BUFFER || binding.type == SHADER_BINDING_BYTES) { - VkDescriptorBufferInfo* buffer_info = arena_alloc(&tmp, sizeof(VkDescriptorBufferInfo)); - buffer_info->buffer = ubo.buffers[context.current_frame]; - buffer_info->offset = 0; - buffer_info->range = binding.data.bytes.size; - - write_sets[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write_sets[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - write_sets[i].descriptorCount = 1; - write_sets[i].dstSet = sets[0]; - write_sets[i].dstBinding = i; - write_sets[i].dstArrayElement = 0; - write_sets[i].pBufferInfo = buffer_info; - } else if (binding.type == SHADER_BINDING_TEXTURE) { - gpu_texture* texture = TEXTURE_GET(binding.data.texture.handle); - VkDescriptorImageInfo* image_info = arena_alloc(&tmp, sizeof(VkDescriptorImageInfo)); - image_info->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - image_info->imageView = texture->view; - image_info->sampler = texture->sampler; - - write_sets[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write_sets[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - write_sets[i].descriptorCount = 1; - write_sets[i].dstSet = sets[0]; - write_sets[i].dstBinding = i; - write_sets[i].dstArrayElement = 0; - write_sets[i].pImageInfo = image_info; - } else { - WARN("Unknown binding"); - } - } - - // Update - vkUpdateDescriptorSets(context.device->logical_device, binding_count, write_sets, 0, NULL); - - // Bind - vkCmdBindDescriptorSets(encoder->cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, - encoder->pipeline->layout_handle, 0, 1, sets, 0, NULL); - - arena_free_storage(&tmp); -} - -void encode_set_vertex_buffer(gpu_cmd_encoder* encoder, buffer_handle buf) { - gpu_buffer* buffer = BUFFER_GET(buf); // context.buffers[buf.raw]; - VkBuffer vbs[] = { buffer->handle }; - VkDeviceSize offsets[] = { 0 }; - vkCmdBindVertexBuffers(encoder->cmd_buffer, 0, 1, vbs, offsets); -} - -void encode_set_index_buffer(gpu_cmd_encoder* encoder, buffer_handle buf) { - gpu_buffer* buffer = BUFFER_GET(buf); // context.buffers[buf.raw]; - vkCmdBindIndexBuffer(encoder->cmd_buffer, buffer->handle, 0, VK_INDEX_TYPE_UINT32); -} - -// TEMP -void encode_set_default_settings(gpu_cmd_encoder* encoder) { - VkViewport viewport = { 0 }; - viewport.x = 0.0f; - viewport.y = 0.0f; - viewport.width = context.swapchain->extent.width; - viewport.height = context.swapchain->extent.height; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - vkCmdSetViewport(encoder->cmd_buffer, 0, 1, &viewport); - - VkRect2D scissor = { 0 }; - scissor.offset = (VkOffset2D){ 0, 0 }; - scissor.extent = context.swapchain->extent; - vkCmdSetScissor(encoder->cmd_buffer, 0, 1, &scissor); -} - -// --- Drawing - -bool gpu_backend_begin_frame() { - u32 current_frame = context.current_frame; - vkWaitForFences(context.device->logical_device, 1, &context.in_flight_fences[current_frame], - VK_TRUE, UINT64_MAX); - - u32 image_index; - VkResult result = vkAcquireNextImageKHR( - context.device->logical_device, context.swapchain->handle, UINT64_MAX, - context.image_available_semaphores[current_frame], VK_NULL_HANDLE, &image_index); - if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || context.is_resizing) { - ERROR("Acquire next image failure. recreate swapchain"); - context.is_resizing = false; - recreate_swapchain(context.swapchain); - return false; - } else if (result != VK_SUCCESS) { - ERROR_EXIT("failed to acquire swapchain image"); - } - - vkResetFences(context.device->logical_device, 1, &context.in_flight_fences[current_frame]); - - context.current_img_index = image_index; - VK_CHECK(vkResetCommandBuffer(context.main_cmd_bufs[current_frame].cmd_buffer, 0)); - return true; -} - -void gpu_temp_draw(size_t n_indices) { - gpu_cmd_encoder* encoder = gpu_get_default_cmd_encoder(); // &context.main_cmd_buf; - /* vkCmdDraw(encoder->cmd_buffer, n_verts, 1, 0, 0); */ - vkCmdDrawIndexed(encoder->cmd_buffer, n_indices, 1, 0, 0, 0); -} - -void gpu_backend_end_frame() { - VkPresentInfoKHR present_info = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR }; - present_info.waitSemaphoreCount = 1; - present_info.pWaitSemaphores = &context.render_finished_semaphores[context.current_frame]; - - VkSwapchainKHR swapchains[] = { context.swapchain->handle }; - present_info.swapchainCount = 1; - present_info.pSwapchains = swapchains; - present_info.pImageIndices = &context.current_img_index; - - VkResult result = vkQueuePresentKHR(context.device->present_queue, &present_info); - if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { - ERROR("Queue present error. recreate swapchain"); - recreate_swapchain(context.swapchain); - return; - } else if (result != VK_SUCCESS) { - ERROR_EXIT("failed to present swapchain image"); - } - context.current_frame = (context.current_frame + 1) % MAX_FRAMES_IN_FLIGHT; - - /* vkDeviceWaitIdle(context.device->logical_device); */ -} - -// TODO: Move into better order in file -void gpu_queue_submit(gpu_cmd_buffer* buffer) { - VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; - - // Specify semaphore to wait on - VkSemaphore wait_semaphores[] = { context.image_available_semaphores[context.current_frame] }; - VkPipelineStageFlags wait_stages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; - - submit_info.waitSemaphoreCount = 1; - submit_info.pWaitSemaphores = wait_semaphores; - submit_info.pWaitDstStageMask = wait_stages; - - // Specify semaphore to signal when finished executing buffer - VkSemaphore signal_semaphores[] = { context.render_finished_semaphores[context.current_frame] }; - submit_info.signalSemaphoreCount = 1; - submit_info.pSignalSemaphores = signal_semaphores; - - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &buffer->cmd_buffer; - - VK_CHECK(vkQueueSubmit(context.device->graphics_queue, 1, &submit_info, - context.in_flight_fences[context.current_frame])); -} - -inline void encode_draw_indexed(gpu_cmd_encoder* encoder, u64 index_count) { - vkCmdDrawIndexed(encoder->cmd_buffer, index_count, 1, 0, 0, 0); -} - -bool select_physical_device(gpu_device* out_device) { - u32 physical_device_count = 0; - VK_CHECK(vkEnumeratePhysicalDevices(context.instance, &physical_device_count, 0)); - if (physical_device_count == 0) { - FATAL("No devices that support vulkan were found"); - return false; - } - TRACE("Number of devices found %d", physical_device_count); - - VkPhysicalDevice* physical_devices = - arena_alloc(&context.temp_arena, physical_device_count * sizeof(VkPhysicalDevice)); - VK_CHECK(vkEnumeratePhysicalDevices(context.instance, &physical_device_count, physical_devices)); - - bool found = false; - for (u32 device_i = 0; device_i < physical_device_count; device_i++) { - if (is_physical_device_suitable(physical_devices[device_i])) { - out_device->physical_device = physical_devices[device_i]; - found = true; - break; - } - } - - if (!found) { - FATAL("Couldn't find a suitable physical device"); - return false; - } - - vkGetPhysicalDeviceProperties(out_device->physical_device, &out_device->properties); - vkGetPhysicalDeviceFeatures(out_device->physical_device, &out_device->features); - vkGetPhysicalDeviceMemoryProperties(out_device->physical_device, &out_device->memory); - - return true; -} - -bool is_physical_device_suitable(VkPhysicalDevice device) { - VkPhysicalDeviceProperties properties; - vkGetPhysicalDeviceProperties(device, &properties); - - VkPhysicalDeviceFeatures features; - vkGetPhysicalDeviceFeatures(device, &features); - - VkPhysicalDeviceMemoryProperties memory; - vkGetPhysicalDeviceMemoryProperties(device, &memory); - - // TODO: Check against these device properties - - queue_family_indices indices = find_queue_families(device); - - vulkan_device_query_swapchain_support(device, context.surface, &context.swapchain_support); - - return indices.has_graphics && indices.has_present && context.swapchain_support.mode_count > 0 && - context.swapchain_support.format_count > 0; -} - -queue_family_indices find_queue_families(VkPhysicalDevice device) { - queue_family_indices indices = { 0 }; - - u32 queue_family_count = 0; - vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, 0); - - VkQueueFamilyProperties* queue_families = - arena_alloc(&context.temp_arena, queue_family_count * sizeof(VkQueueFamilyProperties)); - vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, queue_families); - - for (u32 q_fam_i = 0; q_fam_i < queue_family_count; q_fam_i++) { - // Graphics queue - if (queue_families[q_fam_i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { - indices.graphics_family_index = q_fam_i; - indices.has_graphics = true; - } - - VkBool32 present_support = false; - vkGetPhysicalDeviceSurfaceSupportKHR(device, q_fam_i, context.surface, &present_support); - if (present_support && !indices.has_present) { - indices.present_family_index = q_fam_i; - indices.has_present = true; - } - } - - return indices; -} - -bool create_logical_device(gpu_device* out_device) { - queue_family_indices indices = find_queue_families(out_device->physical_device); - INFO(" %s | %s | %s | %s | %s", bool_str(indices.has_graphics), bool_str(indices.has_present), - bool_str(indices.has_compute), bool_str(indices.has_transfer), - out_device->properties.deviceName); - TRACE("Graphics Family queue index: %d", indices.graphics_family_index); - TRACE("Present Family queue index: %d", indices.present_family_index); - TRACE("Compute Family queue index: %d", indices.compute_family_index); - TRACE("Transfer Family queue index: %d", indices.transfer_family_index); - - // Queues - f32 prio_one = 1.0; - VkDeviceQueueCreateInfo queue_create_infos[1] = { 0 }; - queue_create_infos[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queue_create_infos[0].queueFamilyIndex = indices.graphics_family_index; - queue_create_infos[0].queueCount = 1; - queue_create_infos[0].pQueuePriorities = &prio_one; - queue_create_infos[0].flags = 0; - queue_create_infos[0].pNext = 0; - - // queue_create_infos[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - // queue_create_infos[1].queueFamilyIndex = indices.present_family_index; - // queue_create_infos[1].queueCount = 1; - // queue_create_infos[1].pQueuePriorities = &prio_one; - // queue_create_infos[1].flags = 0; - // queue_create_infos[1].pNext = 0; - - // Features - VkPhysicalDeviceFeatures device_features = { 0 }; - device_features.samplerAnisotropy = VK_TRUE; // request anistrophy - - // Device itself - VkDeviceCreateInfo device_create_info = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; - device_create_info.queueCreateInfoCount = 1; - device_create_info.pQueueCreateInfos = queue_create_infos; - device_create_info.pEnabledFeatures = &device_features; - device_create_info.enabledExtensionCount = 1; - const char* extension_names = VK_KHR_SWAPCHAIN_EXTENSION_NAME; - device_create_info.ppEnabledExtensionNames = &extension_names; - - // deprecated - device_create_info.enabledLayerCount = 0; - device_create_info.ppEnabledLayerNames = 0; - - VkResult result = vkCreateDevice(context.device->physical_device, &device_create_info, - context.allocator, &context.device->logical_device); - if (result != VK_SUCCESS) { - printf("error creating logical device with status %u\n", result); - ERROR_EXIT("Unable to create vulkan logical device. Exiting.."); - } - TRACE("Logical device created"); - - context.device->queue_family_indicies = indices; - - // Retrieve queue handles - vkGetDeviceQueue(context.device->logical_device, indices.graphics_family_index, 0, - &context.device->graphics_queue); - vkGetDeviceQueue(context.device->logical_device, indices.present_family_index, 0, - &context.device->present_queue); - - return true; -} - -VkShaderModule create_shader_module(str8 spirv) { - VkShaderModuleCreateInfo create_info = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO }; - create_info.codeSize = spirv.len; - create_info.pCode = (uint32_t*)spirv.buf; - - VkShaderModule shader_module; - VK_CHECK(vkCreateShaderModule(context.device->logical_device, &create_info, context.allocator, - &shader_module)); - - return shader_module; -} - -void create_descriptor_pools() {} - -void create_swapchain_framebuffers() { - WARN("Recreating framebuffers..."); - u32 image_count = context.swapchain->image_count; - context.swapchain_framebuffers = - arena_alloc(&context.swapchain->swapchain_arena, image_count * sizeof(VkFramebuffer)); - for (u32 i = 0; i < image_count; i++) { - VkImageView attachments[1] = { context.swapchain->image_views[i] }; - - VkFramebufferCreateInfo framebuffer_create_info = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO }; - framebuffer_create_info.attachmentCount = 1; - framebuffer_create_info.pAttachments = attachments; - - framebuffer_create_info.renderPass = - context.main_renderpass; // TODO: description.renderpass->handle; - framebuffer_create_info.width = context.swapchain->extent.width; - framebuffer_create_info.height = context.swapchain->extent.height; - framebuffer_create_info.layers = 1; - - VK_CHECK(vkCreateFramebuffer(context.device->logical_device, &framebuffer_create_info, - context.allocator, &context.swapchain_framebuffers[i])); - } -} - -void create_sync_objects() { - VkSemaphoreCreateInfo semaphore_info = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO }; - VkFenceCreateInfo fence_info = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO }; - fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; - - for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - VK_CHECK(vkCreateSemaphore(context.device->logical_device, &semaphore_info, context.allocator, - &context.image_available_semaphores[i]);); - VK_CHECK(vkCreateSemaphore(context.device->logical_device, &semaphore_info, context.allocator, - &context.render_finished_semaphores[i]);); - - VK_CHECK(vkCreateFence(context.device->logical_device, &fence_info, context.allocator, - &context.in_flight_fences[i])); - } -} - -static i32 find_memory_index(u32 type_filter, u32 property_flags) { - VkPhysicalDeviceMemoryProperties memory_properties; - vkGetPhysicalDeviceMemoryProperties(context.device->physical_device, &memory_properties); - - for (u32 i = 0; i < memory_properties.memoryTypeCount; ++i) { - // Check each memory type to see if its bit is set to 1. - if (type_filter & (1 << i) && - (memory_properties.memoryTypes[i].propertyFlags & property_flags) == property_flags) { - return i; - } - } - - WARN("Unable to find suitable memory type!"); - return -1; -} - -buffer_handle gpu_buffer_create(u64 size, gpu_buffer_type buf_type, gpu_buffer_flags flags, - const void* data) { - VkBufferCreateInfo buffer_info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; - buffer_info.size = size; - buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - - switch (buf_type) { - case CEL_BUFFER_DEFAULT: - buffer_info.usage |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - break; - case CEL_BUFFER_VERTEX: - buffer_info.usage |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; - break; - case CEL_BUFFER_INDEX: - buffer_info.usage |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT; - break; - case CEL_BUFFER_UNIFORM: - buffer_info.usage |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - break; - case CEL_BUFFER_COUNT: - WARN("Incorrect gpu_buffer_type provided. using default"); - break; - } - - buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - // "allocating" the cpu-side buffer struct - /* gpu_buffer buffer; */ - /* buffer.size = size; */ - buffer_handle handle; - gpu_buffer* buffer = buffer_pool_alloc(&context.resource_pools->buffers, &handle); - buffer->size = size; - - VK_CHECK(vkCreateBuffer(context.device->logical_device, &buffer_info, context.allocator, - &buffer->handle)); - - VkMemoryRequirements requirements; - vkGetBufferMemoryRequirements(context.device->logical_device, buffer->handle, &requirements); - - // Just make them always need all of them for now - i32 memory_index = - find_memory_index(requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - - // Allocate the actual VRAM - VkMemoryAllocateInfo allocate_info = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; - allocate_info.allocationSize = requirements.size; - allocate_info.memoryTypeIndex = (u32)memory_index; - - vkAllocateMemory(context.device->logical_device, &allocate_info, context.allocator, - &buffer->memory); - vkBindBufferMemory(context.device->logical_device, buffer->handle, buffer->memory, 0); - - /* Now there are two options: - * 1. create CPU-accessible memory -> map memory -> memcpy -> unmap - * 2. use a staging buffer thats CPU-accessible and copy its contents to a - * GPU-only buffer - */ - - /* context.buffers[context.buffer_count] = buffer; */ - /* context.buffer_count++; */ - - if (data) { - TRACE("Upload data as part of buffer creation"); - if (flags & CEL_BUFFER_FLAG_CPU) { - // map memory -> copy data in -> unmap memory - buffer_upload_bytes(handle, (bytebuffer){ .buf = (u8*)data, .size = size }, 0, size); - } else if (flags & CEL_BUFFER_FLAG_GPU) { - TRACE("Uploading data to buffer using staging buffer"); - // Create a staging buffer - buffer_handle staging = gpu_buffer_create(size, buf_type, CEL_BUFFER_FLAG_CPU, NULL); - - // Copy data into it - buffer_upload_bytes(staging, (bytebuffer){ .buf = (u8*)data, .size = size }, 0, size); - - // Enqueue a copy from the staging buffer into the DEVICE_LOCAL buffer - gpu_cmd_encoder temp_encoder = gpu_cmd_encoder_create(); - gpu_cmd_encoder_begin(temp_encoder); - encode_buffer_copy(&temp_encoder, staging, 0, handle, 0, size); - gpu_cmd_buffer copy_cmd_buffer = gpu_cmd_encoder_finish(&temp_encoder); - - VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &temp_encoder.cmd_buffer; - vkQueueSubmit(context.device->graphics_queue, 1, &submit_info, VK_NULL_HANDLE); - - // Cleanup - vkQueueWaitIdle(context.device->graphics_queue); - gpu_cmd_encoder_destroy(&temp_encoder); - gpu_buffer_destroy(staging); - } - } - - return handle; -} - -void gpu_buffer_destroy(buffer_handle buffer) { - gpu_buffer* b = buffer_pool_get(&context.resource_pools->buffers, buffer); - vkDestroyBuffer(context.device->logical_device, b->handle, context.allocator); - vkFreeMemory(context.device->logical_device, b->memory, context.allocator); - buffer_pool_dealloc(&context.resource_pools->buffers, buffer); -} - -// Upload data to a -void buffer_upload_bytes(buffer_handle gpu_buf, bytebuffer cpu_buf, u64 offset, u64 size) { - gpu_buffer* buffer = buffer_pool_get(&context.resource_pools->buffers, gpu_buf); - void* data_ptr; - vkMapMemory(context.device->logical_device, buffer->memory, 0, size, 0, &data_ptr); - DEBUG("Uploading %d bytes to buffer", size); - memcpy(data_ptr, cpu_buf.buf, size); - vkUnmapMemory(context.device->logical_device, buffer->memory); -} - -void encode_buffer_copy(gpu_cmd_encoder* encoder, buffer_handle src, u64 src_offset, - buffer_handle dst, u64 dst_offset, u64 copy_size) { - VkBufferCopy copy_region; - copy_region.srcOffset = src_offset; - copy_region.dstOffset = dst_offset; - copy_region.size = copy_size; - - gpu_buffer* src_buf = buffer_pool_get(&context.resource_pools->buffers, src); - gpu_buffer* dst_buf = buffer_pool_get(&context.resource_pools->buffers, dst); - vkCmdCopyBuffer(encoder->cmd_buffer, src_buf->handle, dst_buf->handle, 1, ©_region); -} - -// one-shot command buffers -VkCommandBuffer vulkan_command_buffer_create_oneshot() { - VkCommandBufferAllocateInfo alloc_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; - alloc_info.commandPool = context.device->pool; - alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - alloc_info.commandBufferCount = 1; - alloc_info.pNext = 0; - - VkCommandBuffer cmd_buffer; - vkAllocateCommandBuffers(context.device->logical_device, &alloc_info, &cmd_buffer); - - VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; - begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - - vkBeginCommandBuffer(cmd_buffer, &begin_info); - - return cmd_buffer; -} - -void vulkan_command_buffer_finish_oneshot(VkCommandBuffer cmd_buffer) { - VK_CHECK(vkEndCommandBuffer(cmd_buffer)); - - // submit to queue - VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &cmd_buffer; - VK_CHECK(vkQueueSubmit(context.device->graphics_queue, 1, &submit_info, 0)); - VK_CHECK(vkQueueWaitIdle(context.device->graphics_queue)); - - vkFreeCommandBuffers(context.device->logical_device, context.device->pool, 1, &cmd_buffer); -} - -void copy_buffer_to_buffer_oneshot(buffer_handle src, u64 src_offset, buffer_handle dst, - u64 dst_offset, u64 copy_size) { - VkBufferCopy copy_region; - copy_region.srcOffset = src_offset; - copy_region.dstOffset = dst_offset; - copy_region.size = copy_size; - - gpu_buffer* src_buf = buffer_pool_get(&context.resource_pools->buffers, src); - gpu_buffer* dst_buf = buffer_pool_get(&context.resource_pools->buffers, dst); - VkCommandBuffer temp_cmd_buffer = vulkan_command_buffer_create_oneshot(); - vkCmdCopyBuffer(temp_cmd_buffer, src_buf->handle, dst_buf->handle, 1, ©_region); - vulkan_command_buffer_finish_oneshot(temp_cmd_buffer); -} - -void copy_buffer_to_image_oneshot(buffer_handle src, texture_handle dst) { - gpu_buffer* src_buf = buffer_pool_get(&context.resource_pools->buffers, src); - gpu_texture* dst_tex = texture_pool_get(&context.resource_pools->textures, dst); - - VkCommandBuffer temp_cmd_buffer = vulkan_command_buffer_create_oneshot(); - - VkBufferImageCopy region; - region.bufferOffset = 0; - region.bufferRowLength = 0; - region.bufferImageHeight = 0; - region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.imageSubresource.mipLevel = 0; - region.imageSubresource.baseArrayLayer = 0; - region.imageSubresource.layerCount = 1; - printf("Image details width: %d height %d\n", dst_tex->desc.extents.x, dst_tex->desc.extents.y); - region.imageOffset.x = 0; - region.imageOffset.y = 0; - region.imageOffset.z = 0; - region.imageExtent.width = dst_tex->desc.extents.x; - region.imageExtent.height = dst_tex->desc.extents.y; - region.imageExtent.depth = 1; - - vkCmdCopyBufferToImage(temp_cmd_buffer, src_buf->handle, dst_tex->handle, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); - - vulkan_command_buffer_finish_oneshot(temp_cmd_buffer); -} - -VkImage vulkan_image_create(u32x2 dimensions, VkImageType image_type, VkFormat format, - VkImageUsageFlags usage) { - VkImage image; - - VkImageCreateInfo image_create_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; - image_create_info.imageType = VK_IMAGE_TYPE_2D; - image_create_info.extent.width = dimensions.x; - image_create_info.extent.height = dimensions.y; - image_create_info.extent.depth = 1; - image_create_info.mipLevels = 1; - image_create_info.arrayLayers = 1; - image_create_info.format = format; - image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; - image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - image_create_info.usage = usage; // VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; - image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; - - VK_CHECK( - vkCreateImage(context.device->logical_device, &image_create_info, context.allocator, &image)); - - return image; -} - -texture_handle gpu_texture_create(texture_desc desc, bool create_view, const void* data) { - VkDeviceSize image_size = desc.extents.x * desc.extents.y * 4; - // FIXME: handle this properly - VkFormat format = desc.format == CEL_TEXTURE_FORMAT_8_8_8_8_RGBA_UNORM ? VK_FORMAT_R8G8B8A8_SRGB - : VK_FORMAT_D32_SFLOAT; - - VkImage image; // vulkan_image_create(desc.extents, VK_IMAGE_TYPE_2D, format, - // VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); - VkDeviceMemory image_memory; - - VkImageCreateInfo image_create_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; - image_create_info.imageType = VK_IMAGE_TYPE_2D; - image_create_info.extent.width = desc.extents.x; - image_create_info.extent.height = desc.extents.y; - image_create_info.extent.depth = 1; - image_create_info.mipLevels = 1; - image_create_info.arrayLayers = 1; - image_create_info.format = format; - image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; - image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; - if (format == VK_FORMAT_D32_SFLOAT) { - image_create_info.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - } - image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; - - VK_CHECK( - vkCreateImage(context.device->logical_device, &image_create_info, context.allocator, &image)); - - VkMemoryRequirements memory_reqs; - vkGetImageMemoryRequirements(context.device->logical_device, image, &memory_reqs); - - VkMemoryAllocateInfo alloc_info = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; - alloc_info.allocationSize = memory_reqs.size; - alloc_info.memoryTypeIndex = - find_memory_index(memory_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - vkAllocateMemory(context.device->logical_device, &alloc_info, context.allocator, &image_memory); - - vkBindImageMemory(context.device->logical_device, image, image_memory, 0); - - texture_handle handle; - gpu_texture* texture = texture_pool_alloc(&context.resource_pools->textures, &handle); - DEBUG("Allocated texture with handle %d", handle.raw); - texture->handle = image; - texture->debug_label = "Test Texture"; - texture->desc = desc; - texture->memory = image_memory; - texture->size = image_size; - - if (data) { - TRACE("Uploading pixel data to texture using staging buffer"); - // Create a staging buffer - buffer_handle staging = - gpu_buffer_create(image_size, CEL_BUFFER_DEFAULT, CEL_BUFFER_FLAG_CPU, NULL); - // Copy data into it - vulkan_transition_image_layout(texture, format, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - buffer_upload_bytes(staging, (bytebuffer){ .buf = (u8*)data, .size = image_size }, 0, - image_size); - copy_buffer_to_image_oneshot(staging, handle); - vulkan_transition_image_layout(texture, format, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - - gpu_buffer_destroy(staging); - } - - // Texture View - if (create_view) { - VkImageViewCreateInfo view_create_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; - view_create_info.image = image; - view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; - view_create_info.format = format; - view_create_info.subresourceRange.aspectMask = - format == VK_FORMAT_D32_SFLOAT ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; - - view_create_info.subresourceRange.baseMipLevel = 0; - view_create_info.subresourceRange.levelCount = 1; - view_create_info.subresourceRange.baseArrayLayer = 0; - view_create_info.subresourceRange.layerCount = 1; - - VK_CHECK(vkCreateImageView(context.device->logical_device, &view_create_info, context.allocator, - &texture->view)); - } - - // Sampler - VkSamplerCreateInfo sampler_info = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; - sampler_info.magFilter = VK_FILTER_LINEAR; - sampler_info.minFilter = VK_FILTER_LINEAR; - sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; - sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; - sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; - sampler_info.anisotropyEnable = VK_TRUE; - sampler_info.maxAnisotropy = 16; - sampler_info.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; - sampler_info.unnormalizedCoordinates = VK_FALSE; - sampler_info.compareEnable = VK_FALSE; - sampler_info.compareOp = VK_COMPARE_OP_ALWAYS; - sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - sampler_info.mipLodBias = 0.0; - sampler_info.minLod = 0.0; - sampler_info.maxLod = 0.0; - - VkResult res = vkCreateSampler(context.device->logical_device, &sampler_info, context.allocator, - &texture->sampler); - if (res != VK_SUCCESS) { - ERROR("Error creating texture sampler for image %s", texture->debug_label); - exit(1); - } - - return handle; -} - -void vulkan_transition_image_layout(gpu_texture* texture, VkFormat format, VkImageLayout old_layout, - VkImageLayout new_layout) { - VkCommandBuffer temp_cmd_buffer = vulkan_command_buffer_create_oneshot(); - - VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; - barrier.oldLayout = old_layout; - barrier.newLayout = new_layout; - barrier.srcQueueFamilyIndex = context.device->queue_family_indicies.graphics_family_index; - barrier.dstQueueFamilyIndex = context.device->queue_family_indicies.graphics_family_index; - barrier.image = texture->handle; - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barrier.subresourceRange.baseMipLevel = 0; - barrier.subresourceRange.levelCount = 1; - barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = 1; - barrier.srcAccessMask = 0; // TODO - barrier.dstAccessMask = 0; // TODO - - VkPipelineStageFlags source_stage; - VkPipelineStageFlags dest_stage; - - if (old_layout == VK_IMAGE_LAYOUT_UNDEFINED && - new_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { - barrier.srcAccessMask = 0; - barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - - source_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - dest_stage = VK_PIPELINE_STAGE_TRANSFER_BIT; - - } else if (old_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && - new_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - source_stage = VK_PIPELINE_STAGE_TRANSFER_BIT; - dest_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - } else { - FATAL("Unsupported image layout transition"); - return; - } - - vkCmdPipelineBarrier(temp_cmd_buffer, source_stage, dest_stage, 0, 0, 0, 0, 0, 1, &barrier); - - vulkan_command_buffer_finish_oneshot(temp_cmd_buffer); -} - -/* TYPED_POOL(gpu_buffer, buffer); */ -/* TYPED_POOL(gpu_texture, texture); */ - -/* void resource_pools_init(arena* a, struct resource_pools* res_pools) { */ -/* buffer_pool buf_pool = buffer_pool_create(a, MAX_BUFFERS, sizeof(gpu_buffer)); */ -/* res_pools->buffers = buf_pool; */ -/* texture_pool tex_pool = texture_pool_create(a, MAX_TEXTURES, sizeof(gpu_texture)); */ -/* res_pools->textures = tex_pool; */ - -/* context.resource_pools = res_pools; */ -/* } */ - -#endif diff --git a/archive/src/render/archive/backends/vulkan/backend_vulkan.h b/archive/src/render/archive/backends/vulkan/backend_vulkan.h deleted file mode 100644 index 6ca0bb5..0000000 --- a/archive/src/render/archive/backends/vulkan/backend_vulkan.h +++ /dev/null @@ -1,118 +0,0 @@ -#pragma once -#include "defines.h" -#if defined(CEL_REND_BACKEND_VULKAN) -#include -#include -#include - -#include "mem.h" -#include "ral.h" -#include "ral_types.h" - -#define MAX_FRAMES_IN_FLIGHT 2 -#define GPU_SWAPCHAIN_IMG_COUNT 2 - -/* -Conventions: - - Place the 'handle' as the first field of a struct - - Vulkan specific data goes at the top, followed by our internal data -*/ - -typedef struct queue_family_indices { - u32 graphics_family_index; - u32 present_family_index; - u32 compute_family_index; - u32 transfer_family_index; - bool has_graphics; - bool has_present; - bool has_compute; - bool has_transfer; -} queue_family_indices; - -// typedef struct vulkan_framebuffer { -// } vulkan_framebuffer; - -typedef struct gpu_swapchain { - VkSwapchainKHR handle; - arena swapchain_arena; - VkExtent2D extent; - u32x2 dimensions; - VkSurfaceFormatKHR image_format; - VkPresentModeKHR present_mode; - u32 image_count; - VkImage* images; - VkImageView* image_views; -} gpu_swapchain; - -typedef struct gpu_device { - // In Vulkan we store both physical and logical device here - VkPhysicalDevice physical_device; - VkDevice logical_device; - VkPhysicalDeviceProperties properties; - VkPhysicalDeviceFeatures features; - VkPhysicalDeviceMemoryProperties memory; - queue_family_indices queue_family_indicies; - VkQueue graphics_queue; - VkQueue present_queue; - VkQueue compute_queue; - VkQueue transfer_queue; - VkCommandPool pool; -} gpu_device; - -typedef struct gpu_pipeline_layout { - VkPipelineLayout handle; -} gpu_pipeline_layout; - -typedef struct desc_set_uniform_buffer { - VkBuffer buffers[MAX_FRAMES_IN_FLIGHT]; - VkDeviceMemory uniform_buf_memorys[MAX_FRAMES_IN_FLIGHT]; - void* uniform_buf_mem_mappings[MAX_FRAMES_IN_FLIGHT]; - size_t size; -} desc_set_uniform_buffer; - -typedef struct gpu_pipeline { - VkPipeline handle; - VkPipelineLayout layout_handle; - - // Descriptor gubbins - shader_data data_layouts[MAX_SHADER_DATA_LAYOUTS]; - u32 data_layouts_count; - - VkDescriptorSetLayout* desc_set_layouts; - // Based on group, we know which data to load - desc_set_uniform_buffer* uniform_pointers; - u32 desc_set_layouts_count; - -} gpu_pipeline; - -typedef struct gpu_renderpass { - VkRenderPass handle; - // TODO: Where to store framebuffers? VkFramebuffer framebuffers[GPU_SWAPCHAIN_IMG_COUNT]; -} gpu_renderpass; - -typedef struct gpu_cmd_encoder { - VkCommandBuffer cmd_buffer; - VkDescriptorPool descriptor_pool; - gpu_pipeline* pipeline; -} gpu_cmd_encoder; - -typedef struct gpu_cmd_buffer { - VkCommandBuffer cmd_buffer; -} gpu_cmd_buffer; - -typedef struct gpu_buffer { - VkBuffer handle; - VkDeviceMemory memory; - u64 size; -} gpu_buffer; - -typedef struct gpu_texture { - VkImage handle; - VkDeviceMemory memory; - u64 size; - texture_desc desc; - VkImageView view; - VkSampler sampler; - char* debug_label; -} gpu_texture; -#endif \ No newline at end of file diff --git a/archive/src/render/immdraw.c b/archive/src/render/immdraw.c deleted file mode 100644 index 8a10c65..0000000 --- a/archive/src/render/immdraw.c +++ /dev/null @@ -1,176 +0,0 @@ -#include "immdraw.h" -#include "core.h" -#include "file.h" -#include "log.h" -#include "maths.h" -#include "maths_types.h" -#include "primitives.h" -#include "ral_common.h" -#include "ral_impl.h" -#include "ral_types.h" -#include "render.h" -#include "render_types.h" -#include "shader_layouts.h" - -void Immdraw_Init(Immdraw_Storage* storage) { - INFO("Immediate drawing initialisation"); - - // Meshes - Geometry sphere_geo = Geo_CreateUVsphere(1.0, 16, 16); - storage->sphere = Mesh_Create(&sphere_geo, true); - - Geometry cube_geo = Geo_CreateCuboid(f32x3(1.0, 1.0, 1.0)); - storage->cube = Mesh_Create(&cube_geo, true); - - Geometry plane_geo = Geo_CreatePlane(f32x2(1.0, 1.0), 1, 1); - storage->plane = Mesh_Create(&plane_geo, true); - - Geometry cone_geo = Geo_CreateCone(1.0, 1.0, 8); - storage->cone = Mesh_Create(&cone_geo, true); - - Geometry cyl_geo = Geo_CreateCylinder(1.0, 2.0, 8); - storage->cylinder = Mesh_Create(&cyl_geo, true); - - storage->bbox = GenBboxMesh(); - - // Pipeline / material - VertexDescription vertex_desc = { - .debug_label = "Immdraw Vertex", - .use_full_vertex_size = true, - }; - VertexDesc_AddAttr(&vertex_desc, "position", ATTR_F32x3); - VertexDesc_AddAttr(&vertex_desc, "normal", ATTR_F32x3); - - const char* vert_path = "assets/shaders/immdraw.vert"; - const char* frag_path = "assets/shaders/immdraw.frag"; - const char* vert_shader = string_from_file(vert_path); - const char* frag_shader = string_from_file(frag_path); - - ShaderDataLayout camera_data = Binding_Camera_GetLayout(NULL); - ShaderDataLayout imm_uniform_data = ImmediateUniforms_GetLayout(NULL); - - GraphicsPipelineDesc pipeline_desc = { - .debug_name = "Immediate Draw Pipeline", - .vertex_desc = static_3d_vertex_description(), - .data_layouts = { camera_data, imm_uniform_data }, - .data_layouts_count = 2, - .vs = { .debug_name = "Immdraw Vertex Shader", .filepath = vert_path, .code = vert_shader }, - .fs = { .debug_name = "Immdraw Fragment Shader", .filepath = frag_path, .code = frag_shader }, - .depth_test = true, - .wireframe = true, - }; - GPU_Renderpass* rpass = - GPU_Renderpass_Create((GPU_RenderpassDesc){ .default_framebuffer = true }); - storage->colour_pipeline = GPU_GraphicsPipeline_Create(pipeline_desc, rpass); -} - -void Immdraw_Shutdown(Immdraw_Storage* storage) { - GraphicsPipeline_Destroy(storage->colour_pipeline); -} - -void Immdraw_Sphere(Transform tf, Vec4 colour, bool wireframe) { - TRACE("Draw sphere"); - Immdraw_Storage* imm = Render_GetImmdrawStorage(); - Immdraw_Primitive(tf, CEL_TRI, 1.0, colour, wireframe, imm->sphere); -} -void Immdraw_Cuboid(Transform tf, Vec4 colour, bool wireframe) { - TRACE("Draw cube"); - Immdraw_Storage* imm = Render_GetImmdrawStorage(); - Immdraw_Primitive(tf, CEL_TRI, 1.0, colour, wireframe, imm->cube); -} -void Immdraw_Plane(Transform tf, Vec4 colour, bool wireframe) { - TRACE("Draw plane"); - Immdraw_Storage* imm = Render_GetImmdrawStorage(); - Immdraw_Primitive(tf, CEL_TRI, 1.0, colour, wireframe, imm->plane); -} - -void Immdraw_Bbox(Transform tf, Vec4 colour, bool wireframe) { - TRACE("Draw bbox"); - Immdraw_Storage* imm = Render_GetImmdrawStorage(); - Immdraw_Primitive(tf, CEL_LINE, 1.0, colour, wireframe, imm->bbox); -} - -void Immdraw_Cylinder(Transform tf, Vec4 colour, bool wireframe) { - TRACE("Draw cylinder"); - Immdraw_Storage* imm = Render_GetImmdrawStorage(); - Immdraw_Primitive(tf, CEL_TRI, 1.0, colour, wireframe, imm->cylinder); -} - -void Immdraw_Cone(Transform tf, Vec4 colour, bool wireframe) { - TRACE("Draw cone"); - Immdraw_Storage* imm = Render_GetImmdrawStorage(); - Immdraw_Primitive(tf, CEL_TRI, 1.0, colour, wireframe, imm->cone); -} - -void Immdraw_Primitive(Transform tf, PrimitiveTopology topology, f32 size, Vec4 colour, - bool wireframe, Mesh mesh) { - Immdraw_Storage* imm = Render_GetImmdrawStorage(); - GPU_CmdEncoder* enc = GPU_GetDefaultEncoder(); - - // begin renderpass - GPU_CmdEncoder_BeginRender(enc, imm->colour_pipeline->renderpass); - // bind pipeline - GPU_EncodeBindPipeline(enc, imm->colour_pipeline); - - // TODO: implement wireframe in other apis -#if defined(CEL_REND_BACKEND_OPENGL) -#include - if (wireframe) { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - } else { - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } -#endif - - // update uniforms - ImmediateUniforms uniforms = { - .model = transform_to_mat(&tf), - .colour = colour, - }; - Mat4 view, proj; - u32x2 dimensions = GPU_Swapchain_GetDimensions(); - RenderScene* scene = Render_GetScene(); - Camera_ViewProj(&scene->camera, (f32)dimensions.x, (f32)dimensions.y, &view, &proj); - Binding_Camera camera_data = { .view = view, - .projection = proj, - .viewPos = vec4(scene->camera.position.x, scene->camera.position.y, - scene->camera.position.z, 1.0) }; - GPU_EncodeBindShaderData(enc, 0, Binding_Camera_GetLayout(&camera_data)); - GPU_EncodeBindShaderData(enc, 1, ImmediateUniforms_GetLayout(&uniforms)); - - // draw call - GPU_EncodeSetVertexBuffer(enc, mesh.vertex_buffer); - GPU_EncodeSetIndexBuffer(enc, mesh.index_buffer); - GPU_EncodeDrawIndexed(enc, topology, mesh.geometry.index_count); - - // end renderpass - GPU_CmdEncoder_EndRender(enc); -} - -Mesh GenBboxMesh() { - Vertex_darray* vertices = Vertex_darray_new(8); - u32_darray* indices = u32_darray_new(24); - - // normals & uvs dont matter - VERT_3D(vertices, FRONT_BOT_LEFT, VEC3_NEG_Z, vec2(0, 0)); - VERT_3D(vertices, FRONT_BOT_RIGHT, VEC3_NEG_Z, vec2(0, 0)); - VERT_3D(vertices, BACK_BOT_LEFT, VEC3_NEG_Z, vec2(0, 0)); - VERT_3D(vertices, BACK_BOT_RIGHT, VEC3_NEG_Z, vec2(0, 0)); - VERT_3D(vertices, FRONT_TOP_LEFT, VEC3_NEG_Z, vec2(0, 0)); - VERT_3D(vertices, FRONT_TOP_RIGHT, VEC3_NEG_Z, vec2(0, 0)); - VERT_3D(vertices, BACK_TOP_LEFT, VEC3_NEG_Z, vec2(0, 0)); - VERT_3D(vertices, BACK_TOP_RIGHT, VEC3_NEG_Z, vec2(0, 0)); - - u32 line_indices[24] = { 0, 1, 2, 3, 0, 2, 1, 3, 4, 5, 6, 7, 4, 6, 5, 7, 0, 4, 1, 5, 2, 6, 3, 7 }; - for (u32 i = 0; i < 24; i++) { - u32_darray_push(indices, line_indices[i]); - } - - Geometry geo = { .format = VERTEX_STATIC_3D, - .has_indices = true, - .index_count = indices->len, - .vertices = vertices, - .indices = indices }; - - return Mesh_Create(&geo, true); -} diff --git a/archive/src/render/immdraw.h b/archive/src/render/immdraw.h deleted file mode 100644 index 2911350..0000000 --- a/archive/src/render/immdraw.h +++ /dev/null @@ -1,63 +0,0 @@ -/** - * @brief Immediate-mode drawing APIs - */ - -#pragma once -#include "defines.h" -#include "maths_types.h" -#include "ral_impl.h" -#include "ral_types.h" -#include "render_types.h" - -typedef struct Immdraw_Storage { - Mesh plane; - Mesh cube; - Mesh sphere; - Mesh cylinder; - Mesh cone; - Mesh bbox; - GPU_Pipeline* colour_pipeline; /** @brief Pipeline for drawing geometry that has vertex colours */ -} Immdraw_Storage; - -typedef struct ImmediateUniforms { - Mat4 model; - Vec4 colour; -} ImmediateUniforms; - -// --- Public API - -PUB void Immdraw_Init(Immdraw_Storage* storage); -PUB void Immdraw_Shutdown(Immdraw_Storage* storage); - -// These functions cause a pipeline switch and so aren't optimised for performance -PUB void Immdraw_Plane(Transform tf, Vec4 colour, bool wireframe); -PUB void Immdraw_Cuboid(Transform tf, Vec4 colour, bool wireframe); -PUB void Immdraw_Cylinder(Transform tf, Vec4 colour, bool wireframe); -PUB void Immdraw_Cone(Transform tf, Vec4 colour, bool wireframe); -PUB void Immdraw_Sphere(Transform tf, Vec4 colour, bool wireframe); -PUB void Immdraw_Bbox(Transform tf, Vec4 colour, bool wireframe); - -PUB void Immdraw_TransformGizmo(Transform tf, f32 size); - -// --- Internal - -void Immdraw_Primitive(Transform tf, PrimitiveTopology topology, f32 size, Vec4 colour, - bool wireframe, Mesh mesh); - -Mesh GenBboxMesh(); - -static ShaderDataLayout ImmediateUniforms_GetLayout(void* data) { - ImmediateUniforms* d = (ImmediateUniforms*)data; - bool has_data = data != NULL; - - ShaderBinding b1 = { .label = "ImmUniforms", - .kind = BINDING_BYTES, - // .vis = VISIBILITY_VERTEX, - .data.bytes.size = sizeof(ImmediateUniforms) }; - - if (has_data) { - b1.data.bytes.data = d; - } - - return (ShaderDataLayout){ .bindings = { b1 }, .binding_count = 1 }; -} diff --git a/archive/src/render/pbr.c b/archive/src/render/pbr.c deleted file mode 100644 index 4bad528..0000000 --- a/archive/src/render/pbr.c +++ /dev/null @@ -1,266 +0,0 @@ -#include "pbr.h" -#include "animation.h" -#include "camera.h" -#include "core.h" -#include "file.h" -#include "log.h" -#include "maths.h" -#include "mem.h" -#include "ral_common.h" -#include "ral_impl.h" -#include "ral_types.h" -#include "render.h" -#include "render_types.h" -#include "shader_layouts.h" - -void PBR_Init(PBR_Storage* storage) { - INFO("PBR shaders init"); - storage->pbr_pass = PBR_RPassCreate(); - PBR_PipelinesCreate(storage, storage->pbr_pass); -} - -GPU_Renderpass* PBR_RPassCreate() { - GPU_RenderpassDesc desc = { .default_framebuffer = true }; - return GPU_Renderpass_Create(desc); -} - -void PBR_PipelinesCreate(PBR_Storage* storage, GPU_Renderpass* rpass) { - // Common shader bindings - ShaderDataLayout camera_data = Binding_Camera_GetLayout(NULL); - ShaderDataLayout model_data = Binding_Model_GetLayout(NULL); - ShaderDataLayout material_data = PBRMaterial_GetLayout(NULL); - ShaderDataLayout lights_data = Binding_Lights_GetLayout(NULL); - - // Static - { - const char* vert_path = "assets/shaders/static_geometry.vert"; - const char* frag_path = "assets/shaders/pbr_textured.frag"; - char* vert_shader = string_from_file(vert_path); - char* frag_shader = string_from_file(frag_path); - - GraphicsPipelineDesc desc = { - .debug_name = "PBR (Static) Pipeline", - .vertex_desc = static_3d_vertex_description(), - .data_layouts = { camera_data, model_data, material_data, lights_data }, - .data_layouts_count = 4, - .vs = { .debug_name = "PBR (textured) Vertex Shader", - .filepath = str8(vert_path), - .code = vert_shader }, - .fs = { .debug_name = "PBR (textured) Fragment Shader", - .filepath = str8(frag_path), - .code = frag_shader }, - .depth_test = true, - .wireframe = true, - }; - storage->pbr_static_pipeline = GPU_GraphicsPipeline_Create(desc, rpass); - } - - // Skinned - { - const char* vert_path = "assets/shaders/skinned_geometry.vert"; - const char* frag_path = "assets/shaders/pbr_textured.frag"; - char* vert_shader = string_from_file(vert_path); - char* frag_shader = string_from_file(frag_path); - - ShaderDataLayout anim_uniform = AnimData_GetLayout(NULL); - - VertexDescription vertex_desc = { .debug_label = "Skinned vertices", - .use_full_vertex_size = true }; - VertexDesc_AddAttr(&vertex_desc, "inPosition", ATTR_F32x3); - VertexDesc_AddAttr(&vertex_desc, "inNormal", ATTR_F32x3); - VertexDesc_AddAttr(&vertex_desc, "inTexCoords", ATTR_F32x2); - VertexDesc_AddAttr(&vertex_desc, "inBoneIndices", ATTR_I32x4); - VertexDesc_AddAttr(&vertex_desc, "inWeights", ATTR_F32x4); - - GraphicsPipelineDesc desc = { - .debug_name = "PBR (Skinned) Pipeline", - .vertex_desc = vertex_desc, - .data_layouts = { camera_data, model_data, material_data, lights_data, anim_uniform }, - .data_layouts_count = 5, - .vs = { .debug_name = "PBR (textured) Vertex Shader", - .filepath = str8(vert_path), - .code = vert_shader }, - .fs = { .debug_name = "PBR (textured) Fragment Shader", - .filepath = str8(frag_path), - .code = frag_shader }, - .depth_test = true, - .wireframe = true, - }; - storage->pbr_skinned_pipeline = GPU_GraphicsPipeline_Create(desc, rpass); - } -} - -void PBR_Execute(PBR_Storage* storage, Camera camera, TextureHandle shadowmap_tex, - RenderEnt* entities, size_t entity_count) { - // 1. set up our pipeline - // 2. upload constant data (camera, lights) - // 3. draw each entity - // - upload material data -> in the future we will sort & batch by material - // - upload model transform - // - emit draw call - - GPU_CmdEncoder* enc = GPU_GetDefaultEncoder(); - GPU_CmdEncoder_BeginRender(enc, storage->pbr_pass); - - // TEMP: only do skinned - GPU_EncodeBindPipeline(enc, storage->pbr_skinned_pipeline); - - // Feed shader data - Mat4 view, proj; - u32x2 dimensions = GPU_Swapchain_GetDimensions(); - Camera_ViewProj(&camera, (f32)dimensions.x, (f32)dimensions.y, &view, &proj); - Binding_Camera camera_data = { .view = view, - .projection = proj, - .viewPos = vec4(camera.position.x, camera.position.y, - camera.position.z, 1.0) }; - GPU_EncodeBindShaderData(enc, 0, Binding_Camera_GetLayout(&camera_data)); - - Vec3 light_color = vec3(300.0, 300.0, 300.0); - Binding_Lights - lights_data = { .pointLights = { - // FIXME: add lights to our RenderScene structure. for now these are - // hardcoded - (pbr_point_light){ .pos = vec3(0.0, 6.0, 6.0), .color = light_color }, - (pbr_point_light){ .pos = vec3(-10, 10, 10), .color = light_color }, - (pbr_point_light){ .pos = vec3(10, -10, 10), .color = light_color }, - (pbr_point_light){ .pos = vec3(-10, -10, 10), .color = light_color }, - } }; - GPU_EncodeBindShaderData(enc, 3, Binding_Lights_GetLayout(&lights_data)); - - // TODO: Add shadowmap texture to uniforms - Mesh_pool* mesh_pool = Render_GetMeshPool(); - Material_pool* material_pool = Render_GetMaterialPool(); - - for (size_t ent_i = 0; ent_i < entity_count; ent_i++) { - RenderEnt renderable = entities[ent_i]; - Mesh* mesh = Mesh_pool_get(mesh_pool, renderable.mesh); - Material* mat = Material_pool_get(material_pool, renderable.material); - - // upload material data - PBRMaterialUniforms material_data = { .mat = *mat }; - GPU_EncodeBindShaderData(enc, 2, PBRMaterial_GetLayout(&material_data)); - - // upload model transform - Binding_Model model_data = { .model = renderable.affine }; - GPU_EncodeBindShaderData(enc, 1, Binding_Model_GetLayout(&model_data)); - - // Skinning matrices - - // 1. calculate matrices - AnimDataUniform anim_data = { 0 }; - CASSERT(renderable.armature); - Armature* skeleton = renderable.armature; - // Skip the first one as we assume its root for this test - for (int j_i = 1; j_i < skeleton->joints->len; j_i++) { - Joint* j = &skeleton->joints->data[j_i]; - j->local_transform = transform_to_mat(&j->transform_components); - Mat4 m = mat4_mult(j->local_transform, j->inverse_bind_matrix); - Joint* p = &skeleton->joints->data[j->parent]; - j->local_transform = mat4_mult(j->local_transform, p->local_transform); - printf("Quat %f \n", j->transform_components.rotation.z); - } - - // 2. bind and upload - for (int j_i = 1; j_i < skeleton->joints->len; j_i++) { - anim_data.bone_matrices[j_i] = skeleton->joints->data[j_i].local_transform; - } - GPU_EncodeBindShaderData(enc, 3, AnimData_GetLayout(&anim_data)); - - // set buffers - GPU_EncodeSetVertexBuffer(enc, mesh->vertex_buffer); - GPU_EncodeSetIndexBuffer(enc, mesh->index_buffer); - // draw - GPU_EncodeDrawIndexedTris(enc, mesh->geometry.index_count); - } - - GPU_CmdEncoder_EndRender(enc); -} - -void PBRMaterial_BindData(ShaderDataLayout* layout, const void* data) { - PBRMaterialUniforms* d = (PBRMaterialUniforms*)data; - CASSERT(data); - CASSERT(layout->binding_count == 5); - - TextureHandle white1x1 = Render_GetWhiteTexture(); - if (d->mat.albedo_map.raw != INVALID_TEX_HANDLE.raw) { - layout->bindings[0].data.texture.handle = d->mat.albedo_map; - } else { - layout->bindings[0].data.texture.handle = white1x1; - } - // TODO .. the rest -} - -ShaderDataLayout PBRMaterial_GetLayout(void* data) { - PBRMaterialUniforms* d = (PBRMaterialUniforms*)data; - bool has_data = data != NULL; - - ShaderBinding b1 = { - .label = "albedoMap", - .kind = BINDING_TEXTURE, - }; - ShaderBinding b2 = { - .label = "metallicRoughnessMap", - .kind = BINDING_TEXTURE, - }; - ShaderBinding b3 = { - .label = "aoMap", - .kind = BINDING_TEXTURE, - }; - ShaderBinding b4 = { - .label = "normalMap", - .kind = BINDING_TEXTURE, - }; - ShaderBinding b5 = { .label = "PBR_Params", - .kind = BINDING_BYTES, - .data.bytes.size = sizeof(PBR_Params) }; - - if (has_data) { - TextureHandle white1x1 = Render_GetWhiteTexture(); - if (d->mat.albedo_map.raw != INVALID_TEX_HANDLE.raw) { - b1.data.texture.handle = d->mat.albedo_map; - } else { - b1.data.texture.handle = white1x1; - } - - if (d->mat.metallic_roughness_map.raw != INVALID_TEX_HANDLE.raw) { - b2.data.texture.handle = d->mat.metallic_roughness_map; - } else { - b2.data.texture.handle = white1x1; - } - - if (d->mat.ambient_occlusion_map.raw != INVALID_TEX_HANDLE.raw) { - b3.data.texture.handle = d->mat.ambient_occlusion_map; - } else { - b3.data.texture.handle = white1x1; - } - - if (d->mat.normal_map.raw != INVALID_TEX_HANDLE.raw) { - b4.data.texture.handle = d->mat.normal_map; - } else { - b4.data.texture.handle = white1x1; - } - - arena* frame = Render_GetFrameArena(); - PBR_Params* params = arena_alloc(frame, sizeof(PBR_Params)); - params->albedo = d->mat.base_colour; - params->metallic = d->mat.metallic; - params->roughness = d->mat.roughness; - params->ambient_occlusion = d->mat.ambient_occlusion; - b5.data.bytes.data = params; - } - - return (ShaderDataLayout){ .bindings = { b1, b2, b3, b4, b5 }, .binding_count = 5 }; -} - -Material PBRMaterialDefault() { - return (Material){ .name = "Standard Material", - .kind = MAT_PBR, - .base_colour = vec3(1.0, 1.0, 1.0), - .metallic = 0.0, - .roughness = 0.5, - .ambient_occlusion = 0.0, - .albedo_map = INVALID_TEX_HANDLE, - .metallic_roughness_map = INVALID_TEX_HANDLE, - .normal_map = INVALID_TEX_HANDLE, - .ambient_occlusion_map = INVALID_TEX_HANDLE }; -} diff --git a/archive/src/render/pbr.h b/archive/src/render/pbr.h deleted file mode 100644 index 5a21533..0000000 --- a/archive/src/render/pbr.h +++ /dev/null @@ -1,70 +0,0 @@ -/** - * @file pbr.h - * @brief PBR render pass and uniforms - */ - -#pragma once -#include "backend_opengl.h" -#include "camera.h" -#include "defines.h" -#include "maths_types.h" -#include "ral_types.h" -#include "render_types.h" - -// --- Public API - -/** @brief Holds data for the PBR pipeline */ -typedef struct PBR_Storage { - GPU_Renderpass* pbr_pass; - GPU_Pipeline* pbr_static_pipeline; - GPU_Pipeline* pbr_skinned_pipeline; -} PBR_Storage; - -typedef struct PBRMaterialUniforms { - Material mat; -} PBRMaterialUniforms; - -/** @brief */ -PUB void PBR_Init(PBR_Storage* storage); - -// NOTE: For simplicity's sake we will render this pass directly to the default framebuffer -// internally this defers to `PBR_Execute()` -PUB void PBR_Run(PBR_Storage* storage - // light data - // camera - // geometry - // materials -); - -/** @brief Parameters that get passed as a uniform block to the PBR shader */ -typedef struct PBR_Params { - Vec3 albedo; - f32 metallic; - f32 roughness; - f32 ambient_occlusion; -} PBR_Params; - -/** @brief Textures that will get passed into the PBR shader if they're not `INVALID_TEX_HANDLE` */ -typedef struct PBR_Textures { - TextureHandle albedo_map; - TextureHandle normal_map; - bool metal_roughness_combined; - TextureHandle metallic_map; - TextureHandle roughness_map; - TextureHandle ao_map; -} PBR_Textures; - -/** @brief Returns a default white matte material */ -PUB Material PBRMaterialDefault(); - -PUB ShaderDataLayout PBRMaterial_GetLayout(void* data); - -// --- Internal - -GPU_Renderpass* PBR_RPassCreate(); /** @brief Create the PBR Renderpass */ - -void PBR_PipelinesCreate(PBR_Storage* storage, - GPU_Renderpass* rpass); /** @brief Create PBR Pipelines */ - -void PBR_Execute(PBR_Storage* storage, Camera camera, TextureHandle shadowmap_tex, - RenderEnt* entities, size_t entity_count); diff --git a/archive/src/render/render.c b/archive/src/render/render.c deleted file mode 100644 index af636a8..0000000 --- a/archive/src/render/render.c +++ /dev/null @@ -1,359 +0,0 @@ -/** - * @brief - */ - -#include "render.h" -#include -#include -#include -#include "camera.h" -#include "core.h" -#include "grid.h" -#include "immdraw.h" -#include "log.h" -#include "maths.h" -#include "maths_types.h" -#include "mem.h" -#include "pbr.h" -#include "ral_common.h" -#include "ral_impl.h" -#include "ral_types.h" -#include "render_types.h" -#include "shadows.h" -#include "terrain.h" - -#define STB_IMAGE_IMPLEMENTATION -#include - -#define FRAME_ARENA_SIZE MB(1) -#define POOL_SIZE_BYTES \ - MB(10) // we will reserve 10 megabytes up front to store resource, mesh, and material pools -#define MAX_MESHES 1024 -#define MAX_MATERIALS 256 - -extern Core g_core; - -struct Renderer { - struct GLFWwindow* window; - RendererConfig config; - GPU_Device device; - GPU_Swapchain swapchain; - GPU_Renderpass* default_renderpass; - bool frame_aborted; - RenderMode render_mode; - RenderScene scene; - PBR_Storage* pbr; - Shadow_Storage* shadows; - Terrain_Storage* terrain; - Grid_Storage* grid; - Immdraw_Storage* immediate; - // Text_Storage* text; - ResourcePools* resource_pools; - Mesh_pool mesh_pool; - Material_pool material_pool; - arena frame_arena; - TextureHandle white_1x1; - TextureHandle black_1x1; -}; - -Renderer* get_renderer() { return g_core.renderer; } - -bool Renderer_Init(RendererConfig config, Renderer* ren, GLFWwindow** out_window, - GLFWwindow* optional_window) { - INFO("Renderer init"); - ren->render_mode = RENDER_MODE_DEFAULT; - - ren->frame_arena = arena_create(malloc(FRAME_ARENA_SIZE), FRAME_ARENA_SIZE); - - // init resource pools - DEBUG("Initialise GPU resource pools"); - arena pool_arena = arena_create(malloc(POOL_SIZE_BYTES), POOL_SIZE_BYTES); - ren->resource_pools = arena_alloc(&pool_arena, sizeof(struct ResourcePools)); - ResourcePools_Init(&pool_arena, ren->resource_pools); - ren->mesh_pool = Mesh_pool_create(&pool_arena, MAX_MESHES, sizeof(Mesh)); - ren->material_pool = Material_pool_create(&pool_arena, MAX_MATERIALS, sizeof(Material)); - - // GLFW window creation - GLFWwindow* window; - if (optional_window != NULL) { - INFO("GLFWwindow pointer was provided!!!! Skipping generic glfw init.."); - window = optional_window; - } else { - INFO("No GLFWwindow provided - creating one"); - // NOTE: all platforms use GLFW at the moment but thats subject to change - glfwInit(); - -#if defined(CEL_REND_BACKEND_OPENGL) - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); -#elif defined(CEL_REND_BACKEND_VULKAN) - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); -#endif - - window = glfwCreateWindow(config.scr_width, config.scr_height, config.window_name, NULL, NULL); - INFO("Window created"); - if (window == NULL) { - ERROR("Failed to create GLFW window\n"); - glfwTerminate(); - return false; - } - } - - ren->window = window; - *out_window = window; - - glfwMakeContextCurrent(ren->window); - - DEBUG("Set up GLFW window callbacks"); - glfwSetWindowSizeCallback(window, Render_WindowSizeChanged); - - // set the RAL backend up - if (!GPU_Backend_Init(config.window_name, window, ren->resource_pools)) { - return false; - } - - GPU_Device_Create(&ren->device); - GPU_Swapchain_Create(&ren->swapchain); - - // set up default scene - Camera default_cam = - Camera_Create(vec3(0.0, 2.0, 4.0), vec3_normalise(vec3(0.0, -2.0, -4.0)), VEC3_Y, 45.0); - SetCamera(default_cam); - DirectionalLight default_light = { /* TODO */ }; - SetMainLight(default_light); - - // create our renderpasses - ren->shadows = malloc(sizeof(Shadow_Storage)); - Shadow_Init(ren->shadows, 1024, 1024); - - ren->pbr = calloc(1, sizeof(PBR_Storage)); - PBR_Init(ren->pbr); - - ren->terrain = calloc(1, sizeof(Terrain_Storage)); - Terrain_Init(ren->terrain); - - // FIXME - // ren->grid = calloc(1, sizeof(Grid_Storage)); - // Grid_Init(ren->grid); - - ren->immediate = calloc(1, sizeof(Immdraw_Storage)); - Immdraw_Init(ren->immediate); - - // load default textures - ren->white_1x1 = TextureLoadFromFile("assets/textures/white1x1.png"); - ren->black_1x1 = TextureLoadFromFile("assets/textures/black1x1.png"); - - return true; -} - -void Renderer_Shutdown(Renderer* ren) { - free(ren->shadows); - DEBUG("Freed Shadows storage"); - free(ren->pbr); - DEBUG("Freed PBR storage"); - free(ren->terrain); - DEBUG("Freed Terrain storage"); - free(ren->immediate); - DEBUG("Freed Immdraw storage"); - arena_free_storage(&ren->frame_arena); - DEBUG("Freed frame allocator buffer"); -} -size_t Renderer_GetMemReqs() { return sizeof(Renderer); } - -void Render_WindowSizeChanged(GLFWwindow* window, i32 new_width, i32 new_height) { - (void)window; - INFO("Window size changed callback"); - // Renderer* ren = Core_GetRenderer(&g_core); - GPU_Swapchain_Resize(new_width, new_height); -} - -void Render_FrameBegin(Renderer* ren) { - arena_free_all(&ren->frame_arena); - ren->frame_aborted = false; - if (!GPU_Backend_BeginFrame()) { - ren->frame_aborted = true; - WARN("Frame aborted"); - return; - } -} -void Render_FrameEnd(Renderer* ren) { - if (ren->frame_aborted) { - return; - } - - GPU_CmdEncoder* enc = GPU_GetDefaultEncoder(); - - GPU_Backend_EndFrame(); -} -void Render_RenderEntities(RenderEnt* entities, size_t entity_count) { - Renderer* ren = get_renderer(); - RenderScene scene = ren->scene; - - // FUTURE: Depth pre-pass - - Shadow_Storage* shadow_storage = Render_GetShadowStorage(); - shadow_storage->enabled = false; - TextureHandle sun_shadowmap = - shadow_storage->enabled ? Shadow_GetShadowMapTexture(shadow_storage) : INVALID_TEX_HANDLE; - - PBR_Execute(ren->pbr, scene.camera, sun_shadowmap, entities, entity_count); -} - -TextureData TextureDataLoad(const char* path, bool invert_y) { - TRACE("Load texture %s", path); - - // load the file data - int width, height, num_channels; - stbi_set_flip_vertically_on_load(invert_y); - -#pragma GCC diagnostic ignored "-Wpointer-sign" - char* data = stbi_load(path, &width, &height, &num_channels, 0); - if (data) { - DEBUG("loaded texture: %s", path); - } else { - WARN("failed to load texture"); - } - - // printf("width: %d height: %d num channels: %d\n", width, height, num_channels); - - unsigned int channel_type; - GPU_TextureFormat format; - if (num_channels == 4) { - channel_type = GL_RGBA; - format = TEXTURE_FORMAT_8_8_8_8_RGBA_UNORM; - } else { - channel_type = GL_RGB; - format = TEXTURE_FORMAT_8_8_8_RGB_UNORM; - } - TextureDesc desc = { - .extents = { width, height }, - .format = format, - .num_channels = num_channels, - .tex_type = TEXTURE_TYPE_2D, - }; - - return (TextureData){ .description = desc, .image_data = data }; -} - -TextureHandle TextureLoadFromFile(const char* path) { - TextureData tex_data = TextureDataLoad(path, false); - TextureHandle h = GPU_TextureCreate(tex_data.description, true, tex_data.image_data); - return h; -} - -Mesh Mesh_Create(Geometry* geometry, bool free_on_upload) { - Mesh m = { 0 }; - - // Create and upload vertex buffer - size_t vert_bytes = geometry->vertices->len * sizeof(Vertex); - INFO("Creating vertex buffer with size %d (%d x %d)", vert_bytes, geometry->vertices->len, - sizeof(Vertex)); - m.vertex_buffer = - GPU_BufferCreate(vert_bytes, BUFFER_VERTEX, BUFFER_FLAG_GPU, geometry->vertices->data); - - // Create and upload index buffer - if (geometry->has_indices) { - size_t index_bytes = geometry->indices->len * sizeof(u32); - INFO("Creating index buffer with size %d (len: %d)", index_bytes, geometry->indices->len); - m.index_buffer = - GPU_BufferCreate(index_bytes, BUFFER_INDEX, BUFFER_FLAG_GPU, geometry->indices->data); - } - - m.is_uploaded = true; - m.geometry = *geometry; // clone geometry data and store on Mesh struct - if (free_on_upload) { - Geometry_Destroy(geometry); - } - return m; -} - -void Geometry_Destroy(Geometry* geometry) { - if (geometry->indices) { - u32_darray_free(geometry->indices); - } - if (geometry->vertices) { - Vertex_darray_free(geometry->vertices); - } -} -PUB MeshHandle Mesh_Insert(Mesh* mesh) { return Mesh_pool_insert(Render_GetMeshPool(), mesh); } -PUB MaterialHandle Material_Insert(Material* material) { - return Material_pool_insert(Render_GetMaterialPool(), material); -} -Mesh* Mesh_Get(MeshHandle handle) { return Mesh_pool_get(Render_GetMeshPool(), handle); } - -void Mesh_DebugPrint(Mesh* mesh) { - printf("Mesh %d vertices %d indices %d joints \n", mesh->geometry.vertices->len, - mesh->geometry.indices->len); -} - -size_t ModelExtractRenderEnts(RenderEnt_darray* entities, ModelHandle model_handle, Mat4 affine, - RenderEntityFlags flags) { - Model* model = MODEL_GET(model_handle); - for (u32 i = 0; i < model->mesh_count; i++) { - Mesh* m = Mesh_pool_get(Render_GetMeshPool(), model->meshes[i]); - RenderEnt data = { .mesh = model->meshes[i], - .material = m->material, - .affine = affine, - // .bounding_box - .flags = flags }; - RenderEnt_darray_push(entities, data); - } - return model->mesh_count; // how many RenderEnts we pushed -} - -void SetCamera(Camera camera) { g_core.renderer->scene.camera = camera; } -void SetMainLight(DirectionalLight light) { g_core.renderer->scene.sun = light; } - -arena* GetRenderFrameArena(Renderer* r) { return &r->frame_arena; } - -RenderScene* Render_GetScene() { - Renderer* ren = Core_GetRenderer(&g_core); - return &ren->scene; -} - -Shadow_Storage* Render_GetShadowStorage() { - Renderer* ren = Core_GetRenderer(&g_core); - return ren->shadows; -} - -Terrain_Storage* Render_GetTerrainStorage() { - Renderer* ren = Core_GetRenderer(&g_core); - return ren->terrain; -} - -Grid_Storage* Render_GetGridStorage() { - Renderer* ren = Core_GetRenderer(&g_core); - return ren->grid; -} - -Immdraw_Storage* Render_GetImmdrawStorage() { - Renderer* ren = Core_GetRenderer(&g_core); - return ren->immediate; -} - -TextureHandle Render_GetWhiteTexture() { - Renderer* ren = Core_GetRenderer(&g_core); - return ren->white_1x1; -} - -/** @return an arena allocator that gets cleared at the beginning of every render frame */ -arena* Render_GetFrameArena() { - Renderer* ren = Core_GetRenderer(&g_core); - return &ren->frame_arena; -} - -Mesh_pool* Render_GetMeshPool() { - Renderer* ren = Core_GetRenderer(&g_core); - return &ren->mesh_pool; -} -Material_pool* Render_GetMaterialPool() { - Renderer* ren = Core_GetRenderer(&g_core); - return &ren->material_pool; -} - -void Render_SetRenderMode(RenderMode mode) { - Renderer* ren = Core_GetRenderer(&g_core); - ren->render_mode = mode; -} diff --git a/archive/src/render/render.h b/archive/src/render/render.h deleted file mode 100644 index d752f8b..0000000 --- a/archive/src/render/render.h +++ /dev/null @@ -1,151 +0,0 @@ -/** - * @brief - */ - -#pragma once -#include "camera.h" -#include "defines.h" -#include "grid.h" -#include "immdraw.h" -#include "maths_types.h" -#include "ral_types.h" -#include "render_types.h" -#include "shadows.h" - -typedef struct Renderer Renderer; -typedef struct GLFWwindow GLFWwindow; -typedef struct RendererConfig { - const char* window_name; - u32 scr_width, scr_height; - Vec3 clear_colour; -} RendererConfig; - -typedef struct RenderFlags { - bool wireframe; -} RenderFlags; - -typedef struct RenderCtx { - Mat4 view; - Mat4 projection; -} RenderCtx; - -/** @brief Holds globally bound data for rendering a scene. Typically held by the renderer. - * Whenever you call draw functions you can think of this as an implicit parameter. */ -typedef struct RenderScene { - Camera camera; - DirectionalLight sun; -} RenderScene; - -PUB void SetCamera(Camera camera); -PUB void SetMainLight(DirectionalLight light); - -// #define MESH_GET(h) (Mesh_pool_get(g_core.renderer->meshes, h)) -// #define MATERIAL_GET(h) (Material_pool_get(g_core.renderer->material, h)) - -// --- Lifecycle - -PUB bool Renderer_Init(RendererConfig config, Renderer* renderer, GLFWwindow** out_window, - GLFWwindow* optional_window); -PUB void Renderer_Shutdown(Renderer* renderer); -PUB size_t Renderer_GetMemReqs(); -void Render_WindowSizeChanged(GLFWwindow* window, i32 new_width, i32 new_height); - -// internal init functions -void DefaultPipelinesInit(Renderer* renderer); - -// NOTE: All of these functions grab the Renderer instance off the global Core -PUB void Render_FrameBegin(Renderer* renderer); -PUB void Render_FrameEnd(Renderer* renderer); - -/** @brief */ -PUB void Render_RenderEntities(RenderEnt* entities, size_t entity_count); - -// TODO: Render_FrameDraw(); - this will - -// --- Resources - -PUB TextureData TextureDataLoad(const char* path, bool invert_y); -PUB void TextureUpload(TextureHandle handle, size_t n_bytes, const void* data); -PUB TextureHandle TextureLoadFromFile(const char* path); -PUB ModelHandle ModelLoad(const char* debug_name, const char* filepath); - -// --- Rendering Data - -PUB Mesh Mesh_Create(Geometry* geometry, bool free_on_upload); -PUB void Mesh_Delete(Mesh* mesh); -Mesh* Mesh_Get(MeshHandle handle); -void Geometry_Destroy(Geometry* geometry); -MeshHandle Mesh_Insert(Mesh* mesh); -void Mesh_DebugPrint(Mesh* mesh); -MaterialHandle Material_Insert(Material* material); - -/** @brief gets render entities from a model and pushes them into a dynamic array for rendering */ -size_t ModelExtractRenderEnts(RenderEnt_darray* entities, ModelHandle model_handle, Mat4 affine, - RenderEntityFlags flags); - -// --- Drawing - -// NOTE: These functions use the globally bound camera in RenderScene -PUB void DrawMesh(Mesh* mesh, Material* material, Mat4 model); - -/** @brief the renderer does some internal bookkeeping for terrain so we use the terrain - stored on the Renderer rather than accept it as a parameter */ -PUB void Render_DrawTerrain(); - -// --- Getters (not in love with this but I'm finding keeping Renderer internals private to be okay) -arena* GetRenderFrameArena(Renderer* r); - -typedef struct RenderScene RenderScene; -typedef struct Shadow_Storage Shadow_Storage; -typedef struct Terrain_Storage Terrain_Storage; - -RenderScene* Render_GetScene(); -Shadow_Storage* Render_GetShadowStorage(); -Terrain_Storage* Render_GetTerrainStorage(); -Grid_Storage* Render_GetGridStorage(); -Immdraw_Storage* Render_GetImmdrawStorage(); -TextureHandle Render_GetWhiteTexture(); -arena* Render_GetFrameArena(); -Mesh_pool* Render_GetMeshPool(); -Material_pool* Render_GetMaterialPool(); - -// --- Setters -void Render_SetRenderMode(RenderMode mode); - -// ------------------------------------------------- - -// Frame lifecycle on CPU - -// 1. extract -// 2. culling -// 3. render -// 4. dispatch (combined with render for now) - -// typedef struct Cull_Result { -// u64 n_visible_objects; -// u64 n_culled_objects; -// u32* visible_ent_indices; // allocated on frame arena -// size_t index_count; -// } Cull_Result; - -// // everything that can be in the world, knows how to extract rendering data -// typedef void (*ExtractRenderData)(void* world_data); - -// typedef struct Renderer Renderer; - -// /** @brief Produces a smaller set of only those meshes visible in the camera frustum on the CPU -// */ Cull_Result Frame_Cull(Renderer* ren, RenderEnt* entities, size_t entity_count, Camera* -// camera); - -// Cull_Result Frame_Cull(Renderer* ren, RenderEnt* entities, size_t entity_count, Camera* camera) { -// // TODO: u32 chunk_count = Tpool_GetNumWorkers(); - -// arena* frame_arena = GetRenderFrameArena(ren); - -// Cull_Result result = { 0 }; -// result.visible_ent_indices = arena_alloc( -// frame_arena, sizeof(u32) * entity_count); // make space for if all ents are visible - -// assert((result.n_visible_objects + result.n_culled_objects == entity_count)); -// return result; -// } diff --git a/archive/src/render/render_types.h b/archive/src/render/render_types.h deleted file mode 100644 index bdf9849..0000000 --- a/archive/src/render/render_types.h +++ /dev/null @@ -1,138 +0,0 @@ -/** - * @brief - */ - -#pragma once -#include "animation.h" -#include "defines.h" -#include "maths_types.h" -#include "mem.h" -#include "ral_types.h" - -// --- Handles - -#define INVALID_MODEL_HANDLE ((ModelHandle){ .raw = 9999991 }) -#define INVALID_MATERIAL_HANDLE ((MaterialHandle){ .raw = 9999992 }) -#define INVALID_MESH_HANDLE ((MeshHandle){ .raw = 9999993 }) - -typedef enum RenderMode { - RENDER_MODE_DEFAULT, - RENDER_MODE_WIREFRAME, - RENDER_MODE_WIREFRAME_ON_LIT, - RENDER_MODE_COUNT -} RenderMode; - -typedef struct u32_opt { - u32 value; - bool has_value; -} u32_opt; - -typedef struct Mesh { - BufferHandle vertex_buffer; - BufferHandle index_buffer; - Geometry geometry; // NULL means it has been freed CPU-side - MaterialHandle material; - bool is_skinned; // false = its static - Armature armature; - bool is_uploaded; // has the data been uploaded to the GPU -} Mesh; -#ifndef TYPED_MESH_CONTAINERS -KITC_DECL_TYPED_ARRAY(Mesh) -TYPED_POOL(Mesh, Mesh) -#define TYPED_MESH_CONTAINERS -#endif - -typedef struct TextureData { - TextureDesc description; - void* image_data; -} TextureData; - -// --- Supported materials -typedef enum MaterialKind { - MAT_BLINN_PHONG, // NOTE: we're dropping support for this - MAT_PBR, // uses textures for PBR properties - MAT_PBR_PARAMS, // uses float values to represent a surface uniformly - MAT_COUNT -} MaterialKind; -static const char* material_kind_names[] = { "Blinn Phong", "PBR (Textures)", "PBR (Params)", - "Count (This should be an error)" }; - -/** - * @brief - * @note based on https://google.github.io/filament/Filament.html#materialsystem/standardmodel - */ -typedef struct Material { - char name[64]; - MaterialKind kind; // at the moment all materials are PBR materials - Vec3 base_colour; // linear RGB {0,0,0} to {1,1,1} - f32 metallic; - f32 roughness; - f32 ambient_occlusion; - TextureHandle albedo_map; - TextureHandle normal_map; - TextureHandle metallic_roughness_map; - TextureHandle ambient_occlusion_map; -} Material; - -#ifndef TYPED_MATERIAL_CONTAINERS -KITC_DECL_TYPED_ARRAY(Material) -TYPED_POOL(Material, Material) -#define TYPED_MATERIAL_CONTAINERS -#endif - -/** @brief Convenient wrapper around a number of meshes each with a material */ -typedef struct Model { - Str8 name; - MeshHandle* meshes; - size_t mesh_count; - MaterialHandle* materials; - size_t material_count; - arena anim_arena; - AnimationClip_darray* animations; -} Model; -#ifndef TYPED_MODEL_ARRAY -KITC_DECL_TYPED_ARRAY(Model) -#define TYPED_MODEL_ARRAY -#endif - -// TODO: function to create a model from a single mesh (like when using primitives) - -// --- Lights -typedef struct PointLight { - Vec3 position; - f32 constant, linear, quadratic; - Vec3 ambient; - Vec3 diffuse; - Vec3 specular; -} PointLight; - -typedef struct DirectionalLight { - Vec3 direction; - Vec3 ambient; - Vec3 diffuse; - Vec3 specular; -} DirectionalLight; - -// --- - -typedef enum RenderEntityFlag { - REND_ENT_CASTS_SHADOWS = 1 << 0, - REND_ENT_VISIBLE = 1 << 1, -} RenderEntityFlag; -typedef u32 RenderEntityFlags; - -/** @brief A renderable 'thing' */ -typedef struct RenderEnt { - MeshHandle mesh; - MaterialHandle material; - /** If NULL, no armature and the mesh is static geometry, else it is to be skinned */ - Armature* armature; - Mat4 affine; // In the future this should be updated by the transform graph - Bbox_3D bounding_box; - RenderEntityFlags flags; -} RenderEnt; - -#ifndef TYPED_RENDERENT_ARRAY -KITC_DECL_TYPED_ARRAY(RenderEnt) -#define TYPED_RENDERENT_ARRAY -#endif diff --git a/archive/src/render/shader_layouts.h b/archive/src/render/shader_layouts.h deleted file mode 100644 index ef94c89..0000000 --- a/archive/src/render/shader_layouts.h +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once -#include "maths_types.h" -#include "ral_types.h" - -/** @brief shader layout for camera matrices */ -typedef struct Binding_Camera { - Mat4 view; - Mat4 projection; - Vec4 viewPos; -} Binding_Camera; - -typedef struct Binding_Model { - Mat4 model; -} Binding_Model; - -/** @brief data that is handy to have in any shader */ -typedef struct Binding_Globals { -} Binding_Globals; - -typedef struct pbr_point_light { - Vec3 pos; - f32 pad; - Vec3 color; - f32 pad2; -} pbr_point_light; - -typedef struct Binding_Lights { - pbr_point_light pointLights[4]; -} Binding_Lights; - -static ShaderDataLayout Binding_Camera_GetLayout(void* data) { - Binding_Camera* d = data; - bool has_data = data != NULL; - - ShaderBinding b1 = { .label = "Camera", - .kind = BINDING_BYTES, - .data.bytes = { .size = sizeof(Binding_Camera) } }; - if (has_data) { - b1.data.bytes.data = d; - } - return (ShaderDataLayout){ .bindings = { b1 }, .binding_count = 1 }; -} - -static ShaderDataLayout Binding_Model_GetLayout(void* data) { - Binding_Model* d = data; - bool has_data = data != NULL; - - ShaderBinding b1 = { .label = "Model", - .kind = BINDING_BYTES, - .vis = VISIBILITY_VERTEX, - .data.bytes = { .size = sizeof(Binding_Model) } }; - if (has_data) { - b1.data.bytes.data = d; - } - return (ShaderDataLayout){ .bindings = { b1 }, .binding_count = 1 }; -} - -static ShaderDataLayout Binding_Lights_GetLayout(void* data) { - Binding_Lights* d = data; - bool has_data = data != NULL; - - ShaderBinding b1 = { .label = "Lights", - .kind = BINDING_BYTES, - .vis = VISIBILITY_FRAGMENT, - .data.bytes = { .size = sizeof(Binding_Lights) } }; - if (has_data) { - b1.data.bytes.data = d; - } - return (ShaderDataLayout){ .bindings = { b1 }, .binding_count = 1 }; -} diff --git a/archive/src/render/shadows.c b/archive/src/render/shadows.c deleted file mode 100644 index 029eefb..0000000 --- a/archive/src/render/shadows.c +++ /dev/null @@ -1,211 +0,0 @@ -#include "shadows.h" -#include -#include "file.h" -#include "glad/glad.h" -#include "log.h" -#include "maths.h" -#include "maths_types.h" -#include "primitives.h" -#include "ral_common.h" -#include "ral_impl.h" -#include "ral_types.h" -#include "render.h" -#include "render_types.h" -#include "str.h" - -ShaderDataLayout ShadowUniforms_GetLayout(void* data) { - ShadowUniforms* d = (ShadowUniforms*)data; - bool has_data = data != NULL; - - ShaderBinding b1 = { - .label = "ShadowUniforms", - .kind = BINDING_BYTES, - .vis = VISIBILITY_VERTEX, - .data = { .bytes = { .size = sizeof(ShadowUniforms) } } - // TODO: split this into two bindings so we can update model matrix independently - }; - - if (has_data) { - b1.data.bytes.data = data; - } - - return (ShaderDataLayout){ .binding_count = 1, .bindings = { b1 } }; -} - -ShaderDataLayout ShadowDebugQuad_GetLayout(void* data) { - TextureHandle* handle = data; - bool has_data = data != NULL; - - ShaderBinding b1 = { - .label = "depthMap", - .kind = BINDING_TEXTURE, - .vis = VISIBILITY_FRAGMENT, - }; - - if (has_data) { - b1.data.texture.handle = *handle; - } - - return (ShaderDataLayout){ .binding_count = 1, .bindings = { b1 } }; -} - -void Shadow_Init(Shadow_Storage* storage, u32 shadowmap_width, u32 shadowmap_height) { - memset(storage, 0, sizeof(Shadow_Storage)); - arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024); - - TextureDesc depthmap_desc = { .extents = u32x2(shadowmap_width, shadowmap_height), - .format = TEXTURE_FORMAT_DEPTH_DEFAULT, - .tex_type = TEXTURE_TYPE_2D }; - DEBUG("Creating depth map texture for shadows"); - TextureHandle depthmap = GPU_TextureCreate(depthmap_desc, false, NULL); - storage->depth_texture = depthmap; - - // -- shadowmap drawing pass - GPU_RenderpassDesc rpass_desc = { .default_framebuffer = false, - .has_color_target = false, - .has_depth_stencil = true, - .depth_stencil = depthmap }; - - storage->shadowmap_pass = GPU_Renderpass_Create(rpass_desc); - - WARN("About to laod shaders"); - WARN("Shader paths: %s %s", "assets/shaders/shadows.vert", "assets/shaders/shadows.frag"); - Str8 vert_path = str8("assets/shaders/shadows.vert"); - Str8 frag_path = str8("assets/shaders/shadows.frag"); - str8_opt vertex_shader = str8_from_file(&scratch, vert_path); - str8_opt fragment_shader = str8_from_file(&scratch, frag_path); - if (!vertex_shader.has_value || !fragment_shader.has_value) { - ERROR_EXIT("Failed to load shaders from disk"); - } - - ShaderDataLayout uniforms = ShadowUniforms_GetLayout(NULL); - - GraphicsPipelineDesc pipeline_desc = { - .debug_name = "Shadows Pipeline", - .vertex_desc = static_3d_vertex_description(), - .data_layouts = { uniforms }, - .data_layouts_count = 1, - .vs = { .debug_name = "Shadows Vert shader", - .filepath = vert_path, - .code = vertex_shader.contents, - .is_spirv = false }, - .fs = { .debug_name = "Shadows Frag shader", - .filepath = frag_path, - .code = fragment_shader.contents, - .is_spirv = false }, - }; - storage->shadowmap_pipeline = GPU_GraphicsPipeline_Create(pipeline_desc, storage->shadowmap_pass); - - // -- debug quad pipeline - GPU_RenderpassDesc debug_pass_desc = { .default_framebuffer = true }; - storage->debugquad_pass = GPU_Renderpass_Create(debug_pass_desc); - - vert_path = str8("assets/shaders/debug_quad.vert"); - frag_path = str8("assets/shaders/debug_quad.frag"); - vertex_shader = str8_from_file(&scratch, vert_path); - fragment_shader = str8_from_file(&scratch, frag_path); - if (!vertex_shader.has_value || !fragment_shader.has_value) { - ERROR_EXIT("Failed to load shaders from disk"); - } - - ShaderDataLayout debugquad_uniforms = ShadowDebugQuad_GetLayout(NULL); - - GraphicsPipelineDesc debugquad_pipeline_desc = { - .debug_name = "Shadows debug quad Pipeline", - .vertex_desc = static_3d_vertex_description(), - .data_layouts = { debugquad_uniforms }, - .data_layouts_count = 1, - .vs = { .debug_name = "depth debug quad vert shader", - .filepath = vert_path, - .code = vertex_shader.contents, - .is_spirv = false }, - .fs = { .debug_name = "depth debug quad frag shader", - .filepath = frag_path, - .code = fragment_shader.contents, - .is_spirv = false }, - }; - storage->debugquad_pipeline = - GPU_GraphicsPipeline_Create(debugquad_pipeline_desc, storage->debugquad_pass); - - Geometry quad_geo = Geo_CreatePlane(f32x2(1, 1), 1, 1); - // HACK: Swap vertices to make it face us - Vertex top0 = quad_geo.vertices->data[0]; - quad_geo.vertices->data[0] = quad_geo.vertices->data[2]; - quad_geo.vertices->data[2] = top0; - Vertex top1 = quad_geo.vertices->data[1]; - quad_geo.vertices->data[1] = quad_geo.vertices->data[3]; - quad_geo.vertices->data[3] = top1; - storage->quad = Mesh_Create(&quad_geo, false); - - arena_free_storage(&scratch); -} - -void Shadow_Run(RenderEnt* entities, size_t entity_count) { - Shadow_Storage* shadow_storage = Render_GetShadowStorage(); - - // calculations - RenderScene* render_scene = Render_GetScene(); - f32 near_plane = 1.0, far_plane = 10.0; - // -- Not sure about how we want to handle lights - Vec3 light_position = { 1, 4, -1 }; - // -- - Mat4 light_projection = mat4_orthographic(-10.0, 10.0, -10.0, 10.0, near_plane, far_plane); - Mat4 light_view = mat4_look_at(light_position, VEC3_ZERO, VEC3_Y); - Mat4 light_space_matrix = mat4_mult(light_view, light_projection); - - Shadow_ShadowmapExecute(shadow_storage, light_space_matrix, entities, entity_count); -} - -void Shadow_DrawDebugQuad() { - Shadow_Storage* shadow_storage = Render_GetShadowStorage(); - - GPU_CmdEncoder* enc = GPU_GetDefaultEncoder(); - GPU_CmdEncoder_BeginRender(enc, shadow_storage->debugquad_pass); - - GPU_EncodeBindPipeline(enc, shadow_storage->debugquad_pipeline); - ShaderDataLayout quad_data = ShadowDebugQuad_GetLayout(&shadow_storage->depth_texture); - GPU_EncodeBindShaderData(enc, 0, quad_data); - GPU_EncodeSetVertexBuffer(enc, shadow_storage->quad.vertex_buffer); - GPU_EncodeSetIndexBuffer(enc, shadow_storage->quad.index_buffer); - GPU_EncodeDrawIndexedTris(enc, shadow_storage->quad.geometry.indices->len); - - GPU_CmdEncoder_EndRender(enc); -} - -void Shadow_ShadowmapExecute(Shadow_Storage* storage, Mat4 light_space_transform, - RenderEnt* entities, size_t entity_count) { - GPU_CmdEncoder shadow_encoder = GPU_CmdEncoder_Create(); - - GPU_CmdEncoder_BeginRender(&shadow_encoder, storage->shadowmap_pass); - // DEBUG("Begin shadowmap renderpass"); - - // FIXME: shouldnt be gl specific - glClear(GL_DEPTH_BUFFER_BIT); - - GPU_EncodeBindPipeline(&shadow_encoder, storage->shadowmap_pipeline); - - ShadowUniforms uniforms = { - .light_space = light_space_transform, - .model = mat4_ident() // this will be overwritten for each Model - }; - ShaderDataLayout shader_data = ShadowUniforms_GetLayout(&uniforms); - - for (size_t ent_i = 0; ent_i < entity_count; ent_i++) { - RenderEnt renderable = entities[ent_i]; - if (renderable.flags && REND_ENT_CASTS_SHADOWS) { - // Model* model = MODEL_GET(renderable.model); - - uniforms.model = renderable.affine; // update the model transform - - Mesh* mesh = Mesh_pool_get(Render_GetMeshPool(), renderable.mesh); - GPU_EncodeBindShaderData(&shadow_encoder, 0, shader_data); - GPU_EncodeSetVertexBuffer(&shadow_encoder, mesh->vertex_buffer); - GPU_EncodeSetIndexBuffer(&shadow_encoder, mesh->index_buffer); - GPU_EncodeDrawIndexedTris(&shadow_encoder, mesh->geometry.indices->len); - } - } - - GPU_CmdEncoder_EndRender(&shadow_encoder); // end renderpass -} - -TextureHandle Shadow_GetShadowMapTexture(Shadow_Storage* storage) { return storage->depth_texture; } diff --git a/archive/src/render/shadows.h b/archive/src/render/shadows.h deleted file mode 100644 index 0482d10..0000000 --- a/archive/src/render/shadows.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @brief Functions for adding shadows to scene rendering. - */ - -#pragma once -#include "defines.h" -#include "ral_impl.h" -#include "ral_types.h" -#include "render_types.h" - -typedef struct Shadow_Storage { - bool enabled; - GPU_Renderpass* shadowmap_pass; - GPU_Pipeline* shadowmap_pipeline; - TextureHandle depth_texture; - bool debug_quad_enabled; - Mesh quad; - GPU_Renderpass* debugquad_pass; - GPU_Pipeline* debugquad_pipeline; - // TODO: Some statistics tracking -} Shadow_Storage; - -typedef struct ShadowUniforms { - Mat4 light_space; - Mat4 model; -} ShadowUniforms; - -typedef struct Camera Camera; -typedef struct Mat4 Mat4; - -// --- Public API -PUB void Shadow_Init(Shadow_Storage* storage, u32 shadowmap_width, u32 shadowmap_height); - -/** @brief Run shadow map generation for given entities, and store in a texture. - * @note Uses active directional light for now */ -PUB void Shadow_Run(RenderEnt* entities, size_t entity_count); - -PUB void Shadow_DrawDebugQuad(); - -/** @brief Get the shadow texture generated from shadowmap pass */ -PUB TextureHandle Shadow_GetShadowMapTexture(Shadow_Storage* storage); - -// --- Internal -GPU_Renderpass* Shadow_RPassCreate(); // Creates the render pass -GPU_Pipeline* Shadow_PipelineCreate(GPU_Renderpass* rpass); // Creates the pipeline -void Shadow_ShadowmapExecute(Shadow_Storage* storage, Mat4 light_space_transform, - RenderEnt* entities, size_t entity_count); -void Shadow_RenderDebugQuad(); diff --git a/archive/src/render/skybox.c b/archive/src/render/skybox.c deleted file mode 100644 index b4e1e42..0000000 --- a/archive/src/render/skybox.c +++ /dev/null @@ -1,161 +0,0 @@ -#include "skybox.h" -#include -#include "file.h" -#include "glad/glad.h" -#include "log.h" -#include "maths.h" -#include "primitives.h" -#include "ral_common.h" -#include "ral_impl.h" -#include "ral_types.h" -#include "render.h" -#include "render_types.h" -#include "shader_layouts.h" - -float skyboxVertices[] = { - // positions - -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, - 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, - - -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, - -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, - - 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, - - -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, - - -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, - - -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, - 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f -}; - -static const char* faces[6] = { "assets/demo/skybox/right.jpg", "assets/demo/skybox/left.jpg", - "assets/demo/skybox/top.jpg", "assets/demo/skybox/bottom.jpg", - "assets/demo/skybox/front.jpg", "assets/demo/skybox/back.jpg" }; - -Skybox Skybox_Create(const char** face_paths, int n) { - INFO("Creating a skybox"); - CASSERT_MSG( - n == 6, - "We only support full cubemaps for now"); // ! we're only supporting a full cubemap for now - - // -- cube verts - Geometry geom = { .format = VERTEX_POS_ONLY, // doesnt matter - .has_indices = false, - .indices = NULL, - .vertices = Vertex_darray_new(36) }; - for (u32 i = 0; i < (36 * 3); i += 3) { - Vertex_darray_push( - geom.vertices, - (Vertex){ .pos_only = { .position = vec3(skyboxVertices[i], skyboxVertices[i + 1], - skyboxVertices[i + 2]) } }); - } - Mesh cube = Mesh_Create(&geom, false); - - // -- cubemap texture - TextureHandle handle; - GPU_Texture* tex = GPU_TextureAlloc(&handle); - glBindTexture(GL_TEXTURE_CUBE_MAP, tex->id); - - for (unsigned int i = 0; i < n; i++) { - TextureData data = TextureDataLoad(face_paths[i], false); - assert(data.description.format == TEXTURE_FORMAT_8_8_8_RGB_UNORM); - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, data.description.extents.x, - data.description.extents.y, 0, GL_RGB, GL_UNSIGNED_BYTE, data.image_data); - } - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - - // shader pipeline - GPU_RenderpassDesc rpass_desc = { - .default_framebuffer = true, - }; - GPU_Renderpass* pass = GPU_Renderpass_Create(rpass_desc); - - arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024); - - Str8 vert_path = str8("assets/shaders/skybox.vert"); - Str8 frag_path = str8("assets/shaders/skybox.frag"); - str8_opt vertex_shader = str8_from_file(&scratch, vert_path); - str8_opt fragment_shader = str8_from_file(&scratch, frag_path); - if (!vertex_shader.has_value || !fragment_shader.has_value) { - ERROR_EXIT("Failed to load shaders from disk") - } - - ShaderDataLayout camera_data = Binding_Camera_GetLayout(NULL); - ShaderDataLayout shader_data = Skybox_GetLayout(NULL); - - VertexDescription builder = { .debug_label = "pos only" }; - VertexDesc_AddAttr(&builder, "inPosition", ATTR_F32x3); - builder.use_full_vertex_size = true; - - GraphicsPipelineDesc pipeline_desc = { - .debug_name = "Skybox pipeline", - .vertex_desc = builder, - .data_layouts = { shader_data, camera_data }, - .data_layouts_count = 2, - .vs = { .debug_name = "Skybox Vertex Shader", - .filepath = vert_path, - .code = vertex_shader.contents }, - .fs = { .debug_name = "Skybox Fragment Shader", - .filepath = frag_path, - .code = fragment_shader.contents }, - .wireframe = false, - .depth_test = true, - }; - - GPU_Pipeline* pipeline = GPU_GraphicsPipeline_Create(pipeline_desc, pass); - - return (Skybox){ .cube = cube, .texture = handle, .pipeline = pipeline }; -} - -Skybox Skybox_Default() { return Skybox_Create(faces, 6); } - -void Skybox_Draw(Skybox* skybox, Camera camera) { - GPU_CmdEncoder* enc = GPU_GetDefaultEncoder(); - glDepthFunc(GL_LEQUAL); - GPU_CmdEncoder_BeginRender(enc, skybox->pipeline->renderpass); - GPU_EncodeBindPipeline(enc, skybox->pipeline); - GPU_EncodeSetDefaults(enc); - - // Shader data - - Mat4 view, proj; - u32x2 dimensions = GPU_Swapchain_GetDimensions(); - Camera_ViewProj(&camera, dimensions.x, dimensions.y, &view, &proj); - Mat4 new = mat4_ident(); - new.data[0] = view.data[0]; - new.data[1] = view.data[1]; - new.data[2] = view.data[2]; - new.data[4] = view.data[4]; - new.data[5] = view.data[5]; - new.data[6] = view.data[6]; - new.data[8] = view.data[8]; - new.data[9] = view.data[9]; - new.data[10] = view.data[10]; - - Binding_Camera camera_data = { .view = new, - .projection = proj, - .viewPos = vec4(camera.position.x, camera.position.y, - camera.position.z, 1.0) }; - GPU_EncodeBindShaderData(enc, 0, Binding_Camera_GetLayout(&camera_data)); - - SkyboxUniforms uniforms = { .cubemap = skybox->texture }; - ShaderDataLayout skybox_data = Skybox_GetLayout(&uniforms); - GPU_EncodeBindShaderData(enc, 0, skybox_data); - - GPU_EncodeSetVertexBuffer(enc, skybox->cube.vertex_buffer); - GPU_EncodeSetIndexBuffer(enc, skybox->cube.index_buffer); - - GPU_EncodeDrawTris(enc, 36); - - GPU_CmdEncoder_EndRender(enc); - glDepthFunc(GL_LESS); -} diff --git a/archive/src/render/skybox.h b/archive/src/render/skybox.h deleted file mode 100644 index c2ef3a2..0000000 --- a/archive/src/render/skybox.h +++ /dev/null @@ -1,41 +0,0 @@ -/** - * @brief - */ - -#pragma once -#include "camera.h" -#include "defines.h" -#include "ral_impl.h" -#include "render_types.h" - -typedef struct Skybox { - Mesh cube; - TextureHandle texture; - GPU_Pipeline* pipeline; // "shader" -} Skybox; - -PUB Skybox Skybox_Create(const char** face_paths, int n); // should always pass n = 6 for now - -PUB void Skybox_Draw(Skybox* skybox, Camera camera); - -typedef struct SkyboxUniforms { - TextureHandle cubemap; -} SkyboxUniforms; - -static ShaderDataLayout Skybox_GetLayout(void* data) { - SkyboxUniforms* d = (SkyboxUniforms*)data; // cold cast - bool has_data = data != NULL; - - ShaderBinding b1 = { - .label = "cubeMap", - .vis = VISIBILITY_FRAGMENT, - .kind = BINDING_TEXTURE, - }; - - if (has_data) { - b1.data.texture.handle = d->cubemap; - } - return (ShaderDataLayout){ .bindings = { b1 }, .binding_count = 1 }; -} - -Skybox Skybox_Default(); \ No newline at end of file diff --git a/archive/src/resources/gltf.c b/archive/src/resources/gltf.c deleted file mode 100644 index 66ae1b6..0000000 --- a/archive/src/resources/gltf.c +++ /dev/null @@ -1,596 +0,0 @@ -#include -#include -#include -#include "animation.h" -#include "colours.h" -#include "core.h" -#include "defines.h" -#include "file.h" -#include "loaders.h" -#include "log.h" -#include "maths.h" -#include "maths_types.h" -#include "mem.h" -#include "pbr.h" -#include "platform.h" -#include "ral_types.h" -#include "render.h" -#include "render_types.h" -#include "str.h" - -#define CGLTF_IMPLEMENTATION -#include - -extern Core g_core; - -/* GLTF Loading Pipeline - ===================== */ - -struct face { - cgltf_uint indices[3]; -}; -typedef struct face face; - -KITC_DECL_TYPED_ARRAY(Vec3) -KITC_DECL_TYPED_ARRAY(Vec2) -KITC_DECL_TYPED_ARRAY(Vec4u) -KITC_DECL_TYPED_ARRAY(Vec4i) -KITC_DECL_TYPED_ARRAY(Vec4) -KITC_DECL_TYPED_ARRAY(face) -KITC_DECL_TYPED_ARRAY(i32) - -size_t GLTF_LoadMaterials(cgltf_data* data, Str8 relative_path, Material_darray* out_materials); - -ModelHandle ModelLoad_gltf(const char* path, bool invert_texture_y) { - size_t arena_size = MB(1); - arena scratch = arena_create(malloc(arena_size), arena_size); - - TRACE("Loading model at Path %s\n", path); - path_opt relative_path = path_parent(&scratch, path); - if (!relative_path.has_value) { - WARN("Couldnt get a relative path for the path to use for loading materials & textures later"); - } - const char* file_string = string_from_file(path); - - ModelHandle handle; - Model* model = Model_pool_alloc(&g_core.models, &handle); - model->name = Str8_cstr_view(path); - - bool success = - model_load_gltf_str(file_string, path, relative_path.path, model, invert_texture_y); - - if (!success) { - FATAL("Couldnt load GLTF file at path %s", path); - ERROR_EXIT("Load fails are considered crash-worthy right now. This will change later.\n"); - } - - arena_free_all(&scratch); - arena_free_storage(&scratch); - return handle; -} - -void assert_path_type_matches_component_type(cgltf_animation_path_type target_path, - cgltf_accessor* output) { - if (target_path == cgltf_animation_path_type_rotation) { - assert(output->component_type == cgltf_component_type_r_32f); - assert(output->type == cgltf_type_vec4); - } -} - -// TODO: Brainstorm how I can make this simpler and break it up into more testable pieces - -void load_position_components(Vec3_darray* positions, cgltf_accessor* accessor) { - TRACE("Loading %d vec3 position components", accessor->count); - CASSERT_MSG(accessor->component_type == cgltf_component_type_r_32f, - "Positions components are floats"); - CASSERT_MSG(accessor->type == cgltf_type_vec3, "Vertex positions should be a vec3"); - - for (cgltf_size v = 0; v < accessor->count; ++v) { - Vec3 pos; - cgltf_accessor_read_float(accessor, v, &pos.x, 3); - Vec3_darray_push(positions, pos); - } -} - -void load_normal_components(Vec3_darray* normals, cgltf_accessor* accessor) { - TRACE("Loading %d vec3 normal components", accessor->count); - CASSERT_MSG(accessor->component_type == cgltf_component_type_r_32f, - "Normal vector components are floats"); - CASSERT_MSG(accessor->type == cgltf_type_vec3, "Vertex normals should be a vec3"); - - for (cgltf_size v = 0; v < accessor->count; ++v) { - Vec3 pos; - cgltf_accessor_read_float(accessor, v, &pos.x, 3); - Vec3_darray_push(normals, pos); - } -} - -void load_texcoord_components(Vec2_darray* texcoords, cgltf_accessor* accessor) { - TRACE("Load texture coordinates from accessor"); - CASSERT(accessor->component_type == cgltf_component_type_r_32f); - CASSERT_MSG(accessor->type == cgltf_type_vec2, "Texture coordinates should be a vec2"); - - for (cgltf_size v = 0; v < accessor->count; ++v) { - Vec2 tex; - bool success = cgltf_accessor_read_float(accessor, v, &tex.x, 2); - if (!success) { - ERROR("Error loading tex coord"); - } - Vec2_darray_push(texcoords, tex); - } -} - -void load_joint_index_components(Vec4i_darray* joint_indices, cgltf_accessor* accessor) { - TRACE("Load joint indices from accessor"); - CASSERT(accessor->component_type == cgltf_component_type_r_16u); - CASSERT_MSG(accessor->type == cgltf_type_vec4, "Joint indices should be a vec4"); - Vec4i tmp_joint_index; - Vec4 joints_as_floats; - for (cgltf_size v = 0; v < accessor->count; ++v) { - cgltf_accessor_read_float(accessor, v, &joints_as_floats.x, 4); - tmp_joint_index.x = (u32)joints_as_floats.x; - tmp_joint_index.y = (u32)joints_as_floats.y; - tmp_joint_index.z = (u32)joints_as_floats.z; - tmp_joint_index.w = (u32)joints_as_floats.w; - printf("Joints affecting vertex %d : %d %d %d %d\n", v, tmp_joint_index.x, tmp_joint_index.y, - tmp_joint_index.z, tmp_joint_index.w); - Vec4i_darray_push(joint_indices, tmp_joint_index); - } -} - -bool model_load_gltf_str(const char* file_string, const char* filepath, Str8 relative_path, - Model* out_model, bool invert_textures_y) { - TRACE("Load GLTF from string"); - - // Setup temps - Vec3_darray* tmp_positions = Vec3_darray_new(1000); - Vec3_darray* tmp_normals = Vec3_darray_new(1000); - Vec2_darray* tmp_uvs = Vec2_darray_new(1000); - Vec4i_darray* tmp_joint_indices = Vec4i_darray_new(1000); - Vec4_darray* tmp_weights = Vec4_darray_new(1000); - Material_darray* tmp_materials = Material_darray_new(1); - Mesh_darray* tmp_meshes = Mesh_darray_new(1); - i32_darray* tmp_material_indexes = i32_darray_new(1); - - Joint_darray* joints = Joint_darray_new(256); - - cgltf_options options = { 0 }; - cgltf_data* data = NULL; - cgltf_result result = cgltf_parse_file(&options, filepath, &data); - if (result != cgltf_result_success) { - WARN("gltf load failed"); - // TODO: cleanup arrays(allocate all from arena ?) - return false; - } - - cgltf_load_buffers(&options, data, filepath); - DEBUG("loaded buffers"); - - // --- Skin - size_t num_skins = data->skins_count; - bool is_skinned = false; - Armature main_skeleton = { 0 }; - if (num_skins == 1) { - is_skinned = true; - } else if (num_skins > 1) { - WARN("GLTF files with more than 1 skin are not supported"); - return false; - } - - if (is_skinned) { - cgltf_skin* gltf_skin = data->skins; - DEBUG("loading skin %s", gltf_skin->name); - size_t num_joints = gltf_skin->joints_count; - DEBUG("# Joints %d", num_joints); - - // Create our data that will be placed onto the model - Armature armature = { .label = "test_skin" }; - printf("Skin %s\n", gltf_skin->name); - // armature.label = Clone_cstr(&armature.arena, gltf_skin->name); - armature.joints = joints; // ! Make sure not to free this - - cgltf_accessor* gltf_inverse_bind_matrices = gltf_skin->inverse_bind_matrices; - - // --- Joints - // for each one we'll spit out a joint - for (size_t i = 0; i < num_joints; i++) { - // Get the joint and assign its node index for later referencing - cgltf_node* joint_node = gltf_skin->joints[i]; - TRACE("Joint %d (node index %d)", i, cgltf_node_index(data, joint_node)); - Joint joint_i = { .debug_label = "test_joint", - .node_idx = cgltf_node_index(data, joint_node), - .inverse_bind_matrix = mat4_ident() }; - - if (joint_node->children_count > 0 && !joint_node->has_translation && - !joint_node->has_rotation) { - WARN("Joint node with index %d is the root node", i); - joint_i.transform_components = TRANSFORM_DEFAULT; - joint_i.parent = -1; - for (u32 c_i = 0; c_i < joint_node->children_count; c_i++) { - joint_i.children[c_i] = cgltf_node_index(data, joint_node->children[c_i]); - joint_i.children_count++; - } - } else { - TRACE("Storing joint transform"); - joint_i.transform_components = TRANSFORM_DEFAULT; - if (joint_node->has_translation) { - memcpy(&joint_i.transform_components.position, &joint_node->translation, 3 * sizeof(f32)); - } - if (joint_node->has_rotation) { - memcpy(&joint_i.transform_components.rotation, &joint_node->rotation, 4 * sizeof(f32)); - } - if (joint_node->has_scale) { - memcpy(&joint_i.transform_components.scale, &joint_node->scale, 3 * sizeof(f32)); - } - joint_i.parent = cgltf_node_index(data, joint_node->parent); - } - // Calculate and store the starting transform of the joint - joint_i.local_transform = transform_to_mat(&joint_i.transform_components); - // Read in the inverse bind matrix - cgltf_accessor_read_float(gltf_inverse_bind_matrices, i, &joint_i.inverse_bind_matrix.data[0], - 16); - Joint_darray_push(armature.joints, joint_i); - } - main_skeleton = armature; - // out_model->armature = armature; - // out_model->has_joints = true; - } - - // --- Materials - size_t num_materials = GLTF_LoadMaterials(data, relative_path, tmp_materials); - - // --- Meshes - size_t num_meshes = data->meshes_count; - TRACE("Num meshes %d", num_meshes); - for (size_t m = 0; m < num_meshes; m++) { - printf("Primitive count %d\n", data->meshes[m].primitives_count); - for (size_t prim_i = 0; prim_i < data->meshes[m].primitives_count; prim_i++) { - DEBUG("Primitive %d\n", prim_i); - - cgltf_primitive primitive = data->meshes[m].primitives[prim_i]; - DEBUG("Found %d attributes", primitive.attributes_count); - - for (cgltf_size a = 0; a < primitive.attributes_count; a++) { - cgltf_attribute attribute = primitive.attributes[a]; - if (attribute.type == cgltf_attribute_type_position) { - cgltf_accessor* accessor = attribute.data; - load_position_components(tmp_positions, accessor); - } else if (attribute.type == cgltf_attribute_type_normal) { - cgltf_accessor* accessor = attribute.data; - load_normal_components(tmp_normals, accessor); - } else if (attribute.type == cgltf_attribute_type_texcoord) { - cgltf_accessor* accessor = attribute.data; - load_texcoord_components(tmp_uvs, accessor); - } else if (attribute.type == cgltf_attribute_type_joints) { - TRACE("Load joint indices from accessor"); - cgltf_accessor* accessor = attribute.data; - load_joint_index_components(tmp_joint_indices, accessor); - } else if (attribute.type == cgltf_attribute_type_weights) { - TRACE("Load joint weights from accessor"); - cgltf_accessor* accessor = attribute.data; - CASSERT(accessor->component_type == cgltf_component_type_r_32f); - CASSERT(accessor->type == cgltf_type_vec4); - - for (cgltf_size v = 0; v < accessor->count; ++v) { - Vec4 weights; - cgltf_accessor_read_float(accessor, v, &weights.x, 4); - printf("Weights affecting vertex %d : %f %f %f %f\n", v, weights.x, weights.y, - weights.z, weights.w); - Vec4_darray_push(tmp_weights, weights); - } - } else { - WARN("Unhandled cgltf_attribute_type: %s. skipping..", attribute.name); - } - } - // mesh.vertex_bone_data = vertex_bone_data_darray_new(1); - i32 mat_idx = -1; - if (primitive.material != NULL) { - DEBUG("Primitive Material %s", primitive.material->name); - // FIXME! - for (u32 i = 0; i < Material_darray_len(tmp_materials); i++) { - printf("%s vs %s \n", primitive.material->name, tmp_materials->data[i].name); - if (strcmp(primitive.material->name, tmp_materials->data[i].name) == 0) { - INFO("Found material"); - mat_idx = i; - i32_darray_push(tmp_material_indexes, mat_idx); - break; - } - } - } else { - i32_darray_push(tmp_material_indexes, -1); - } - - TRACE("Vertex data has been loaded"); - - Vertex_darray* geo_vertices = Vertex_darray_new(3); - u32_darray* geo_indices = u32_darray_new(0); - - // Store vertices - printf("Positions %d Normals %d UVs %d\n", tmp_positions->len, tmp_normals->len, - tmp_uvs->len); - // assert(tmp_positions->len == tmp_normals->len); - // assert(tmp_normals->len == tmp_uvs->len); - bool has_normals = tmp_normals->len > 0; - bool has_uvs = tmp_uvs->len > 0; - for (u32 v_i = 0; v_i < tmp_positions->len; v_i++) { - Vertex v = { 0 }; - if (is_skinned) { - v.skinned_3d.position = tmp_positions->data[v_i]; - v.skinned_3d.normal = has_normals ? tmp_normals->data[v_i] : VEC3_ZERO, - v.skinned_3d.tex_coords = has_uvs ? tmp_uvs->data[v_i] : vec2_create(0., 0.); - v.skinned_3d.bone_ids = tmp_joint_indices->data[v_i]; - v.skinned_3d.bone_weights = tmp_weights->data[v_i]; - } else { - v.static_3d.position = tmp_positions->data[v_i]; - v.static_3d.normal = has_normals ? tmp_normals->data[v_i] : VEC3_ZERO, - v.static_3d.tex_coords = has_uvs ? tmp_uvs->data[v_i] : vec2_create(0., 0.); - } - Vertex_darray_push(geo_vertices, v); - }; - - // Store indices - cgltf_accessor* indices = primitive.indices; - if (primitive.indices > 0) { - WARN("indices! %d", indices->count); - - // store indices - for (cgltf_size i = 0; i < indices->count; ++i) { - cgltf_uint ei; - cgltf_accessor_read_uint(indices, i, &ei, 1); - u32_darray_push(geo_indices, ei); - } - - Geometry* geometry = malloc(sizeof(Geometry)); - geometry->format = is_skinned ? VERTEX_SKINNED : VERTEX_STATIC_3D; - geometry->has_indices = true; - geometry->vertices = geo_vertices; - geometry->indices = geo_indices; - geometry->index_count = geo_indices->len; - - Mesh m = Mesh_Create(geometry, false); - if (is_skinned) { - m.is_skinned = true; - m.armature = main_skeleton; - } - Mesh_darray_push(tmp_meshes, m); - - Vec3_darray_clear(tmp_positions); - Vec3_darray_clear(tmp_normals); - Vec2_darray_clear(tmp_uvs); - Vec4i_darray_clear(tmp_joint_indices); - Vec4_darray_clear(tmp_weights); - } else { - WARN("No indices found. Ignoring mesh..."); - } - } - - // --- Animations - size_t num_animations = data->animations_count; - TRACE("Num animations %d", num_animations); - - if (num_animations > 0) { - if (!out_model->animations) { - out_model->animations = AnimationClip_darray_new(num_animations); - } - out_model->anim_arena = arena_create(malloc(MB(1)), MB(1)); - arena* arena = &out_model->anim_arena; - - // Iterate over each animation in the GLTF - for (int anim_idx = 0; anim_idx < data->animations_count; anim_idx++) { - cgltf_animation animation = data->animations[anim_idx]; - AnimationClip clip = { 0 }; - clip.clip_name = "test anim clip"; - clip.channels = AnimationSampler_darray_new(1); - - // for each animation, loop through all the channels - for (size_t c = 0; c < animation.channels_count; c++) { - cgltf_animation_channel channel = animation.channels[c]; - - AnimationSampler sampler = { 0 }; - - KeyframeKind data_type; - - switch (channel.target_path) { - case cgltf_animation_path_type_rotation: - data_type = KEYFRAME_ROTATION; - break; - case cgltf_animation_path_type_translation: - data_type = KEYFRAME_TRANSLATION; - break; - case cgltf_animation_path_type_scale: - data_type = KEYFRAME_SCALE; - break; - case cgltf_animation_path_type_weights: - data_type = KEYFRAME_WEIGHTS; - WARN("Morph target weights arent supported yet"); - return false; - default: - WARN("unsupported animation type"); - return false; - } - - sampler.current_index = 0; - sampler.animation.interpolation = INTERPOLATION_LINEAR; // NOTE: hardcoded for now - - // Keyframe times - size_t n_frames = channel.sampler->input->count; - CASSERT_MSG(channel.sampler->input->component_type == cgltf_component_type_r_32f, - "Expected animation sampler input component to be type f32"); - f32* times = arena_alloc(arena, n_frames * sizeof(f32)); - sampler.animation.n_timestamps = n_frames; - sampler.animation.timestamps = times; - cgltf_accessor_unpack_floats(channel.sampler->input, times, n_frames); - - // Keyframe values - size_t n_values = channel.sampler->output->count; - CASSERT_MSG(n_frames == n_values, "keyframe times = keyframe values"); - - Keyframes keyframes = { 0 }; - keyframes.kind = data_type; - keyframes.count = n_values; - keyframes.values = arena_alloc(arena, n_values * sizeof(Keyframe)); - for (cgltf_size v = 0; v < channel.sampler->output->count; ++v) { - switch (data_type) { - case KEYFRAME_ROTATION: { - Quat rot; - cgltf_accessor_read_float(channel.sampler->output, v, &rot.x, 4); - // printf("Quat %f %f %f %f\n", rot.x, rot.y, rot.z, rot.w); - keyframes.values[v].rotation = rot; - break; - } - case KEYFRAME_TRANSLATION: { - Vec3 trans; - cgltf_accessor_read_float(channel.sampler->output, v, &trans.x, 3); - keyframes.values[v].translation = trans; - break; - } - case KEYFRAME_SCALE: { - Vec3 scale; - cgltf_accessor_read_float(channel.sampler->output, v, &scale.x, 3); - keyframes.values[v].scale = scale; - break; - } - case KEYFRAME_WEIGHTS: { - // TODO: morph weights - break; - } - } - } - sampler.animation.values = keyframes; - sampler.min = channel.sampler->input->min[0]; - sampler.max = channel.sampler->input->max[0]; - - // *target_property = sampler; - printf("%d timestamps between %f and %f\n", sampler.animation.n_timestamps, sampler.min, - sampler.max); - - // TODO: get target - size_t target_index = cgltf_node_index(data, channel.target_node); - size_t joint_index = 0; - bool found = false; - for (u32 ji = 0; ji < main_skeleton.joints->len; ji++) { - if (main_skeleton.joints->data[ji].node_idx == target_index) { - joint_index = ji; - found = true; - break; - } - } - if (!found) { - WARN("Coulndnt find joint index"); - } - sampler.target_joint_idx = - joint_index; // NOTE: this assuming the target is a joint at the moment - AnimationSampler_darray_push(clip.channels, sampler); - } - - AnimationClip_darray_push(out_model->animations, clip); - } - } - - // exit(0); - } - - num_meshes = tmp_meshes->len; - - // we now have an array of meshes, materials, and the material which each mesh should get - out_model->meshes = malloc(num_meshes * sizeof(MeshHandle)); - out_model->mesh_count = num_meshes; - out_model->materials = malloc(num_materials * sizeof(MaterialHandle)); - out_model->material_count = num_materials; - - MaterialHandle* mat_handles = calloc(num_materials, sizeof(MaterialHandle)); - for (u32 mat_i = 0; mat_i < num_materials; mat_i++) { - mat_handles[mat_i] = - Material_pool_insert(Render_GetMaterialPool(), &tmp_materials->data[mat_i]); - } - memcpy(out_model->materials, mat_handles, num_materials * sizeof(MaterialHandle)); - - for (u32 mesh_i = 0; mesh_i < num_meshes; mesh_i++) { - i32 mat_idx = tmp_material_indexes->data[mesh_i]; - if (mat_idx > 0) { - tmp_meshes->data[mesh_i].material = mat_handles[mat_idx]; - - } else { - Material default_mat = PBRMaterialDefault(); - tmp_meshes->data[mesh_i].material = - Material_pool_insert(Render_GetMaterialPool(), &default_mat); - } - MeshHandle mesh = Mesh_pool_insert(Render_GetMeshPool(), &tmp_meshes->data[mesh_i]); - out_model->meshes[mesh_i] = mesh; - } - - free(mat_handles); - - return true; -} - -const char* bool_yes_no(bool pred) { return pred ? "Yes" : "No"; } - -// Loads all materials -size_t GLTF_LoadMaterials(cgltf_data* data, Str8 relative_path, Material_darray* out_materials) { - size_t num_materials = data->materials_count; - TRACE("Num materials %d", num_materials); - for (size_t m = 0; m < num_materials; m++) { - cgltf_material gltf_material = data->materials[m]; - TRACE("Loading material '%s'", gltf_material.name); - cgltf_pbr_metallic_roughness pbr = gltf_material.pbr_metallic_roughness; - - Material our_material = PBRMaterialDefault(); // focusing on PBR materials for now - - our_material.base_colour = - vec3(pbr.base_color_factor[0], pbr.base_color_factor[1], pbr.base_color_factor[2]); - our_material.metallic = pbr.metallic_factor; - our_material.roughness = pbr.roughness_factor; - - // -- albedo / base colour - cgltf_texture_view albedo_tex_view = pbr.base_color_texture; - bool has_albedo_texture = albedo_tex_view.texture != NULL; - TRACE("Has PBR base colour texture? %s", bool_yes_no(has_albedo_texture)); - printf("Base colour factor: %f %f %f\n", pbr.base_color_factor[0], pbr.base_color_factor[1], - pbr.base_color_factor[2]); - if (has_albedo_texture) { - char albedo_map_path[1024]; - snprintf(albedo_map_path, sizeof(albedo_map_path), "%s/%s", relative_path.buf, - albedo_tex_view.texture->image->uri); - our_material.albedo_map = TextureLoadFromFile(albedo_map_path); - } else { - our_material.albedo_map = Render_GetWhiteTexture(); - WARN("GLTF model has no albedo map"); - our_material.base_colour = - vec3_create(pbr.base_color_factor[0], pbr.base_color_factor[1], pbr.base_color_factor[2]); - } - - // -- metallic - cgltf_texture_view metal_rough_tex_view = pbr.metallic_roughness_texture; - printf("Metal factor: %f\n", pbr.metallic_factor); - printf("Roughness factor: %f\n", pbr.roughness_factor); - if (metal_rough_tex_view.texture != NULL) { - char metal_rough_map_path[1024]; - snprintf(metal_rough_map_path, sizeof(metal_rough_map_path), "%s/%s", relative_path.buf, - metal_rough_tex_view.texture->image->uri); - our_material.metallic_roughness_map = TextureLoadFromFile(metal_rough_map_path); - } else { - WARN("GLTF model has no metal/roughness map"); - our_material.metallic = pbr.metallic_factor; - our_material.roughness = pbr.roughness_factor; - } - - cgltf_texture_view normal_tex_view = gltf_material.normal_texture; - if (normal_tex_view.texture != NULL) { - char normal_map_path[1024]; - snprintf(normal_map_path, sizeof(normal_map_path), "%s/%s", relative_path.buf, - normal_tex_view.texture->image->uri); - our_material.normal_map = TextureLoadFromFile(normal_map_path); - } else { - WARN("GLTF model has no normal map"); - } - - u32 string_length = strlen(gltf_material.name) + 1; - assert(string_length < 64); - strcpy(our_material.name, gltf_material.name); - - Material_darray_push(out_materials, our_material); - } - - return out_materials->len; -} diff --git a/archive/src/resources/loaders.h b/archive/src/resources/loaders.h deleted file mode 100644 index ea1f9a2..0000000 --- a/archive/src/resources/loaders.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include "defines.h" -#include "render_types.h" -#include "str.h" - -// --- Public API -PUB ModelHandle ModelLoad_obj(const char* path, bool invert_texture_y); -PUB ModelHandle ModelLoad_gltf(const char* path, bool invert_texture_y); - -typedef struct GLTF_LoadStats { - u32 mesh_count, material_count, vertex_count, index_count, animation_count, joint_count; -} GLTF_LoadStats; - -// --- Internal -bool model_load_gltf_str(const char* file_string, const char* filepath, Str8 relative_path, - Model* out_model, bool invert_textures_y); diff --git a/archive/src/resources/obj.c b/archive/src/resources/obj.c deleted file mode 100644 index a5e9b18..0000000 --- a/archive/src/resources/obj.c +++ /dev/null @@ -1,398 +0,0 @@ -/** - * @file obj.c - * @brief Wavefront OBJ loader. - * @copyright Copyright (c) 2024 - */ -#include -#include -#include -#include -#include -#include - -#include "core.h" -#include "darray.h" -#include "file.h" -#include "log.h" -#include "maths.h" -#include "mem.h" -#include "platform.h" -#include "render.h" -#include "render_types.h" -#include "str.h" - -extern Core g_core; - -struct face { - u32 vertex_indices[3]; - u32 normal_indices[3]; - u32 uv_indices[3]; -}; -typedef struct face face; - -KITC_DECL_TYPED_ARRAY(Vec3) -KITC_DECL_TYPED_ARRAY(Vec2) -KITC_DECL_TYPED_ARRAY(face) - -// Forward declarations -// void create_submesh(mesh_darray *meshes, Vec3_darray *tmp_positions, Vec3_darray *tmp_normals, -// Vec2_darray *tmp_uvs, face_darray *tmp_faces, material_darray *materials, -// bool material_loaded, char current_material_name[256]); -// bool load_material_lib(const char *path, str8 relative_path, material_darray *materials); -// bool model_load_obj_str(const char *file_string, str8 relative_path, Model *out_model, -// bool invert_textures_y); - -ModelHandle model_load_obj(Core* core, const char* path, bool invert_textures_y) { - size_t arena_size = 1024; - arena scratch = arena_create(malloc(arena_size), arena_size); - - TRACE("Loading model at Path %s\n", path); - path_opt relative_path = path_parent(&scratch, path); - if (!relative_path.has_value) { - WARN("Couldnt get a relative path for the path to use for loading materials & textures later"); - } - const char* file_string = string_from_file(path); - - ModelHandle handle; - // model *model = model_pool_alloc(&g_core.models, &handle); - // model->name = str8_cstr_view(path); - // model->meshes = mesh_darray_new(1); - - // bool success = model_load_obj_str(file_string, relative_path.path, &model, invert_textures_y); - - // if (!success) { - // FATAL("Couldnt load OBJ file at path %s", path); - // ERROR_EXIT("Load fails are considered crash-worthy right now. This will change later.\n"); - // } - - // arena_free_all(&scratch); - // arena_free_storage(&scratch); - return handle; -} - -bool model_load_obj_str(const char* file_string, Str8 relative_path, Model* out_model, - bool invert_textures_y) { - TRACE("Load OBJ from string"); - - // // Setup temps - // vec3_darray *tmp_positions = vec3_darray_new(1000); - // vec3_darray *tmp_normals = vec3_darray_new(1000); - // vec2_darray *tmp_uvs = vec2_darray_new(1000); - // face_darray *tmp_faces = face_darray_new(1000); - // // TODO: In the future I'd like these temporary arrays to be allocated from an arena provided - // // by the function one level up, model_load_obj. That way we can just `return false;` anywhere - // in - // // this code to indicate an error, and be sure that all that memory will be cleaned up without - // // having to call vec3_darray_free in every single error case before returning. - - // // Other state - // bool object_set = false; - // bool material_loaded = false; - // char current_material_name[64]; - - // char *pch; - // char *rest = file_string; - // pch = strtok_r((char *)file_string, "\n", &rest); - - // int line_num = 0; - // char last_char_type = 'a'; - - // while (pch != NULL) { - // line_num++; - // char line_header[128]; - // int offset = 0; - - // // skip whitespace - // char *p = pch; - - // skip_space(pch); - - // if (*p == '\0') { - // /* the string is empty */ - // } else { - // // read the first word of the line - // int res = sscanf(pch, "%s %n", line_header, &offset); - // /* printf("header: %s, offset : %d res: %d\n",line_header, offset, res); */ - // if (res != 1) { - // break; - // } - - // if (strcmp(line_header, "o") == 0 || strcmp(line_header, "g") == 0) { - // // if we're currently parsing one - // if (!object_set) { - // object_set = true; - // } else { - // create_submesh(out_model->meshes, tmp_positions, tmp_normals, tmp_uvs, tmp_faces, - // NULL, // out_model->materials, - // material_loaded, current_material_name); - // object_set = false; - // } - // } else if (strcmp(line_header, "v") == 0) { - // // special logic: if we went from faces back to vertices trigger a mesh output. - // // PS: I hate OBJ - // if (last_char_type == 'f') { - // create_submesh(out_model->meshes, tmp_positions, tmp_normals, tmp_uvs, tmp_faces, - // NULL, // FIXME: out_model->materials, - // material_loaded, current_material_name); - // object_set = false; - // } - - // last_char_type = 'v'; - // vec3 vertex; - // sscanf(pch + offset, "%f %f %f", &vertex.x, &vertex.y, &vertex.z); - - // vec3_darray_push(tmp_positions, vertex); - // } else if (strcmp(line_header, "vt") == 0) { - // last_char_type = 't'; - // vec2 uv; - // char copy[1024]; - // memcpy(copy, pch + offset, strlen(pch + offset) + 1); - // char *p = pch + offset; - // while (isspace((unsigned char)*p)) ++p; - - // // I can't remember what is going on here - // memset(copy, 0, 1024); - // memcpy(copy, pch + offset, strlen(pch + offset) + 1); - // int res = sscanf(copy, "%f %f", &uv.x, &uv.y); - // memset(copy, 0, 1024); - // memcpy(copy, pch + offset, strlen(pch + offset) + 1); - // if (res != 1) { - // // da frick? some .obj files have 3 uvs instead of 2 - // f32 dummy; - // int res2 = sscanf(copy, "%f %f %f", &uv.x, &uv.y, &dummy); - // } - - // if (invert_textures_y) { - // uv.y = -uv.y; // flip Y axis to be consistent with how other PNGs are being handled - // // `texture_load` will flip it again - // } - // vec2_darray_push(tmp_uvs, uv); - // } else if (strcmp(line_header, "vn") == 0) { - // last_char_type = 'n'; - // vec3 normal; - // sscanf(pch + offset, "%f %f %f", &normal.x, &normal.y, &normal.z); - // vec3_darray_push(tmp_normals, normal); - // } else if (strcmp(line_header, "f") == 0) { - // last_char_type = 'f'; - // struct face f; - // sscanf(pch + offset, "%d/%d/%d %d/%d/%d %d/%d/%d", &f.vertex_indices[0], - // &f.uv_indices[0], - // &f.normal_indices[0], &f.vertex_indices[1], &f.uv_indices[1], - // &f.normal_indices[1], &f.vertex_indices[2], &f.uv_indices[2], - // &f.normal_indices[2]); - // // printf("f %d/%d/%d %d/%d/%d %d/%d/%d\n", f.vertex_indices[0], f.uv_indices[0], - // // f.normal_indices[0], - // // f.vertex_indices[1], f.uv_indices[1], f.normal_indices[1], - // // f.vertex_indices[2], f.uv_indices[2], f.normal_indices[2]); - // face_darray_push(tmp_faces, f); - // } else if (strcmp(line_header, "mtllib") == 0) { - // char filename[1024]; - // sscanf(pch + offset, "%s", filename); - // char mtllib_path[1024]; - // snprintf(mtllib_path, sizeof(mtllib_path), "%s/%s", relative_path.buf, filename); - // if (!load_material_lib(mtllib_path, relative_path, out_model->materials)) { - // ERROR("couldnt load material lib"); - // return false; - // } - // } else if (strcmp(line_header, "usemtl") == 0) { - // material_loaded = true; - // sscanf(pch + offset, "%s", current_material_name); - // } - // } - - // pch = strtok_r(NULL, "\n", &rest); - // } - - // // last mesh or if one wasnt created with 'o' directive - // if (face_darray_len(tmp_faces) > 0) { - // TRACE("Last leftover mesh"); - // create_submesh(out_model->meshes, tmp_positions, tmp_normals, tmp_uvs, tmp_faces, - // NULL, // TODO: out_model->materials, - // material_loaded, current_material_name); - // } - - // // Free data - // free((char *)file_string); - // vec3_darray_free(tmp_positions); - // vec3_darray_free(tmp_normals); - // vec2_darray_free(tmp_uvs); - // face_darray_free(tmp_faces); - // TRACE("Freed temporary OBJ loading data"); - - // if (mesh_darray_len(out_model->meshes) > 256) { - // printf("num meshes: %ld\n", mesh_darray_len(out_model->meshes)); - // } - - // // TODO: bounding box calculation for each mesh - // // TODO: bounding box calculation for model - - // TODO: copy from mesh_darray to malloc'd mesh* array - - return true; -} - -// /** -// * @brief Takes the current positions, normals, uvs arrays and constructs the vertex array -// * from those indices. -// */ -// void create_submesh(mesh_darray *meshes, vec3_darray *tmp_positions, vec3_darray *tmp_normals, -// vec2_darray *tmp_uvs, face_darray *tmp_faces, material_darray *materials, -// bool material_loaded, char current_material_name[256]) { -// // size_t num_verts = face_darray_len(tmp_faces) * 3; -// // vertex_darray *out_vertices = vertex_darray_new(num_verts); - -// // face_darray_iter face_iter = face_darray_iter_new(tmp_faces); -// // struct face *f; - -// // while ((f = face_darray_iter_next(&face_iter))) { -// // for (int j = 0; j < 3; j++) { -// // vertex vert = { 0 }; -// // vert.position = tmp_positions->data[f->vertex_indices[j] - 1]; -// // if (vec3_darray_len(tmp_normals) == 0) { -// // vert.normal = vec3_create(0.0, 0.0, 0.0); -// // } else { -// // vert.normal = tmp_normals->data[f->normal_indices[j] - 1]; -// // } -// // vert.uv = tmp_uvs->data[f->uv_indices[j] - 1]; -// // vertex_darray_push(out_vertices, vert); -// // } -// // } - -// // DEBUG("Loaded submesh\n vertices: %zu\n uvs: %zu\n normals: %zu\n faces: %zu", -// // vec3_darray_len(tmp_positions), vec2_darray_len(tmp_uvs), -// vec3_darray_len(tmp_normals), -// // face_darray_len(tmp_faces)); - -// // // Clear current object faces -// // face_darray_clear(tmp_faces); - -// // mesh m = { .vertices = out_vertices }; -// // if (material_loaded) { -// // // linear scan to find material -// // bool found = false; -// // DEBUG("Num of materials : %ld", material_darray_len(materials)); -// // material_darray_iter mat_iter = material_darray_iter_new(materials); -// // blinn_phong_material *cur_material; -// // while ((cur_material = material_darray_iter_next(&mat_iter))) { -// // if (strcmp(cur_material->name, current_material_name) == 0) { -// // DEBUG("Found match"); -// // m.material_index = mat_iter.current_idx - 1; -// // found = true; -// // break; -// // } -// // } - -// // if (!found) { -// // // TODO: default material -// // m.material_index = 0; -// // DEBUG("Set default material"); -// // } -// // } -// // mesh_darray_push(meshes, m); -// } - -// bool load_material_lib(const char *path, str8 relative_path, material_darray *materials) { -// TRACE("BEGIN load material lib at %s", path); - -// // const char *file_string = string_from_file(path); -// // if (file_string == NULL) { -// // ERROR("couldnt load %s", path); -// // return false; -// // } - -// // char *pch; -// // char *saveptr; -// // pch = strtok_r((char *)file_string, "\n", &saveptr); - -// // material current_material = DEFAULT_MATERIAL; - -// // bool material_set = false; - -// // while (pch != NULL) { -// // char line_header[128]; -// // int offset = 0; -// // // read the first word of the line -// // int res = sscanf(pch, "%s %n", line_header, &offset); -// // if (res != 1) { -// // break; -// // } - -// // // When we see "newmtl", start a new material, or flush the previous one -// // if (strcmp(line_header, "newmtl") == 0) { -// // if (material_set) { -// // // a material was being parsed, so flush that one and start a new one -// // material_darray_push(materials, current_material); -// // DEBUG("pushed material with name %s", current_material.name); -// // WARN("Reset current material"); -// // current_material = DEFAULT_MATERIAL; -// // } else { -// // material_set = true; -// // } -// // // scan the new material name -// // char material_name[64]; -// // sscanf(pch + offset, "%s", current_material.name); -// // DEBUG("material name %s\n", current_material.name); -// // // current_material.name = material_name; -// // } else if (strcmp(line_header, "Ka") == 0) { -// // // ambient -// // sscanf(pch + offset, "%f %f %f", ¤t_material.ambient_colour.x, -// // ¤t_material.ambient_colour.y, ¤t_material.ambient_colour.z); -// // } else if (strcmp(line_header, "Kd") == 0) { -// // // diffuse -// // sscanf(pch + offset, "%f %f %f", ¤t_material.diffuse.x, -// ¤t_material.diffuse.y, -// // ¤t_material.diffuse.z); -// // } else if (strcmp(line_header, "Ks") == 0) { -// // // specular -// // sscanf(pch + offset, "%f %f %f", ¤t_material.specular.x, -// // ¤t_material.specular.y, -// // ¤t_material.specular.z); -// // } else if (strcmp(line_header, "Ns") == 0) { -// // // specular exponent -// // sscanf(pch + offset, "%f", ¤t_material.spec_exponent); -// // } else if (strcmp(line_header, "map_Kd") == 0) { -// // char diffuse_map_filename[1024]; -// // sscanf(pch + offset, "%s", diffuse_map_filename); -// // char diffuse_map_path[1024]; -// // snprintf(diffuse_map_path, sizeof(diffuse_map_path), "%s/%s", relative_path.buf, -// // diffuse_map_filename); -// // printf("load from %s\n", diffuse_map_path); - -// // // -------------- -// // texture diffuse_texture = texture_data_load(diffuse_map_path, true); -// // current_material.diffuse_texture = diffuse_texture; -// // strcpy(current_material.diffuse_tex_path, diffuse_map_path); -// // texture_data_upload(¤t_material.diffuse_texture); -// // // -------------- -// // } else if (strcmp(line_header, "map_Ks") == 0) { -// // // char specular_map_path[1024] = "assets/"; -// // // sscanf(pch + offset, "%s", specular_map_path + 7); -// // char specular_map_filename[1024]; -// // sscanf(pch + offset, "%s", specular_map_filename); -// // char specular_map_path[1024]; -// // snprintf(specular_map_path, sizeof(specular_map_path), "%s/%s", relative_path.buf, -// // specular_map_filename); -// // printf("load from %s\n", specular_map_path); -// // // -------------- -// // texture specular_texture = texture_data_load(specular_map_path, true); -// // current_material.specular_texture = specular_texture; -// // strcpy(current_material.specular_tex_path, specular_map_path); -// // texture_data_upload(¤t_material.specular_texture); -// // // -------------- -// // } else if (strcmp(line_header, "map_Bump") == 0) { -// // // TODO -// // } - -// // pch = strtok_r(NULL, "\n", &saveptr); -// // } - -// // TRACE("end load material lib"); - -// // // last mesh or if one wasnt created with 'o' directive -// // // TRACE("Last leftover material"); -// // material_darray_push(materials, current_material); - -// // INFO("Loaded %ld materials", material_darray_len(materials)); -// TRACE("END load material lib"); -// return true; -// } diff --git a/archive/src/std/buf.h b/archive/src/std/buf.h deleted file mode 100644 index 77fc7b9..0000000 --- a/archive/src/std/buf.h +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @file buf.h - * @brief - */ -#pragma once -#include "defines.h" - -typedef struct bytebuffer { - u8* buf; - size_t size; -} bytebuffer; diff --git a/archive/src/std/containers/container_utils.h b/archive/src/std/containers/container_utils.h deleted file mode 100644 index e1d164c..0000000 --- a/archive/src/std/containers/container_utils.h +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @file container_utils.h - * @author your name (you@domain.com) - * @brief - * @version 0.1 - * @date 2024-06-19 - * - * @copyright Copyright (c) 2024 - * - */ - -#pragma once - -typedef struct generic_iterator { -} generic_iterator; - -typedef void* (*iterator_next_item)(void* iterator); \ No newline at end of file diff --git a/archive/src/std/containers/darray.h b/archive/src/std/containers/darray.h deleted file mode 100644 index 080afb4..0000000 --- a/archive/src/std/containers/darray.h +++ /dev/null @@ -1,151 +0,0 @@ -/** - * @file darray.h - * @brief Typed dynamic array - * @copyright Copyright (c) 2023 - */ -// COPIED FROM KITC WITH SOME MINOR ADJUSTMENTS - -/* TODO: - - a 'find' function that takes a predicate (maybe wrap with a macro so we dont have to define a - new function?) -*/ - -#ifndef KITC_TYPED_ARRAY_H -#define KITC_TYPED_ARRAY_H - -#include -#include -#include -#include - -#define DARRAY_DEFAULT_CAPACITY 64 -#define DARRAY_RESIZE_FACTOR 3 - -/** @brief create a new darray type and functions with type `N` */ -#define typed_array(T) \ - struct { \ - /* @brief current number of items in the array */ \ - size_t len; \ - size_t capacity; \ - T* data; \ - } - -#define typed_array_iterator(T) \ - struct { \ - T##_darray* array; \ - size_t current_idx; \ - } - -#define PREFIX static - -#define KITC_DECL_TYPED_ARRAY(T) DECL_TYPED_ARRAY(T, T) - -#define DECL_TYPED_ARRAY(T, Type) \ - typedef typed_array(T) Type##_darray; \ - typedef typed_array_iterator(Type) Type##_darray_iter; \ - \ - /* Create a new one growable array */ \ - PREFIX Type##_darray* Type##_darray_new(size_t starting_capacity) { \ - Type##_darray* d; \ - T* data; \ - d = malloc(sizeof(Type##_darray)); \ - data = malloc(starting_capacity * sizeof(T)); \ - \ - d->len = 0; \ - d->capacity = starting_capacity; \ - d->data = data; \ - \ - return d; \ - } \ - \ - PREFIX void Type##_darray_free(Type##_darray* d) { \ - if (d != NULL) { \ - free(d->data); \ - free(d); \ - } \ - } \ - \ - PREFIX T* Type##_darray_resize(Type##_darray* d, size_t capacity) { \ - /* resize the internal data block */ \ - T* new_data = realloc(d->data, sizeof(T) * capacity); \ - /* TODO: handle OOM error */ \ - \ - d->capacity = capacity; \ - d->data = new_data; \ - return new_data; \ - } \ - \ - PREFIX void Type##_darray_push(Type##_darray* d, T value) { \ - if (d->len >= d->capacity) { \ - size_t new_capacity = \ - d->capacity > 0 ? d->capacity * DARRAY_RESIZE_FACTOR : DARRAY_DEFAULT_CAPACITY; \ - T* resized = Type##_darray_resize(d, new_capacity); \ - (void)resized; \ - } \ - \ - d->data[d->len] = value; \ - d->len += 1; \ - } \ - \ - PREFIX void Type##_darray_push_copy(Type##_darray* d, const T* value) { \ - if (d->len >= d->capacity) { \ - size_t new_capacity = \ - d->capacity > 0 ? d->capacity * DARRAY_RESIZE_FACTOR : DARRAY_DEFAULT_CAPACITY; \ - T* resized = Type##_darray_resize(d, new_capacity); \ - (void)resized; \ - } \ - \ - T* place = d->data + d->len; \ - d->len += 1; \ - memcpy(place, value, sizeof(T)); \ - } \ - \ - PREFIX void Type##_darray_pop(Type##_darray* d, T* dest) { \ - T* item = d->data + (d->len - 1); \ - d->len -= 1; \ - memcpy(dest, item, sizeof(T)); \ - } \ - \ - PREFIX void Type##_darray_ins(Type##_darray* d, const T* value, size_t index) { \ - /* check if requires resize */ \ - if (d->len + 1 > d->capacity) { \ - size_t new_capacity = \ - d->capacity > 0 ? d->capacity * DARRAY_RESIZE_FACTOR : DARRAY_DEFAULT_CAPACITY; \ - T* resized = Type##_darray_resize(d, new_capacity); \ - (void)resized; \ - } \ - \ - /* shift existing data after index */ \ - T* insert_dest = d->data + index; \ - T* shift_dest = insert_dest + 1; \ - \ - int num_items = d->len - index; \ - \ - d->len += 1; \ - memcpy(shift_dest, insert_dest, num_items * sizeof(T)); \ - memcpy(insert_dest, value, sizeof(T)); \ - } \ - \ - PREFIX void Type##_darray_clear(Type##_darray* d) { \ - d->len = 0; \ - memset(d->data, 0, d->capacity * sizeof(T)); \ - } \ - \ - PREFIX size_t Type##_darray_len(Type##_darray* d) { return d->len; } \ - \ - PREFIX Type##_darray_iter Type##_darray_iter_new(Type##_darray* d) { \ - Type##_darray_iter iterator; \ - iterator.array = d; \ - iterator.current_idx = 0; \ - return iterator; \ - } \ - \ - PREFIX void* Type##_darray_iter_next(Type##_darray_iter* iterator) { \ - if (iterator->current_idx < iterator->array->len) { \ - return &iterator->array->data[iterator->current_idx++]; \ - } else { \ - return NULL; \ - } \ - } - -#endif // KITC_TYPED_ARRAY_H diff --git a/archive/src/std/containers/graphs.h b/archive/src/std/containers/graphs.h deleted file mode 100644 index 5dbec97..0000000 --- a/archive/src/std/containers/graphs.h +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @file graphs.h - * @author your name (you@domain.com) - * @brief - * @version 0.1 - * @date 2024-04-27 - * - * @copyright Copyright (c) 2024 - * - */ - -// Adjacency list backed graphs - -// Matrix backed graphs (not as useful) \ No newline at end of file diff --git a/archive/src/std/containers/hashmap.h b/archive/src/std/containers/hashmap.h deleted file mode 100644 index 95c1c6b..0000000 --- a/archive/src/std/containers/hashmap.h +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @file hashmap.h - * @author your name (you@domain.com) - * @brief - * @version 0.1 - * @date 2024-04-27 - * - * @copyright Copyright (c) 2024 - * - */ - -typedef struct hashmap hashmap; - -/* -Example usage -------------- -init hashmap -insert (string, material) -get (string) -> material_opt or material* ? - -*/ - -void hashmap_init(hashmap* map); - -// ... - -void hashmap_free(hashmap* map); \ No newline at end of file diff --git a/archive/src/std/containers/hashset.h b/archive/src/std/containers/hashset.h deleted file mode 100644 index 7f87213..0000000 --- a/archive/src/std/containers/hashset.h +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @file hashset.h - * @author your name (you@domain.com) - * @brief - * @version 0.1 - * @date 2024-04-27 - * - * @copyright Copyright (c) 2024 - * - */ - -#include "defines.h" - -typedef struct hashset hashset; - -/** @brief Describes a function that will take a pointer to a datatype (e.g. a u64 or a struct) - and return a hashed key. */ -typedef uint64_t (*hash_item)(void* item); - -void hashset_init(hashset* set, hash_item hash_func, size_t initial_capacity); -// TODO: void hashset_from_iterator(); -bool hashset_insert(hashset* set, void* item, uint64_t* out_key); -void hashset_batch_insert(hashset* set, void* items, u64 item_count); -bool hashset_contains(hashset* set, void* item); -bool hashset_remove_item(hashset* set, void* item); -bool hashset_remove_key(hashset* set, uint64_t key); -void hashset_merge(hashset* set_a, hashset* set_b); -hashset* hashset_merge_cloned(hashset* set_a, hashset* set_b); -void hashset_free(hashset* set); \ No newline at end of file diff --git a/archive/src/std/containers/ring_queue.c b/archive/src/std/containers/ring_queue.c deleted file mode 100644 index 8bfc10b..0000000 --- a/archive/src/std/containers/ring_queue.c +++ /dev/null @@ -1,68 +0,0 @@ -#include "ring_queue.h" - -#include -#include -#include "defines.h" - -ring_queue* ring_queue_new(size_t type_size, size_t capacity, void* memory) { - ring_queue* q = malloc(sizeof(ring_queue)); - q->len = 0; - q->capacity = capacity; - q->type_size = type_size; - q->head = 0; - q->tail = -1; - - if (memory) { - // caller owns the memory - q->owns_memory = false; - q->data = memory; - } else { - // ring queue should own the memory - q->owns_memory = true; - q->data = malloc(capacity * type_size); - } - - return q; -} - -void ring_queue_free(ring_queue* queue) { - if (queue) { - if (queue->owns_memory) { - free(queue->data); - } - free(queue); - } -} - -bool ring_queue_enqueue(ring_queue* queue, const void* value) { - if (queue->len == queue->capacity) { - return false; - } - - queue->tail = (queue->tail + 1) % queue->capacity; - memcpy(queue->data + (queue->tail * queue->type_size), value, queue->type_size); - queue->len++; - return true; -} - -bool ring_queue_dequeue(ring_queue* queue, void* out_value) { - if (queue->len == 0) { - // queue is empty - return false; - } - - memcpy(out_value, queue->data + (queue->head * queue->type_size), queue->type_size); - queue->head = (queue->head + 1) % queue->capacity; - queue->len--; - return true; -} - -bool ring_queue_peek(const ring_queue* queue, void* out_value) { - if (queue->len == 0) { - // queue is empty - return false; - } - - memcpy(out_value, queue->data + (queue->head * queue->type_size), queue->type_size); - return true; -} \ No newline at end of file diff --git a/archive/src/std/containers/ring_queue.h b/archive/src/std/containers/ring_queue.h deleted file mode 100644 index 15d5da4..0000000 --- a/archive/src/std/containers/ring_queue.h +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @file ring_queue.h - * @author your name (you@domain.com) - * @brief - * @version 0.1 - * @date 2024-02-24 - * - * @copyright Copyright (c) 2024 - * - */ -#pragma once -#include "defines.h" - -/** - * @brief a fixed-size ring queue - */ -typedef struct ring_queue { - size_t len; - size_t capacity; - size_t type_size; - void* data; - bool owns_memory; - int32_t head; - int32_t tail; -} ring_queue; - -ring_queue* ring_queue_new(size_t type_size, size_t capacity, void* memory_block); - -void ring_queue_free(ring_queue* queue); - -bool ring_queue_enqueue(ring_queue* queue, const void* value); - -bool ring_queue_dequeue(ring_queue* queue, void* out_value); - -bool ring_queue_peek(const ring_queue* queue, void* out_value); \ No newline at end of file diff --git a/archive/src/std/containers/stack_array.h b/archive/src/std/containers/stack_array.h deleted file mode 100644 index d2b6bdd..0000000 --- a/archive/src/std/containers/stack_array.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include - -// Defines "_sarray" types - -#define TYPED_STACK_ARRAY(T, Name, Len) \ - typedef struct Name##_sarray { \ - T items[ Len ]; \ - size_t len; \ - } Name##_sarray; \ - Name##_sarray Name##_sarray_create() { \ - Name##_sarray arr = { .len = 0 }; \ - return arr; \ - } \ - bool Name##_sarray_push(Name##_sarray* arr, T item) { \ - if (arr->len == Len) { return false; }\ - arr->items[arr->len++] = item;\ - return true;\ - } diff --git a/archive/src/std/mem.c b/archive/src/std/mem.c deleted file mode 100644 index 1f9078b..0000000 --- a/archive/src/std/mem.c +++ /dev/null @@ -1,135 +0,0 @@ -#include -#include -#include -#include - -#include "log.h" -#include "mem.h" - -#ifndef DEFAULT_ALIGNMENT -#define DEFAULT_ALIGNMENT (2 * sizeof(void*)) -#endif - -// --- Arena - -void* arena_alloc_align(arena* a, size_t size, size_t align) { - ptrdiff_t padding = -(uintptr_t)a->curr & (align - 1); - ptrdiff_t available = a->end - a->curr - padding; - // TRACE("Padding %td available %td", padding, available); - if (available < 0 || (ptrdiff_t)size > available) { - ERROR_EXIT("Arena ran out of memory\n"); - } - void* p = a->curr + padding; - a->curr += padding + size; - return memset(p, 0, size); -} -void* arena_alloc(arena* a, size_t size) { return arena_alloc_align(a, size, DEFAULT_ALIGNMENT); } - -arena arena_create(void* backing_buffer, size_t capacity) { - return (arena){ .begin = backing_buffer, - .curr = backing_buffer, - .end = backing_buffer + (ptrdiff_t)capacity }; -} - -void arena_free_all(arena* a) { - a->curr = a->begin; // pop everything at once and reset to the start. -} - -void arena_free_storage(arena* a) { free(a->begin); } - -arena_save arena_savepoint(arena* a) { - arena_save savept = { .arena = a, .savepoint = a->curr }; - return savept; -} - -void arena_rewind(arena_save savepoint) { savepoint.arena->curr = savepoint.savepoint; } - -// --- Pool - -void_pool void_pool_create(arena* a, const char* debug_label, u64 capacity, u64 entry_size) { - size_t memory_requirements = capacity * entry_size; - void* backing_buf = arena_alloc(a, memory_requirements); - - assert(entry_size >= sizeof(void_pool_header)); // TODO: create my own assert with error message - - void_pool pool = { .capacity = capacity, - .entry_size = entry_size, - .count = 0, - .backing_buffer = backing_buf, - .free_list_head = NULL, - .debug_label = debug_label }; - - void_pool_free_all(&pool); - - return pool; -} - -void void_pool_free_all(void_pool* pool) { - // set all entries to be free - for (u64 i = 0; i < pool->capacity; i++) { - void* ptr = &pool->backing_buffer[i * pool->entry_size]; - void_pool_header* free_node = - (void_pool_header*)ptr; // we reuse the actual entry itself to hold the header - if (i == (pool->capacity - 1)) { - // if the last one we make its next pointer NULL indicating its full - free_node->next = NULL; - } - free_node->next = pool->free_list_head; - // now the head points to this entry - pool->free_list_head = free_node; - } -} - -void* void_pool_get(void_pool* pool, u32 raw_handle) { - // An handle is an index into the array essentially - void* ptr = pool->backing_buffer + (raw_handle * pool->entry_size); - return ptr; -} - -void* void_pool_alloc(void_pool* pool, u32* out_raw_handle) { - // get the next free node - if (pool->count == pool->capacity) { - WARN("Pool is full!"); - return NULL; - } - if (pool->free_list_head == NULL) { - ERROR("%s Pool is full (head = null)", pool->debug_label); - return NULL; - } - void_pool_header* free_node = pool->free_list_head; - - // What index does this become? - uintptr_t start = (uintptr_t)pool->backing_buffer; - uintptr_t cur = (uintptr_t)free_node; - // TRACE("%ld %ld ", start, cur); - assert(cur > start); - u32 index = (u32)((cur - start) / pool->entry_size); - /* printf("Index %d\n", index); */ - if (out_raw_handle != NULL) { - *out_raw_handle = index; - } - - pool->free_list_head = free_node->next; - - memset(free_node, 0, pool->entry_size); - pool->count++; - return (void*)free_node; -} - -void void_pool_dealloc(void_pool* pool, u32 raw_handle) { - // push free node back onto the free list - void* ptr = void_pool_get(pool, raw_handle); - void_pool_header* freed_node = (void_pool_header*)ptr; - - freed_node->next = pool->free_list_head; - pool->free_list_head = freed_node; - - pool->count--; -} - -u32 void_pool_insert(void_pool* pool, void* item) { - u32 raw_handle; - void* item_dest = void_pool_alloc(pool, &raw_handle); - memcpy(item_dest, item, pool->entry_size); - return raw_handle; -} diff --git a/archive/src/std/mem.h b/archive/src/std/mem.h deleted file mode 100644 index 56c1230..0000000 --- a/archive/src/std/mem.h +++ /dev/null @@ -1,96 +0,0 @@ -/** - * @file mem.h - * @brief Allocators, memory tracking - * @version 0.1 - * @date 2024-02-24 - * - * @copyright Copyright (c) 2024 - * - */ -#pragma once - -#include -#include "defines.h" - -typedef void* (*alloc_fn)(size_t size); -typedef void (*free_fn)(void* ptr); - -typedef struct allocator_t { - alloc_fn alloc; - free_fn free; -} allocator_t; - -// --- Arena - -// Inspired by https://nullprogram.com/blog/2023/09/27/ -typedef struct arena { - char* begin; - char* curr; - char* end; -} arena; - -typedef struct arena_save { - arena* arena; - char* savepoint; -} arena_save; - -arena arena_create(void* backing_buffer, size_t capacity); -void* arena_alloc(arena* a, size_t size); -void* arena_alloc_align(arena* a, size_t size, size_t align); -void arena_free_all(arena* a); -void arena_free_storage(arena* a); -arena_save arena_savepoint(arena* a); -void arena_rewind(arena_save savepoint); -// TODO: arena_resize - -// --- Pool - -typedef struct void_pool_header void_pool_header; -struct void_pool_header { - void_pool_header* next; -}; - -typedef struct void_pool { - u64 capacity; - u64 entry_size; - u64 count; - void* backing_buffer; - void_pool_header* free_list_head; - const char* debug_label; -} void_pool; - -void_pool void_pool_create(arena* a, const char* debug_label, u64 capacity, u64 entry_size); -void void_pool_free_all(void_pool* pool); -bool void_pool_is_empty(void_pool* pool); -bool void_pool_is_full(void_pool* pool); -void* void_pool_get(void_pool* pool, u32 raw_handle); -void* void_pool_alloc(void_pool* pool, u32* out_raw_handle); -void void_pool_dealloc(void_pool* pool, u32 raw_handle); -u32 void_pool_insert(void_pool* pool, void* item); -// TODO: fn to dealloc from the pointer that was handed out - -// TODO: macro that lets us specialise - -/* typedef struct Name##_handle Name##_handle; \ */ -#define TYPED_POOL(T, Name) \ - typedef struct Name##_pool { \ - void_pool inner; \ - } Name##_pool; \ - \ - static Name##_pool Name##_pool_create(arena* a, u64 cap, u64 entry_size) { \ - void_pool p = void_pool_create(a, "\"" #Name "\"", cap, entry_size); \ - return (Name##_pool){ .inner = p }; \ - } \ - static inline T* Name##_pool_get(Name##_pool* pool, Name##Handle handle) { \ - return (T*)void_pool_get(&pool->inner, handle.raw); \ - } \ - static inline T* Name##_pool_alloc(Name##_pool* pool, Name##Handle* out_handle) { \ - return (T*)void_pool_alloc(&pool->inner, &out_handle->raw); \ - } \ - static inline void Name##_pool_dealloc(Name##_pool* pool, Name##Handle handle) { \ - void_pool_dealloc(&pool->inner, handle.raw); \ - } \ - static Name##Handle Name##_pool_insert(Name##_pool* pool, T* item) { \ - u32 raw_handle = void_pool_insert(pool, item); \ - return (Name##Handle){ .raw = raw_handle }; \ - } diff --git a/archive/src/std/str.c b/archive/src/std/str.c deleted file mode 100644 index 89c76a0..0000000 --- a/archive/src/std/str.c +++ /dev/null @@ -1,74 +0,0 @@ -#include "str.h" -#include -#include -#include "log.h" -#include "mem.h" - -Str8 Str8_create(u8* buf, size_t len) { return (Str8){ .buf = buf, .len = len }; } - -Str8 Str8_cstr_view(char* string) { return Str8_create((u8*)string, strlen(string)); } - -bool Str8_equals(Str8 a, Str8 b) { - if (a.len != b.len) { - return false; - } - - for (size_t i = 0; i < a.len; i++) { - if (a.buf[i] != b.buf[i]) { - return false; - } - } - return true; -} - -char* Str8_to_cstr(arena* a, Str8 s) { - bool is_null_terminated = s.buf[s.len - 1] == 0; - size_t n_bytes = is_null_terminated ? s.len : s.len + 1; - - u8* dest = arena_alloc(a, n_bytes); - - memcpy(dest, s.buf, s.len); - if (is_null_terminated) { - dest[s.len] = '\0'; - } - return (char*)dest; -} - -char* Clone_cstr(arena* a, const char* s) { - if (s == NULL) { - WARN("Tried to clone a NULL char*"); - return NULL; - } - Str8 st = Str8_cstr_view(s); - return Str8_to_cstr(a, st); -} - -Str8 Str8_concat(arena* a, Str8 left, Str8 right) { - size_t n_bytes = left.len + right.len + 1; - - u8* dest = arena_alloc(a, n_bytes); - memcpy(dest, left.buf, left.len); - memcpy(dest + right.len, right.buf, right.len); - - dest[n_bytes - 1] = '\0'; - - return Str8_create(dest, n_bytes); -} - -Str8 Str8_substr(Str8 s, u64 min, u64 max) { - assert(min >= 0); - assert(min < s.len); - assert(max >= 0); - assert(max <= s.len); - uint8_t* start = s.buf + (ptrdiff_t)min; - size_t new_len = max - min; - return (Str8){ .buf = start, .len = new_len }; -} - -Str8 Str8_take(Str8 s, u64 first_n) { return Str8_substr(s, 0, first_n); } - -Str8 Str8_drop(Str8 s, u64 last_n) { return Str8_substr(s, s.len - last_n, s.len); } - -Str8 Str8_skip(Str8 s, u64 n) { return Str8_substr(s, n, s.len); } - -Str8 Str8_chop(Str8 s, u64 n) { return Str8_substr(s, 0, s.len - n); } diff --git a/archive/src/std/str.h b/archive/src/std/str.h deleted file mode 100644 index a29bf9a..0000000 --- a/archive/src/std/str.h +++ /dev/null @@ -1,89 +0,0 @@ -/** - * @file str.h - * @author your name (you@domain.com) - * @brief - * @version 0.1 - * @date 2024-02-25 - * - * @copyright Copyright (c) 2024 - * - */ -#pragma once - -#include - -#include "defines.h" -#include "mem.h" - -/** - * @brief Fat pointer representing a UTF8 (TODO some APIs supporting utf8) encoded string - * @note when using `printf` you must use %s.*s length, string until our own modified - print routines are written. alternatively wrap in `cstr()` and pass to `%s`. - */ -typedef struct { - u8* buf; - size_t len; -} Str8; - -// --- Constructors - -/** @brief Take a string literal and turn it into a `str8` */ -#define str8(s) \ - (Str8) { (u8*)s, ((sizeof(s) / sizeof(*(s)) - 1)) } - -Str8 Str8_create(u8* buf, size_t len); - -// TODO: Str8_OntoArena(arena* a, Str8 s); - -/** @brief Return a null-terminated C string cloned onto an arena */ -char* Str8_to_cstr(arena* a, Str8 s); - -#define cstr(a, s) (Str8_to_cstr(a, s)) // Shorthand - -/** @brief Return a Str8 that references a statically allocated string. - `string` therefore must already be null-terminated. - @note The backing `string` cannot be modified. */ -Str8 Str8_cstr_view(char* string); - -char* Clone_cstr(arena* a, const char* s); - -// --- Comparisons - -/** @brief Compare two strings for exact equality */ -bool Str8_equals(Str8 a, Str8 b); - -/** - * @brief Compare the first `first_nchars` of each string for equality - * @details If either of the strings are shorter than the number only the characters up until the - end of the shorter string will be compared. - * @returns 0 if they are fully equal up until `first_nchars`, i.e they never differed, else it - returns the index at which the first string differed from the second string. -*/ -size_t Str8_nequals(Str8 a, Str8 b, size_t first_nchars); - -bool Str8_ends_with(Str8 input_str, Str8 suffix); - -/// --- Subviews - -Str8 Str8_substr(Str8 s, u64 min, u64 max); -/** @brief Keeps only the `first_n` chars of `s` */ -Str8 Str8_take(Str8 s, u64 first_n); -/** @brief Keeps only the `last_n` chars of `s` */ -Str8 Str8_drop(Str8 s, u64 last_n); -/** @brief Keeps everything after the first `n` chars of `s` */ -Str8 Str8_skip(Str8 s, u64 n); -/** @brief Keeps everything before the last `n` chars of `s` */ -Str8 Str8_chop(Str8 s, u64 n); - -Str8 Str8_concat(arena* a, Str8 left, Str8 right); - -/// --- Misc - -static inline bool Str8_is_null_term(Str8 a) { - return a.buf[a.len] == 0; // This doesn't seem safe. YOLO -} - -// TODO: move or delete this and replace with handling using our internal type -static void skip_space(char* p) { - while (isspace((unsigned char)*p)) ++p; -} diff --git a/archive/src/std/utils.h b/archive/src/std/utils.h deleted file mode 100644 index c9827a3..0000000 --- a/archive/src/std/utils.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once -#include - -const char* bool_str(bool input) { return input ? "True" : "False"; } \ No newline at end of file diff --git a/archive/src/systems/grid.c b/archive/src/systems/grid.c deleted file mode 100644 index e907865..0000000 --- a/archive/src/systems/grid.c +++ /dev/null @@ -1,84 +0,0 @@ -#include "grid.h" -#include "file.h" -#include "log.h" -#include "maths.h" -#include "maths_types.h" -#include "primitives.h" -#include "ral_common.h" -#include "ral_impl.h" -#include "ral_types.h" -#include "render.h" -#include "render_types.h" -#include "shader_layouts.h" - -void Grid_Init(Grid_Storage* storage) { - INFO("Infinite Grid initialisation"); - Geometry plane_geo = Geo_CreatePlane(f32x2(1.0, 1.0), 1, 1); - Mesh plane_mesh = Mesh_Create(&plane_geo, true); - storage->plane_vertices = plane_mesh.vertex_buffer; - - u32 indices[6] = { 5, 4, 3, 2, 1, 0 }; - storage->plane_indices = - GPU_BufferCreate(6 * sizeof(u32), BUFFER_INDEX, BUFFER_FLAG_GPU, &indices); - - GPU_RenderpassDesc rpass_desc = { - .default_framebuffer = true, - }; - storage->renderpass = GPU_Renderpass_Create(rpass_desc); - - arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024); - - Str8 vert_path = str8("assets/shaders/grid.vert"); - Str8 frag_path = str8("assets/shaders/grid.frag"); - str8_opt vertex_shader = str8_from_file(&scratch, vert_path); - str8_opt fragment_shader = str8_from_file(&scratch, frag_path); - if (!vertex_shader.has_value || !fragment_shader.has_value) { - ERROR_EXIT("Failed to load shaders from disk") - } - - ShaderDataLayout camera_data = Binding_Camera_GetLayout(NULL); - - GraphicsPipelineDesc pipeline_desc = { - .debug_name = "Infinite grid pipeline", - .vertex_desc = static_3d_vertex_description(), - .data_layouts = { camera_data }, - .data_layouts_count = 1, - .vs = { - .debug_name = "Grid vertex shader", - .filepath = vert_path, - .code = vertex_shader.contents, - }, - .fs = { - .debug_name = "Grid fragment shader", - .filepath = frag_path, - .code = fragment_shader.contents, - }, - .wireframe = false, - }; - storage->pipeline = GPU_GraphicsPipeline_Create(pipeline_desc, storage->renderpass); -} - -void Grid_Draw() { - Grid_Storage* grid = Render_GetGridStorage(); - Grid_Execute(grid); -} - -void Grid_Execute(Grid_Storage* storage) { - RenderScene* scene = Render_GetScene(); - GPU_CmdEncoder* enc = GPU_GetDefaultEncoder(); - GPU_CmdEncoder_BeginRender(enc, storage->renderpass); - GPU_EncodeBindPipeline(enc, storage->pipeline); - Mat4 view, proj; - u32x2 dimensions = GPU_Swapchain_GetDimensions(); - Camera camera = scene->camera; - Camera_ViewProj(&camera, (f32)dimensions.x, (f32)dimensions.y, &view, &proj); - Binding_Camera camera_data = { .view = view, - .projection = proj, - .viewPos = vec4(camera.position.x, camera.position.y, - camera.position.z, 1.0) }; - GPU_EncodeBindShaderData(enc, 0, Binding_Camera_GetLayout(&camera_data)); - GPU_EncodeSetVertexBuffer(enc, storage->plane_vertices); - GPU_EncodeSetIndexBuffer(enc, storage->plane_indices); - GPU_EncodeDrawIndexedTris(enc, 6); - GPU_CmdEncoder_EndRender(enc); -} diff --git a/archive/src/systems/grid.h b/archive/src/systems/grid.h deleted file mode 100644 index d8bc567..0000000 --- a/archive/src/systems/grid.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "ral_impl.h" -#include "ral_types.h" - -typedef struct Grid_Storage { - GPU_Renderpass* renderpass; - GPU_Pipeline* pipeline; - BufferHandle plane_vertices; - BufferHandle plane_indices; -} Grid_Storage; - -// --- Public API -PUB void Grid_Init(Grid_Storage* storage); -// void Grid_Shutdown(Grid_Storage* storage); -PUB void Grid_Draw(); - -// --- Internal -void Grid_Execute(Grid_Storage* storage); -// typedef struct GridUniforms {} GridUniforms; -// ShaderDataLayout GridUniforms_GetLayout(void* data); \ No newline at end of file diff --git a/archive/src/systems/input.c b/archive/src/systems/input.c deleted file mode 100644 index c3af96a..0000000 --- a/archive/src/systems/input.c +++ /dev/null @@ -1,105 +0,0 @@ -#include "input.h" - -#include -#include -#include - -#include "keys.h" -#include "log.h" - -static Input_State* g_input; // Use a global to simplify caller code - -bool Input_Init(Input_State* input, GLFWwindow* window) { - INFO("Input init"); - memset(input, 0, sizeof(Input_State)); - - input->window = window; - // Set everything to false. Could just set memory to zero but where's the fun in that - for (int i = KEYCODE_SPACE; i < KEYCODE_MAX; i++) { - input->depressed_keys[i] = false; - input->just_pressed_keys[i] = false; - input->just_released_keys[i] = false; - } - - g_input = input; - - assert(input->mouse.x_delta == 0); - assert(input->mouse.y_delta == 0); - - INFO("Finish input init"); - return true; -} - -void Input_Shutdown(Input_State* input) {} - -void Input_Update(Input_State* input) { - glfwPollEvents(); - // --- update keyboard input - - // if we go from un-pressed -> pressed, set as "just pressed" - // if we go from pressed -> un-pressed, set as "just released" - for (int i = KEYCODE_SPACE; i < KEYCODE_MAX; i++) { - bool new_state = false; - if (glfwGetKey(input->window, i) == GLFW_PRESS) { - new_state = true; - } else { - new_state = false; - } - if (!input->depressed_keys[i] == false && new_state) { - input->just_pressed_keys[i] = true; - } else { - input->just_pressed_keys[i] = false; - } - - if (input->depressed_keys[i] && !new_state) { - input->just_released_keys[i] = true; - } else { - input->just_released_keys[i] = false; - } - - input->depressed_keys[i] = new_state; - } - - // --- update mouse input - - // cursor position - f64 current_x, current_y; - glfwGetCursorPos(input->window, ¤t_x, ¤t_y); - i32 quantised_cur_x = (i32)current_x; - i32 quantised_cur_y = (i32)current_y; - - mouse_state new_mouse_state = { 0 }; - new_mouse_state.x = quantised_cur_x; - new_mouse_state.y = quantised_cur_y; - new_mouse_state.x_delta = quantised_cur_x - input->mouse.x; - new_mouse_state.y_delta = quantised_cur_y - input->mouse.y; - - // buttons - int left_state = glfwGetMouseButton(input->window, GLFW_MOUSE_BUTTON_LEFT); - int right_state = glfwGetMouseButton(input->window, GLFW_MOUSE_BUTTON_RIGHT); - - for (int i = 0; i < 3; i++) { - new_mouse_state.prev_pressed_states[i] = input->mouse.cur_pressed_states[i]; - } - new_mouse_state.cur_pressed_states[MOUSEBTN_LEFT] = left_state == GLFW_PRESS; - new_mouse_state.cur_pressed_states[MOUSEBTN_RIGHT] = right_state == GLFW_PRESS; - - // this was dumb! need to also check button state changes lol - // if (new_mouse_state.x != input->mouse.x || new_mouse_state.y != input->mouse.y) - // TRACE("Mouse (x,y) = (%d,%d)", input->mouse.x, input->mouse.y); - - input->mouse = new_mouse_state; -} - -bool key_is_pressed(keycode key) { return g_input->depressed_keys[key]; } - -bool key_just_pressed(keycode key) { return g_input->just_pressed_keys[key]; } - -bool key_just_released(keycode key) { return g_input->just_released_keys[key]; } - -bool MouseBtn_Held(MouseBtn btn) { - assert(btn < 3); - return g_input->mouse.prev_pressed_states[btn] && g_input->mouse.cur_pressed_states[btn]; -} - -mouse_state Input_GetMouseState() { return g_input->mouse; } \ No newline at end of file diff --git a/archive/src/systems/input.h b/archive/src/systems/input.h deleted file mode 100644 index c3b2500..0000000 --- a/archive/src/systems/input.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * @brief - */ -#pragma once - -#include "defines.h" -#include "keys.h" - -struct GLFWWindow; - -typedef enum MouseBtn { - MOUSEBTN_LEFT = 0, - MOUSEBTN_RIGHT = 1, - MOUSEBTN_MIDDLE = 2, -} MouseBtn; - -typedef struct mouse_state { - i32 x; - i32 y; - i32 x_delta; - i32 y_delta; - bool prev_pressed_states[3]; - bool cur_pressed_states[3]; -} mouse_state; - -typedef struct Input_State { - struct GLFWwindow* window; - mouse_state mouse; - bool depressed_keys[KEYCODE_MAX]; - bool just_pressed_keys[KEYCODE_MAX]; - bool just_released_keys[KEYCODE_MAX]; -} Input_State; - -/** @brief `key` is currently being held down */ -PUB bool key_is_pressed(keycode key); - -/** @brief `key` was just pressed */ -PUB bool key_just_pressed(keycode key); - -/** @brief `key` was just released */ -PUB bool key_just_released(keycode key); - -// TODO: right btn as well -PUB bool MouseBtn_Held(MouseBtn btn); - -// --- Lifecycle - -PUB bool Input_Init(Input_State* input, struct GLFWwindow* window); -PUB void Input_Shutdown(Input_State* input); - -PUB void Input_Update(Input_State* state); // must be run once per main loop - -PUB mouse_state Input_GetMouseState(); \ No newline at end of file diff --git a/archive/src/systems/keys.h b/archive/src/systems/keys.h deleted file mode 100644 index 6082a59..0000000 --- a/archive/src/systems/keys.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -typedef enum keycode { - // TODO: add all keycodes - KEYCODE_SPACE = 32, - KEYCODE_APOSTROPHE = 39, - KEYCODE_COMMA = 44, - KEYCODE_MINUS = 45, - KEYCODE_PERIOD = 46, - KEYCODE_SLASH = 47, - KEYCODE_0 = 48, - KEYCODE_1 = 49, - KEYCODE_2 = 50, - KEYCODE_3 = 51, - KEYCODE_4 = 52, - KEYCODE_5 = 53, - KEYCODE_6 = 54, - KEYCODE_7 = 55, - KEYCODE_8 = 56, - KEYCODE_9 = 57, - KEYCODE_SEMICOLON = 59, - KEYCODE_EQUAL = 61, - KEYCODE_A = 65, - KEYCODE_B = 66, - KEYCODE_C = 67, - KEYCODE_D = 68, - KEYCODE_E = 69, - KEYCODE_F = 70, - KEYCODE_G = 71, - KEYCODE_H = 72, - KEYCODE_I = 73, - KEYCODE_J = 74, - KEYCODE_K = 75, - KEYCODE_L = 76, - KEYCODE_M = 77, - KEYCODE_N = 78, - KEYCODE_O = 79, - KEYCODE_P = 80, - KEYCODE_Q = 81, - KEYCODE_R = 82, - KEYCODE_S = 83, - KEYCODE_T = 84, - KEYCODE_U = 85, - KEYCODE_V = 86, - KEYCODE_W = 87, - KEYCODE_X = 88, - KEYCODE_Y = 89, - KEYCODE_Z = 90, - - KEYCODE_ESCAPE = 256, - KEYCODE_ENTER = 257, - KEYCODE_TAB = 258, - KEYCODE_BACKSPACE = 259, - KEYCODE_KEY_RIGHT = 262, - KEYCODE_KEY_LEFT = 263, - KEYCODE_KEY_DOWN = 264, - KEYCODE_KEY_UP = 265, - KEYCODE_MAX = 348 -} keycode; diff --git a/archive/src/systems/screenspace.h b/archive/src/systems/screenspace.h deleted file mode 100644 index 5f0c579..0000000 --- a/archive/src/systems/screenspace.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * @brief Drawing shapes for UI or other reasons in screenspace - */ -#pragma once - -#include "colours.h" -#include "darray.h" -#include "defines.h" -#include "render_types.h" - -/** A draw_cmd packet for rendering a rectangle */ -struct draw_rect { - i32 x, y; // signed ints so we can draw things offscreen (e.g. a window half inside the viewport) - u32 width, height; - rgba colour; - // TODO: border colour, gradients -}; - -/** A draw_cmd packet for rendering a circle */ -struct draw_circle { - i32 x, y; - f32 radius; - rgba colour; -}; - -/** @brief Tagged union that represents a UI shape to be drawn. */ -typedef struct draw_cmd { - enum { DRAW_RECT, CIRCLE } draw_cmd_type; - union { - struct draw_rect rect; - struct draw_circle circle; - }; -} draw_cmd; - -KITC_DECL_TYPED_ARRAY(draw_cmd) - -typedef struct screenspace_state { - u32 rect_vbo; - u32 rect_vao; - // shader rect_shader; - draw_cmd_darray* draw_cmd_buf; -} screenspace_state; - -// --- Lifecycle -bool screenspace_2d_init(screenspace_state* state); -void screenspace_2d_shutdown(screenspace_state* state); -/** Drains the draw_cmd buffer and emits draw calls to render each one */ -void screenspace_2d_render(screenspace_state* state); - -struct core; - -/** @brief Draw a rectangle to the screen. (0,0) is the bottom-left */ -void draw_rectangle(struct core* core, rgba colour, i32 x, i32 y, u32 width, u32 height); \ No newline at end of file diff --git a/archive/src/systems/terrain.c b/archive/src/systems/terrain.c deleted file mode 100644 index 069000e..0000000 --- a/archive/src/systems/terrain.c +++ /dev/null @@ -1,204 +0,0 @@ -/** - * @brief - */ -#include "terrain.h" -#include -#include "file.h" -#include "glad/glad.h" -#include "log.h" -#include "maths.h" -#include "mem.h" -#include "ral_common.h" -#include "ral_impl.h" -#include "ral_types.h" -#include "render.h" -#include "shader_layouts.h" -#include "str.h" - -#define TERRAIN_GRID_U 505 -#define TERRAIN_GRID_V 505 - -bool Terrain_Init(Terrain_Storage* storage) { - storage->grid_dimensions = u32x2(TERRAIN_GRID_U, TERRAIN_GRID_V); - storage->hmap_loaded = false; - - GPU_RenderpassDesc rpass_desc = { - .default_framebuffer = true, - }; - storage->hmap_renderpass = GPU_Renderpass_Create(rpass_desc); - - arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024); - - Str8 vert_path = str8("assets/shaders/terrain.vert"); - Str8 frag_path = str8("assets/shaders/terrain.frag"); - str8_opt vertex_shader = str8_from_file(&scratch, vert_path); - str8_opt fragment_shader = str8_from_file(&scratch, frag_path); - if (!vertex_shader.has_value || !fragment_shader.has_value) { - ERROR_EXIT("Failed to load shaders from disk") - } - - ShaderDataLayout camera_data = Binding_Camera_GetLayout(NULL); - ShaderDataLayout terrain_data = TerrainUniforms_GetLayout(NULL); - - GraphicsPipelineDesc pipeline_desc = { - .debug_name = "terrain rendering pipeline", - .vertex_desc = static_3d_vertex_description(), - .data_layouts = { camera_data, terrain_data }, - .data_layouts_count = 2, - .vs = { - .debug_name = "terrain vertex shader", - .filepath = vert_path, - .code = vertex_shader.contents, - }, - .fs = { - .debug_name = "terrain fragment shader", - .filepath = frag_path, - .code = fragment_shader.contents, - }, - .wireframe = false, - }; - storage->hmap_pipeline = GPU_GraphicsPipeline_Create(pipeline_desc, storage->hmap_renderpass); - - storage->texture = TextureLoadFromFile("assets/demo/textures/grass2.png"); - - return true; -} - -void Terrain_Shutdown(Terrain_Storage* storage) {} - -void Terrain_LoadHeightmap(Terrain_Storage* storage, Heightmap hmap, f32 grid_scale, - bool free_on_upload) { - // If there's a current one we will delete it and reallocate buffers - if (storage->hmap_loaded) { - GPU_BufferDestroy(storage->vertex_buffer); - GPU_BufferDestroy(storage->index_buffer); - } - - u32 width = hmap.pixel_dimensions.x; - u32 height = hmap.pixel_dimensions.y; - storage->grid_scale = grid_scale; - - size_t num_vertices = storage->grid_dimensions.x * storage->grid_dimensions.y; - storage->num_vertices = num_vertices; - - Vertex_darray* vertices = Vertex_darray_new(num_vertices); - u32 index = 0; - for (u32 i = 0; i < storage->grid_dimensions.x; i++) { - for (u32 j = 0; j < storage->grid_dimensions.y; j++) { - size_t position = j * storage->grid_dimensions.x + i; - u8* bytes = hmap.image_data; - u8 channel = bytes[position]; - float value = (float)channel / 255.0; - // printf("(%d, %d) %d : %f \n", i, j, channel, value); - - assert(index < num_vertices); - f32 height = Heightmap_HeightXZ(&hmap, i, j); - Vec3 v_pos = vec3_create(i * grid_scale, height, j * grid_scale); - Vec3 v_normal = VEC3_Y; - float tiling_factor = 505.0f; - Vec2 v_uv = vec2((f32)i / width * tiling_factor, (f32)j / height * tiling_factor); - Vertex v = { .static_3d = { .position = v_pos, .normal = v_normal, .tex_coords = v_uv } }; - Vertex_darray_push(vertices, v); - index++; - } - } - BufferHandle vertices_handle = GPU_BufferCreate(num_vertices * sizeof(Vertex), BUFFER_VERTEX, - BUFFER_FLAG_GPU, vertices->data); - storage->vertex_buffer = vertices_handle; - - u32 quad_count = (width - 1) * (height - 1); - u32 indices_count = quad_count * 6; - storage->indices_count = indices_count; - u32_darray* indices = u32_darray_new(indices_count); - for (u32 i = 0; i < (width - 1); i++) { // row - for (u32 j = 0; j < (height - 1); j++) { // col - u32 bot_left = i * width + j; - u32 top_left = (i + 1) * width + j; - u32 top_right = (i + 1) * width + (j + 1); - u32 bot_right = i * width + j + 1; - - // top left tri - u32_darray_push(indices, top_right); - u32_darray_push(indices, top_left); - u32_darray_push(indices, bot_left); - - // bottom right tri - u32_darray_push(indices, bot_right); - u32_darray_push(indices, top_right); - u32_darray_push(indices, bot_left); - } - } - - BufferHandle indices_handle = - GPU_BufferCreate(indices_count * sizeof(u32), BUFFER_INDEX, BUFFER_FLAG_GPU, indices->data); - storage->index_buffer = indices_handle; -} - -Heightmap Heightmap_FromImage(Str8 filepath) { - size_t max_size = MB(16); - arena arena = arena_create(malloc(max_size), max_size); - // str8_opt maybe_file = str8_from_file(&arena, filepath); - // assert(maybe_file.has_value); - - TextureData hmap_tex = TextureDataLoad(Str8_to_cstr(&arena, filepath), false); - - // arena_free_storage(&arena); - - return (Heightmap){ - .pixel_dimensions = hmap_tex.description.extents, - .filepath = filepath, - .image_data = hmap_tex.image_data, - .num_channels = hmap_tex.description.num_channels, - .is_uploaded = false, - }; -} - -void Terrain_Draw(Terrain_Storage* storage) { - GPU_CmdEncoder* enc = GPU_GetDefaultEncoder(); - GPU_EncodeBindPipeline(enc, storage->hmap_pipeline); - RenderScene* scene = Render_GetScene(); - - Mat4 view, proj; - u32x2 dimensions = GPU_Swapchain_GetDimensions(); - Camera_ViewProj(&scene->camera, (f32)dimensions.x, (f32)dimensions.y, &view, &proj); - Binding_Camera camera_data = { .view = view, - .projection = proj, - .viewPos = vec4(scene->camera.position.x, scene->camera.position.y, - scene->camera.position.z, 1.0) }; - GPU_EncodeBindShaderData(enc, 0, Binding_Camera_GetLayout(&camera_data)); - - TerrainUniforms uniforms = { .tex_slot_1 = storage->texture }; - ShaderDataLayout terrain_data = TerrainUniforms_GetLayout(&uniforms); - GPU_EncodeBindShaderData(enc, 1, terrain_data); - - GPU_EncodeSetVertexBuffer(enc, storage->vertex_buffer); - GPU_EncodeSetIndexBuffer(enc, storage->index_buffer); - - GPU_EncodeDrawIndexedTris(enc, storage->indices_count); - // glDrawArrays(GL_POINTS, 0, storage->num_vertices); -} - -f32 Heightmap_HeightXZ(const Heightmap* hmap, u32 x, u32 z) { - // its single channel so only one byte per pixel - size_t position = x * hmap->pixel_dimensions.x + z; - u8* bytes = hmap->image_data; - u8 channel = bytes[position]; - float value = (float)channel / 2.0; /// 255.0; - return value; -} - -ShaderDataLayout TerrainUniforms_GetLayout(void* data) { - TerrainUniforms* d = data; - bool has_data = data != NULL; - - ShaderBinding b1 = { - .label = "TextureSlot1", - .kind = BINDING_TEXTURE, - .vis = VISIBILITY_FRAGMENT, - }; - - if (has_data) { - b1.data.texture.handle = d->tex_slot_1; - } - return (ShaderDataLayout){ .bindings = { b1 }, .binding_count = 1 }; -} diff --git a/archive/src/systems/terrain.h b/archive/src/systems/terrain.h deleted file mode 100644 index 5a96132..0000000 --- a/archive/src/systems/terrain.h +++ /dev/null @@ -1,72 +0,0 @@ -/** - * @file terrain.h - * @brief - */ - -#pragma once - -/* -Future: - - Chunked terrain - - Dynamic LOD -*/ - -#include "defines.h" -#include "maths_types.h" -#include "ral_types.h" -#include "render.h" -#include "str.h" - -typedef struct Heightmap { - Str8 filepath; - u32x2 pixel_dimensions; - void* image_data; - u32 num_channels; - bool is_uploaded; -} Heightmap; - -typedef struct Terrain_Storage { - // arena terrain_allocator; - u32x2 grid_dimensions; - f32 grid_scale; - u32 num_vertices; - Heightmap heightmap; // NULL = no heightmap - GPU_Renderpass* hmap_renderpass; - GPU_Pipeline* hmap_pipeline; - TextureHandle texture; - - bool hmap_loaded; - BufferHandle vertex_buffer; - BufferHandle index_buffer; - u32 indices_count; -} Terrain_Storage; - -// --- Public API -PUB bool Terrain_Init(Terrain_Storage* storage); -PUB void Terrain_Shutdown(Terrain_Storage* storage); -PUB void Terrain_Draw( - Terrain_Storage* storage); // NOTE: For now it renders directly to main framebuffer - -/** @brief Sets the active heightmap to be rendered and collided against. */ -PUB void Terrain_LoadHeightmap(Terrain_Storage* storage, Heightmap hmap, f32 grid_scale, - bool free_on_upload); -PUB Heightmap Heightmap_FromImage(Str8 filepath); -PUB Heightmap Heightmap_FromPerlin(/* TODO: perlin noise generation parameters */); - -PUB bool Terrain_IsActive(); // checks whether we have a loaded heightmap and it's being rendered - -/** @brief Get the height (the Y component) for a vertex at a particular coordinate in the heightmap - */ -PUB f32 Heightmap_HeightXZ(const Heightmap* hmap, u32 x, u32 z); - -/** @brief Calculate the normal vector of a vertex at a particular coordinate in the heightmap */ -PUB Vec3 Heightmap_NormalXZ(const Heightmap* hmap, f32 x, f32 z); - -// /** @brief Generate the `geometry_data` for a heightmap ready to be uploaded to the GPU */ -// Geometry geo_heightmap(arena* a, Heightmap heightmap); - -typedef struct TerrainUniforms { - TextureHandle tex_slot_1; -} TerrainUniforms; - -ShaderDataLayout TerrainUniforms_GetLayout(void* data); \ No newline at end of file diff --git a/archive/src/systems/text.c b/archive/src/systems/text.c deleted file mode 100644 index 2bb5399..0000000 --- a/archive/src/systems/text.c +++ /dev/null @@ -1 +0,0 @@ -// TODO: Port from previous repo \ No newline at end of file diff --git a/archive/src/systems/text.h b/archive/src/systems/text.h deleted file mode 100644 index 983ffd6..0000000 --- a/archive/src/systems/text.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * @brief - */ -#pragma once - -#include - -#include "darray.h" -#include "defines.h" -#include "ral.h" -#include "render_types.h" - -// struct core; - -// /** @brief internal font struct */ -// typedef struct font { -// const char *name; -// stbtt_fontinfo stbtt_font; -// stbtt_bakedchar c_data[96]; -// texture_handle bitmap_tex; -// } font; - -// typedef struct draw_text_packet { -// char *contents; -// f32 x; -// f32 y; -// } draw_text_packet; - -// KITC_DECL_TYPED_ARRAY(draw_text_packet) - -// typedef struct text_system_state { -// font default_font; -// shader_handle glyph_shader; -// u32 glyph_vbo; -// u32 glyph_vao; -// draw_text_packet_darray *draw_cmd_buf; -// // TODO: fonts array or hashtable -// } text_system_state; - -// void text_system_render(text_system_state *text); - -// // --- Lifecycle functions -// bool text_system_init(text_system_state *text); -// void text_system_shutdown(text_system_state *text); - -// // --- Drawing - -// /** -// * @brief immediate mode draw text. -// * @note immediately emits draw calls causing a shader program switch if you weren't previously -// drawing text in the current frame. -// */ -// void draw_text(struct core *core, f32 x, f32 y, char *contents); diff --git a/archive/src/transform_hierarchy.c b/archive/src/transform_hierarchy.c deleted file mode 100644 index a5f4d97..0000000 --- a/archive/src/transform_hierarchy.c +++ /dev/null @@ -1,185 +0,0 @@ - -/** - * @file transform_hierarchy.h - */ -#pragma once -#include "transform_hierarchy.h" -#include -#include - -#include "core.h" -#include "log.h" -#include "maths.h" -#include "maths_types.h" -#include "render_types.h" - -// struct transform_hierarchy { -// transform_node root; -// }; - -// transform_hierarchy* transform_hierarchy_create() { -// transform_hierarchy* tfh = malloc(sizeof(struct transform_hierarchy)); - -// tfh->root = (transform_node){ .model = { ABSENT_MODEL_HANDLE }, -// .tf = TRANSFORM_DEFAULT, -// .local_matrix_tf = mat4_ident(), -// .world_matrix_tf = mat4_ident(), -// .parent = NULL, -// .children = { 0 }, -// .n_children = 0, -// .tfh = tfh }; -// return tfh; -// } - -// bool free_node(transform_node* node, void* _ctx_data) { -// if (!node) return true; // leaf node -// if (node == &node->tfh->root) { -// WARN("You can't free the root node!"); -// return false; -// } - -// printf("Freed node\n"); -// free(node); -// return true; -// } - -// void transform_hierarchy_free(transform_hierarchy* tfh) { -// transform_hierarchy_dfs(&tfh->root, free_node, false, NULL); -// free(tfh); -// } - -// transform_node* transform_hierarchy_root_node(transform_hierarchy* tfh) { return &tfh->root; } - -// transform_node* transform_hierarchy_add_node(transform_node* parent, ModelHandle model, -// Transform tf) { -// if (!parent) { -// WARN("You tried to add a node to a bad parent (NULL?)"); -// return NULL; -// } -// transform_node* node = malloc(sizeof(transform_node)); -// node->model = model; -// node->tf = tf; -// node->local_matrix_tf = mat4_ident(); -// node->world_matrix_tf = mat4_ident(); -// node->parent = parent; -// memset(node->children, 0, sizeof(node->children)); -// node->n_children = 0; -// node->tfh = parent->tfh; - -// // push into parent's children array -// u32 next_index = parent->n_children; -// if (next_index == MAX_TF_NODE_CHILDREN) { -// ERROR("This transform hierarchy node already has MAX children. Dropping."); -// free(node); -// } else { -// parent->children[next_index] = node; -// parent->n_children++; -// } - -// return node; -// } - -// void transform_hierarchy_delete_node(transform_node* node) { -// // delete all children -// for (u32 i = 0; i < node->n_children; i++) { -// transform_node* child = node->children[i]; -// transform_hierarchy_dfs(child, free_node, false, NULL); -// } - -// if (node->parent) { -// for (u32 i = 0; i < node->parent->n_children; i++) { -// transform_node* child = node->parent->children[i]; -// if (child == node) { -// node->parent->children[i] = NULL; // HACK: this will leave behind empty slots in the -// // children array of the parent. oh well. -// } -// } -// } - -// free(node); -// } - -// void transform_hierarchy_dfs(transform_node* start_node, -// bool (*visit_node)(transform_node* node, void* ctx_data), -// bool is_pre_order, void* ctx_data) { -// if (!start_node) return; - -// bool continue_traversal = true; -// if (is_pre_order) { -// continue_traversal = visit_node(start_node, ctx_data); -// } - -// if (continue_traversal) { -// for (u32 i = 0; i < start_node->n_children; i++) { -// transform_node* child = start_node->children[i]; -// transform_hierarchy_dfs(child, visit_node, is_pre_order, ctx_data); -// } -// } - -// if (!is_pre_order) { -// // post-order -// visit_node(start_node, ctx_data); -// } -// } - -// // Update matrix for the current node -// bool update_matrix(transform_node* node, void* _ctx_data) { -// if (!node) return true; // leaf node - -// if (node->parent && node->parent->tf.is_dirty) { -// node->tf.is_dirty = true; -// } - -// if (node->tf.is_dirty) { -// // invalidates children -// Mat4 updated_local_transform = transform_to_mat(&node->tf); -// node->local_matrix_tf = updated_local_transform; -// if (node->parent) { -// Mat4 updated_world_transform = -// mat4_mult(node->parent->world_matrix_tf, updated_local_transform); -// node->world_matrix_tf = updated_world_transform; -// } -// } - -// return true; -// } - -// void transform_hierarchy_propagate_transforms(transform_hierarchy* tfh) { -// // kickoff traversal -// transform_hierarchy_dfs(&tfh->root, update_matrix, false, NULL); -// } - -// struct print_ctx { -// Core* core; -// u32 indentation_lvl; -// }; - -// bool print_node(transform_node* node, void* ctx_data) { -// struct print_ctx* ctx = (struct print_ctx*)ctx_data; - -// if (!node) return true; -// if (!node->parent) { -// printf("Root Node\n"); -// ctx->indentation_lvl++; -// return true; -// } - -// // Grab the model -// // FIXME -// // model m = ctx->core->models->data[node->model.raw]; -// for (int i = 0; i < ctx->indentation_lvl; i++) { -// printf(" "); -// } -// // printf("Node %s\n", m.name.buf); -// ctx->indentation_lvl++; - -// return true; -// } - -// void transform_hierarchy_debug_print(transform_node* start_node, Core* core) { -// struct print_ctx* ctx = malloc(sizeof(struct print_ctx)); -// ctx->core = core; -// ctx->indentation_lvl = 0; -// transform_hierarchy_dfs(start_node, print_node, true, (void*)ctx); -// free(ctx); -// } diff --git a/archive/src/transform_hierarchy.h b/archive/src/transform_hierarchy.h deleted file mode 100644 index 142ea99..0000000 --- a/archive/src/transform_hierarchy.h +++ /dev/null @@ -1,80 +0,0 @@ -/** - * @file transform_hierarchy.h - */ -#pragma once - -#include "maths_types.h" -#include "ral.h" -#include "render_types.h" - -#define MAX_TF_NODE_CHILDREN \ - 32 /** TEMP: Make it simpler to manage children in `transform_node`s */ - -typedef struct TransformHierarchy TransformHierarchy; - -struct Transform_Node { - ModelHandle model; /** A handle back to what model this node represents */ - Transform tf; - Mat4 local_matrix_tf; /** cached local affine transform */ - Mat4 world_matrix_tf; /** cached world-space affine transform */ - - struct transform_node* parent; - struct transform_node* children[MAX_TF_NODE_CHILDREN]; - u32 n_children; - struct transform_hierarchy* tfh; -}; -typedef struct Transform_Node Transform_Node; -typedef struct Transform_Node TF_Node; - -// --- Lifecycle - -/** @brief Allocates and returns an empty transform hierarchy with a root node */ -TransformHierarchy* TransformHierarchy_Create(); - -// /** -// * @brief recursively frees all the children and then finally itself -// * @note in the future we can use an object pool for the nodes -// */ -// void transform_hierarchy_free(transform_hierarchy* tfh); - -// // --- Main usecase - -// /** @brief Updates matrices of any invalidated nodes based on the `is_dirty` flag inside -// `transform` -// */ -// void transform_hierarchy_propagate_transforms(transform_hierarchy* tfh); - -// // --- Queries - -// /** @brief Get a pointer to the root node */ -// Transform_Node* TransformHierarchy_RootNode(TransformHierarchy* tfh); - -// // --- Mutations -// Transform_Node* TransformHierarchy_AddNode(transform_node* parent, ModelHandle model, -// Transform tf); -// void transform_hierarchy_delete_node(transform_node* node); - -// // --- Traversal - -// /** -// * @brief Perform a depth-first search traversal starting from `start_node`. -// * @param start_node The starting node of the traversal. -// * @param visit_node The function to call for each node visited. The callback should return false -// to stop the traversal early. -// * @param is_pre_order Indicates whether to do pre-order or post-order traversal i.e. when to -// call the `visit_node` function. -// * @param ctx_data An optional pointer to data that is be passed on each call to `visit_node`. -// Can be used to carry additional information or context. -// * -// * @note The main use-cases are: -// 1. traversing the whole tree to update cached 4x4 affine transform matrices -// (post-order) -// 2. freeing child nodes after deleting a node in the tree (post-order) -// 3. debug pretty printing the whole tree (post-order) -// */ -// void transform_hierarchy_dfs(transform_node* start_node, -// bool (*visit_node)(transform_node* node, void* ctx_data), -// bool is_pre_order, void* ctx_data); - -// struct Core; -// void transform_hierarchy_debug_print(transform_node* start_node, struct Core* core); diff --git a/archive/xmake.lua b/archive/xmake.lua deleted file mode 100644 index 3c05a70..0000000 --- a/archive/xmake.lua +++ /dev/null @@ -1,205 +0,0 @@ --- set_project("celeritas") --- set_version("0.1.0") --- set_config("cc", "clang") - --- add_rules("mode.debug", "mode.release") -- we have two modes: debug & release - --- -- -Wall : base set of warnings --- -- -Wextra : additional warnings not covered by -Wall --- -- -Wundef : undefined macros --- -- -Wdouble-promotion : catch implicit converion of float to double --- add_cflags("-Wall", "-Wextra", "-Wundef", "-Wdouble-promotion") - --- if is_mode("debug") then --- add_cflags("-g") -- Add debug symbols in debug mode --- add_defines("CDEBUG") --- elseif is_mode("release") then --- add_defines("CRELEASE") --- end - --- -- Platform defines and system packages --- if is_plat("linux") then --- add_defines("CEL_PLATFORM_LINUX") --- add_syslinks("dl", "X11", "pthread") --, "vulkan") --- elseif is_plat("windows") then --- add_defines("CEL_PLATFORM_WINDOWS") --- add_syslinks("user32", "gdi32", "kernel32", "shell32") --- -- add_requires("vulkansdk", { system = true }) --- -- add_links("pthreadVC2-w64") --- elseif is_plat("macosx") then --- add_defines("CEL_PLATFORM_MAC") --- add_frameworks("Cocoa", "IOKit", "CoreVideo", "OpenGL") --- add_frameworks("Foundation", "Metal", "QuartzCore") --- set_runenv("MTL_DEBUG_LAYER", "1") --- add_requires("vulkansdk", { system = true }) --- -- add_syslinks("GL") --- end - --- -- Compile GLFW from source --- package("local_glfw") --- add_deps("cmake") --- set_sourcedir(path.join(os.scriptdir(), "deps/glfw-3.3.8")) --- on_install(function(package) --- local configs = {} --- -- NOTE(omni): Keeping these around as comments in case we need to modify glfw flags --- -- table.insert(configs, "-DCMAKE_BUILD_TYPE=" .. (package:debug() and "Debug" or "Release")) --- -- table.insert(configs, "-DBUILD_SHARED_LIBS=" .. (package:config("shared") and "ON" or "OFF")) --- import("package.tools.cmake").install(package, configs) --- end) --- on_test(function(package) --- -- assert(package:has_cfuncs("add", {includes = "foo.h"})) --- end) --- package_end() - --- add_requires("local_glfw") - --- local core_sources = { --- "deps/glad/src/glad.c", --- "src/*.c", --- "src/core/*.c", --- "src/logos/*.c", --- "src/maths/*.c", --- "src/platform/*.c", --- "src/ral/*.c", --- "src/ral/backends/opengl/*.c", --- "src/render/*.c", --- "src/resources/*.c", --- "src/std/*.c", --- "src/std/containers/*.c", --- "src/systems/*.c", --- } - --- local unity_sources = { --- "deps/Unity/src/unity.c", --- "deps/Unity/extras/fixture/src/unity_fixture.c", --- "deps/Unity/extras/memory/src/unity_memory.c", --- } - --- rule("compile_glsl_vert_shaders") --- set_extensions(".vert") --- on_buildcmd_file(function(target, batchcmds, sourcefile, opt) --- local targetfile = path.join(target:targetdir(), path.basename(sourcefile) .. ".vert.spv") - --- print("Compiling shader: %s to %s", sourcefile, targetfile) --- batchcmds:vrunv('glslc', { sourcefile, "-o", targetfile }) --- -- batchcmds:add_depfiles(sourcefile) --- end) - --- rule("compile_glsl_frag_shaders") --- set_extensions(".frag") --- on_buildcmd_file(function(target, batchcmds, sourcefile, opt) --- local targetfile = path.join(target:targetdir(), path.basename(sourcefile) .. ".frag.spv") - --- print("Compiling shader: %s to %s", sourcefile, targetfile) --- batchcmds:vrunv('glslc', { sourcefile, "-o", targetfile }) --- -- batchcmds:add_depfiles(sourcefile) --- end) --- -- TODO: Metal shaders compilation - --- -- common configuration for both static and shared libraries --- target("core_config") --- set_kind("static") -- kind is required but you can ignore it since it's just for common settings --- add_packages("local_glfw") --- add_defines("CEL_REND_BACKEND_OPENGL") --- add_includedirs("deps/cgltf", { public = true }) --- add_includedirs("deps/glfw-3.3.8/include/GLFW", { public = true }) --- add_includedirs("deps/glad/include", { public = true }) --- add_includedirs("deps/stb_image", { public = true }) --- add_includedirs("deps/stb_image_write", { public = true }) --- add_includedirs("deps/stb_truetype", { public = true }) --- add_includedirs("include/", { public = true }) --- add_includedirs("src/", { public = true }) --- add_includedirs("src/core", { public = true }) --- add_includedirs("src/logos/", { public = true }) --- add_includedirs("src/maths/", { public = true }) --- add_includedirs("src/platform/", { public = true }) --- add_includedirs("src/ral", { public = true }) --- add_includedirs("src/ral/backends/opengl", { public = true }) --- add_includedirs("src/render", { public = true }) --- add_includedirs("src/ral/backends/vulkan", { public = true }) --- add_includedirs("src/resources/", { public = true }) --- add_includedirs("src/std/", { public = true }) --- add_includedirs("src/std/containers", { public = true }) --- add_includedirs("src/systems/", { public = true }) --- add_files("src/empty.c") -- for some reason we need this on Mac so it doesnt call 'ar' with no files and error --- -- add_rules("compile_glsl_vert_shaders") --- -- add_rules("compile_glsl_frag_shaders") --- -- add_files("assets/shaders/*.frag") --- if is_plat("windows") then --- -- add_includedirs("$(env VULKAN_SDK)/Include", { public = true }) --- -- add_linkdirs("$(env VULKAN_SDK)/Lib", { public = true }) --- -- add_links("vulkan-1") --- end --- if is_plat("macosx") then --- -- add_files("src/renderer/backends/metal/*.m") --- -- add_files("src/ral/backends/vulkan/*.c") --- end --- set_default(false) -- prevents standalone building of this target - --- target("core_static") --- set_kind("static") --- add_deps("core_config") -- inherit common configurations --- set_policy("build.merge_archive", true) --- add_files(core_sources) --- -- Link against static CRT --- if is_plat("windows") then --- add_links("libcmt", "legacy_stdio_definitions") -- for release builds --- add_links("libcmtd", "legacy_stdio_definitions") -- for debug builds --- end - --- target("core_shared") --- set_kind("shared") --- add_deps("core_config") -- inherit common configurations --- add_files(core_sources) --- -- Link against dynamic CRT --- if is_plat("windows") then --- add_links("msvcrt", "legacy_stdio_definitions") -- for release builds --- add_links("msvcrtd", "legacy_stdio_definitions") -- for debug builds --- end - --- -- target("main_loop") --- -- set_kind("binary") --- -- set_group("examples") --- -- add_deps("core_static") --- -- add_files("examples/main_loop/ex_main_loop.c") --- -- set_rundir("$(projectdir)") - --- -- target("tri") --- -- set_kind("binary") --- -- set_group("examples") --- -- add_deps("core_static") --- -- add_files("examples/triangle/ex_triangle.c") --- -- set_rundir("$(projectdir)") --- -- if is_plat("macosx") then --- -- before_build(function (target) --- -- print("build metal shaders lib") --- -- os.exec("mkdir -p build/shaders") --- -- os.exec("xcrun -sdk macosx metal -c assets/shaders/triangle.metal -o build/shaders/gfx.air") --- -- os.exec("xcrun -sdk macosx metallib build/shaders/gfx.air -o build/gfx.metallib") --- -- end) --- -- end - --- target("skinned") --- set_kind("binary") --- set_group("examples") --- add_deps("core_shared") --- add_files("examples/skinned_animation/ex_skinned_animation.c") --- set_rundir("$(projectdir)") - --- target("game") --- set_kind("binary") --- set_group("examples") --- add_deps("core_static") --- add_files("examples/game_demo/game_demo.c") --- set_rundir("$(projectdir)") - --- target("pool_tests") --- set_kind("binary") --- set_group("tests") --- add_deps("core_static") --- add_files(unity_sources) --- add_includedirs("deps/Unity/src", {public = true}) --- add_includedirs("deps/Unity/extras/fixture/src", {public = true}) --- add_includedirs("deps/Unity/extras/memory/src", {public = true}) --- add_files("tests/pool_tests.c") --- add_files("tests/pool_test_runner.c") diff --git a/src/archive/src/animation.c b/src/archive/src/animation.c new file mode 100644 index 0000000..d7973dc --- /dev/null +++ b/src/archive/src/animation.c @@ -0,0 +1,90 @@ +#include "animation.h" +#include "immdraw.h" +#include "log.h" +#include "maths.h" +#include "maths_types.h" +#include "ral_types.h" + +Keyframe Animation_Sample(AnimationSampler* sampler, f32 t) { + size_t previous_index = 0; + f32 previous_time = 0.0; + // look forwards + DEBUG("%d\n", keyframe_kind_strings[sampler->animation.values.kind]); + TRACE("Total timestamps %d", sampler->animation.n_timestamps); + for (u32 i = 0; i < sampler->animation.n_timestamps; i++) { + f32 current_time = sampler->animation.timestamps[i]; + if (current_time > t) { + break; + } + previous_time = sampler->animation.timestamps[i]; + previous_index = i; + } + + size_t next_index = (previous_index + 1) % sampler->animation.n_timestamps; + f32 next_time = sampler->animation.timestamps[next_index]; + printf("%d %f %d %f\n", previous_index, previous_time, next_index, next_time); + + Keyframe prev_value = sampler->animation.values.values[previous_index]; + Keyframe next_value = sampler->animation.values.values[next_index]; + + printf("%d %d\n", previous_index, next_index); + + f32 time_diff = + sampler->animation.timestamps[next_index] - sampler->animation.timestamps[previous_index]; + f32 percent = (t - previous_time) / time_diff; + + switch (sampler->animation.values.kind) { + case KEYFRAME_ROTATION: + return (Keyframe){ .rotation = quat_slerp( + sampler->animation.values.values[previous_index].rotation, + sampler->animation.values.values[next_index].rotation, percent) }; + case KEYFRAME_TRANSLATION: + case KEYFRAME_SCALE: + case KEYFRAME_WEIGHTS: + WARN("TODO: other keyframe kind interpolation"); + return prev_value; + } +} + +void Animation_Tick(AnimationClip* clip, Armature* armature, f32 time) { + TRACE("Ticking animation %s", clip->clip_name); + + for (u32 c_i = 0; c_i < clip->channels->len; c_i++) { + AnimationSampler* sampler = clip->channels->data; + + // Interpolated keyframe based on time + Keyframe k = Animation_Sample(sampler, time); + + // Get the joint in the armature + Joint* joint = &armature->joints->data[sampler->target_joint_idx]; + if (sampler->animation.values.kind == KEYFRAME_ROTATION) { + // Update the joints rotation + joint->transform_components.rotation = k.rotation; + } else { + WARN("not yet implemented animation kind"); + } + } +} + +void Animation_VisualiseJoints(Armature* armature) { + for (int j = 0; j < armature->joints->len; j++) { + Joint joint = armature->joints->data[j]; + Transform tf = joint.transform_components; + tf.scale = vec3(0.05, 0.05, 0.05); + Immdraw_Sphere(tf, vec4(0, 1, 1, 1), true); + } +} + +ShaderDataLayout AnimData_GetLayout(void* data) { + AnimDataUniform* d = data; + bool has_data = data != NULL; + + ShaderBinding b1 = { .label = "AnimData", + .kind = BINDING_BYTES, + .data.bytes.size = sizeof(AnimDataUniform) }; + + if (has_data) { + b1.data.bytes.data = d; + } + return (ShaderDataLayout){ .bindings = { b1 }, .binding_count = 1 }; +} diff --git a/src/archive/src/animation.h b/src/archive/src/animation.h new file mode 100644 index 0000000..5883f13 --- /dev/null +++ b/src/archive/src/animation.h @@ -0,0 +1,122 @@ +#pragma once + +#include "cgltf.h" +#include "darray.h" +#include "defines.h" +#include "maths_types.h" +#include "ral_types.h" + +typedef enum Interpolation { + INTERPOLATION_STEP, + INTERPOLATION_LINEAR, + INTERPOLATION_CUBIC, /** @brief Cubic spline interpolation */ + INTERPOLATION_COUNT +} Interpolation; + +typedef enum KeyframeKind { + KEYFRAME_ROTATION, + KEYFRAME_TRANSLATION, + KEYFRAME_SCALE, + KEYFRAME_WEIGHTS, +} KeyframeKind; + +static const char* keyframe_kind_strings[4] = { "ROTATION", "TRANSLATION", "SCALE", "WEIGHTS"}; + +typedef union Keyframe { + Quat rotation; + Vec3 translation; + Vec3 scale; + f32 weights[4]; +} Keyframe; + +typedef struct Keyframes { + KeyframeKind kind; + Keyframe* values; + size_t count; +} Keyframes; + +typedef struct Joint { + // used instead of pointers later to update correct joints + size_t node_idx; + ssize_t parent; // parent bone. -1 means its the root + size_t children[8]; // children bones, upto 8 + u8 children_count; + char* debug_label; // optional + Mat4 inverse_bind_matrix; + Mat4 local_transform; + /** @brief holds position, rotation, and scale that will be written to by animation + samplers every tick of the animation system. */ + Transform transform_components; +} Joint; +#ifndef TYPED_JOINT_ARRAY +KITC_DECL_TYPED_ARRAY(Joint); +#define TYPED_JOINT_ARRAY +#endif + +typedef u32 JointIdx; + +typedef struct Armature { + char* label; + Joint_darray* joints; +} Armature; + +// NOTE: I think we will need to topologically sort the joints to store them in array if we want to +// do linear array traversal +// when calculating transforms. + +typedef struct AnimationSpline { + f32* timestamps; + size_t n_timestamps; + Keyframes values; + Interpolation interpolation; +} AnimationSpline; + +// combines a sampler and a channel in gltf +typedef struct AnimationSampler { + int current_index; + f32 min; + f32 max; + AnimationSpline animation; + u32 target_joint_idx; // index into the array of joints in an armature +} AnimationSampler; +#ifndef TYPED_ANIM_SAMPLER_ARRAY +KITC_DECL_TYPED_ARRAY(AnimationSampler); +#define TYPED_ANIM_SAMPLER_ARRAY +#endif + +/** @brief Sample an animation at a given time `t` returning an interpolated keyframe */ +PUB Keyframe Animation_Sample(AnimationSampler* sampler, f32 t); + +/** @brief A clip contains one or more animation curves. */ +typedef struct AnimationClip { + const char* clip_name; + bool is_playing; + f32 time; + AnimationSampler_darray* channels; +} AnimationClip; +#ifndef TYPED_ANIM_CLIP_ARRAY +KITC_DECL_TYPED_ARRAY(AnimationClip); +#define TYPED_ANIM_CLIP_ARRAY +#endif + +// typedef struct SkinnedAnimation { +// Mat4* joint_matrices; +// size_t n_joints; +// } SkinnedAnimation; + +PUB void Animation_Play(AnimationClip* clip); + +void Animation_Tick(AnimationClip* clip, Armature* armature, f32 delta_time); + +void Animation_VisualiseJoints(Armature* armature); + +#define MAX_BONES 100 + +typedef struct AnimDataUniform { + Mat4 bone_matrices[MAX_BONES]; +} AnimDataUniform; +ShaderDataLayout AnimData_GetLayout(void* data); + +// Animation Targets: +// - Mesh +// - Joint diff --git a/src/archive/src/apidocs/coldark_prism.css b/src/archive/src/apidocs/coldark_prism.css new file mode 100644 index 0000000..39dd470 --- /dev/null +++ b/src/archive/src/apidocs/coldark_prism.css @@ -0,0 +1,317 @@ +/** + * Coldark Theme for Prism.js + * Theme variation: Dark + * Tested with HTML, CSS, JS, JSON, PHP, YAML, Bash script + * @author Armand Philippot + * @homepage https://github.com/ArmandPhilippot/coldark-prism + * @license MIT + */ +code[class*="language-"], +pre[class*="language-"] { + color: #e3eaf2; + background: none; + font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +pre[class*="language-"]::-moz-selection, +pre[class*="language-"] ::-moz-selection, +code[class*="language-"]::-moz-selection, +code[class*="language-"] ::-moz-selection { + background: #3c526d; +} + +pre[class*="language-"]::selection, +pre[class*="language-"] ::selection, +code[class*="language-"]::selection, +code[class*="language-"] ::selection { + background: #3c526d; +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; +} + +:not(pre) > code[class*="language-"], +pre[class*="language-"] { + background: #111b27; +} + +/* Inline code */ +:not(pre) > code[class*="language-"] { + padding: 0.1em 0.3em; + border-radius: 0.3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: #8da1b9; +} + +.token.punctuation { + color: #e3eaf2; +} + +.token.delimiter.important, +.token.selector .parent, +.token.tag, +.token.tag .token.punctuation { + color: #66cccc; +} + +.token.attr-name, +.token.boolean, +.token.boolean.important, +.token.number, +.token.constant, +.token.selector .token.attribute { + color: #e6d37a; +} + +.token.class-name, +.token.key, +.token.parameter, +.token.property, +.token.property-access, +.token.variable { + color: #6cb8e6; +} + +.token.attr-value, +.token.inserted, +.token.color, +.token.selector .token.value, +.token.string, +.token.string .token.url-link { + color: #91d076; +} + +.token.builtin, +.token.keyword-array, +.token.package, +.token.regex { + color: #f4adf4; +} + +.token.function, +.token.selector .token.class, +.token.selector .token.id { + color: #c699e3; +} + +.token.atrule .token.rule, +.token.combinator, +.token.keyword, +.token.operator, +.token.pseudo-class, +.token.pseudo-element, +.token.selector, +.token.unit { + color: #e9ae7e; +} + +.token.deleted, +.token.important { + color: #cd6660; +} + +.token.keyword-this, +.token.this { + color: #6cb8e6; +} + +.token.important, +.token.keyword-this, +.token.this, +.token.bold { + font-weight: bold; +} + +.token.delimiter.important { + font-weight: inherit; +} + +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +.language-markdown .token.title, +.language-markdown .token.title .token.punctuation { + color: #6cb8e6; + font-weight: bold; +} + +.language-markdown .token.blockquote.punctuation { + color: #f4adf4; +} + +.language-markdown .token.code { + color: #66cccc; +} + +.language-markdown .token.hr.punctuation { + color: #6cb8e6; +} + +.language-markdown .token.url .token.content { + color: #91d076; +} + +.language-markdown .token.url-link { + color: #e6d37a; +} + +.language-markdown .token.list.punctuation { + color: #f4adf4; +} + +.language-markdown .token.table-header { + color: #e3eaf2; +} + +.language-json .token.operator { + color: #e3eaf2; +} + +.language-scss .token.variable { + color: #66cccc; +} + +/* overrides color-values for the Show Invisibles plugin + * https://prismjs.com/plugins/show-invisibles/ + */ +.token.token.tab:not(:empty):before, +.token.token.cr:before, +.token.token.lf:before, +.token.token.space:before { + color: #8da1b9; +} + +/* overrides color-values for the Toolbar plugin + * https://prismjs.com/plugins/toolbar/ + */ +div.code-toolbar > .toolbar.toolbar > .toolbar-item > a, +div.code-toolbar > .toolbar.toolbar > .toolbar-item > button { + color: #111b27; + background: #6cb8e6; +} + +div.code-toolbar > .toolbar.toolbar > .toolbar-item > a:hover, +div.code-toolbar > .toolbar.toolbar > .toolbar-item > a:focus, +div.code-toolbar > .toolbar.toolbar > .toolbar-item > button:hover, +div.code-toolbar > .toolbar.toolbar > .toolbar-item > button:focus { + color: #111b27; + background: #6cb8e6da; + text-decoration: none; +} + +div.code-toolbar > .toolbar.toolbar > .toolbar-item > span, +div.code-toolbar > .toolbar.toolbar > .toolbar-item > span:hover, +div.code-toolbar > .toolbar.toolbar > .toolbar-item > span:focus { + color: #111b27; + background: #8da1b9; +} + +/* overrides color-values for the Line Highlight plugin + * http://prismjs.com/plugins/line-highlight/ + */ +.line-highlight.line-highlight { + background: #3c526d5f; + background: linear-gradient(to right, #3c526d5f 70%, #3c526d55); +} + +.line-highlight.line-highlight:before, +.line-highlight.line-highlight[data-end]:after { + background-color: #8da1b9; + color: #111b27; + box-shadow: 0 1px #3c526d; +} + +pre[id].linkable-line-numbers.linkable-line-numbers span.line-numbers-rows > span:hover:before { + background-color: #8da1b918; +} + +/* overrides color-values for the Line Numbers plugin + * http://prismjs.com/plugins/line-numbers/ + */ +.line-numbers.line-numbers .line-numbers-rows { + border-right: 1px solid #0b121b; + background: #0b121b7a; +} + +.line-numbers .line-numbers-rows > span:before { + color: #8da1b9da; +} + +/* overrides color-values for the Match Braces plugin + * https://prismjs.com/plugins/match-braces/ + */ +.rainbow-braces .token.token.punctuation.brace-level-1, +.rainbow-braces .token.token.punctuation.brace-level-5, +.rainbow-braces .token.token.punctuation.brace-level-9 { + color: #e6d37a; +} + +.rainbow-braces .token.token.punctuation.brace-level-2, +.rainbow-braces .token.token.punctuation.brace-level-6, +.rainbow-braces .token.token.punctuation.brace-level-10 { + color: #f4adf4; +} + +.rainbow-braces .token.token.punctuation.brace-level-3, +.rainbow-braces .token.token.punctuation.brace-level-7, +.rainbow-braces .token.token.punctuation.brace-level-11 { + color: #6cb8e6; +} + +.rainbow-braces .token.token.punctuation.brace-level-4, +.rainbow-braces .token.token.punctuation.brace-level-8, +.rainbow-braces .token.token.punctuation.brace-level-12 { + color: #c699e3; +} + +/* overrides color-values for the Diff Highlight plugin + * https://prismjs.com/plugins/diff-highlight/ + */ +pre.diff-highlight > code .token.token.deleted:not(.prefix), +pre > code.diff-highlight .token.token.deleted:not(.prefix) { + background-color: #cd66601f; +} + +pre.diff-highlight > code .token.token.inserted:not(.prefix), +pre > code.diff-highlight .token.token.inserted:not(.prefix) { + background-color: #91d0761f; +} + +/* overrides color-values for the Command Line plugin + * https://prismjs.com/plugins/command-line/ + */ +.command-line .command-line-prompt { + border-right: 1px solid #0b121b; +} + +.command-line .command-line-prompt > span:before { + color: #8da1b9da; +} diff --git a/src/archive/src/apidocs/doc_styles.css b/src/archive/src/apidocs/doc_styles.css new file mode 100644 index 0000000..ee0851b --- /dev/null +++ b/src/archive/src/apidocs/doc_styles.css @@ -0,0 +1,76 @@ +/* + Josh's Custom CSS Reset + https://www.joshwcomeau.com/css/custom-css-reset/ +*/ +*, *::before, *::after { + box-sizing: border-box; +} +* { + margin: 0; +} +body { + line-height: 1.5; + -webkit-font-smoothing: antialiased; +} +img, picture, video, canvas, svg { + display: block; + max-width: 100%; +} +input, button, textarea, select { + font: inherit; +} +p, h1, h2, h3, h4, h5, h6 { + overflow-wrap: break-word; +} +#root, #__next { + isolation: isolate; +} + +/* Styles */ + +html { + -webkit-text-size-adjust: 100%; + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; /* 4 */ + font-feature-settings: normal; + font-variation-settings: normal; +} + +pre { + margin: 0; + padding: 0; +} +code { + margin: 0; + padding: 6px 0 !important +} + +:root { + /* TODO: create basic greyscale colours */ +} + +main { + padding: 12px; +} + +h1 { + font-size: 18px; + margin-bottom: 20px; + /* font-weight: 700; */ +} + +h3 { + font-size: 16px; + font-weight: 700; + text-transform: uppercase; +} + +.category-list { + padding: 10px 20px; + list-style-type: none; +} + +.signature { +} diff --git a/src/archive/src/apidocs/gen_apidocs.py b/src/archive/src/apidocs/gen_apidocs.py new file mode 100644 index 0000000..d01e441 --- /dev/null +++ b/src/archive/src/apidocs/gen_apidocs.py @@ -0,0 +1,119 @@ +# Generates a static webpage for the public C-API of `celeritas-core` +# +# TODO: +# - remove prefixes like 'static' and 'inline' +# - parse docstrings from source + +import re +import os +from pathlib import Path + +# --- HTML Fragments +page_start = """ + + + + + + + + + + + + + + + + Celeritas core API + + +
    +""" + +page_header = """ +
    +

    CELERITAS CORE API DOCS

    +
    +""" + +page_footer = """ +
    +
    +""" + +page_end = """ +
    + + +""" + +def emit_function_sig(signature: str) -> str: + return f""" +
  • +
    {signature}
    +
  • + """ + +categories = { + "Core": "src/core", + "Render": "src/new_render", + "Maths": "src/maths", + "RAL": "src/ral", + "Systems": "src/systems", +} + +def find_pub_functions_in_folder(folder_path): + functions = [] + for filename in os.listdir(folder_path): + filepath = os.path.join(folder_path, filename) + if os.path.isfile(filepath): + file_funcs = find_pub_functions_in_file(filepath) + functions.extend(file_funcs) + + return functions + +def find_pub_functions_in_file(file_path): + pattern = r'PUB\s+(\w+\s+)*(\w+)\s+(\w+)\s*\((.*?)\)' + + with open(file_path, 'r') as file: + content = file.read() + + matches = re.finditer(pattern, content, re.MULTILINE) + + # Collect all the functions into an array + functions = [] + for match in matches: + signature = match.group(0) + if signature.startswith("PUB "): + signature = signature[4:] + if signature.startswith("c_static_inline "): + signature = signature[16:] + + print(signature) + functions.append(signature) + + return functions + +def generate_html(): + html_filepath = "index.html" + + script_dir = Path(__file__).resolve().parent + grandparent_dir = script_dir.parents[1] + + with open(html_filepath, 'w') as export_file: + export_file.write(page_start) + export_file.write(page_header) + # TODO: make the actual content + for category in categories.keys(): + folder = os.path.join(grandparent_dir, categories[category]) + category_funcs = find_pub_functions_in_folder(folder) + export_file.write(f"

    {category}

    ") + export_file.write("
      ") + for func in category_funcs: + export_file.write(emit_function_sig(func)) + export_file.write("
    ") + export_file.write(page_end) + +if __name__ == "__main__": + generate_html() diff --git a/src/archive/src/apidocs/index.html b/src/archive/src/apidocs/index.html new file mode 100644 index 0000000..a72dbf3 --- /dev/null +++ b/src/archive/src/apidocs/index.html @@ -0,0 +1,304 @@ + + + + + + + + + + + + + + + + + Celeritas core API + + +
    + +
    +

    CELERITAS CORE API DOCS

    +
    +

    Core

      +
    • +
      Camera Camera_Create(Vec3 pos, Vec3 front, Vec3 up, f32 fov)
      +
    • + +
    • +
      Mat4 Camera_View2D(Camera* c)
      +
    • + +
    • +
      void FlyCamera_Update(Camera* camera)
      +
    • +

    Render

      +
    • +
      Skybox Skybox_Create(const char** face_paths, int n)
      +
    • + +
    • +
      void Skybox_Draw(Skybox* skybox, Camera camera)
      +
    • + +
    • +
      void SetCamera(Camera camera)
      +
    • + +
    • +
      void SetMainLight(DirectionalLight light)
      +
    • + +
    • +
      void PBR_Init(PBR_Storage* storage)
      +
    • + +
    • +
      Material PBRMaterialDefault()
      +
    • + +
    • +
      ShaderDataLayout PBRMaterial_GetLayout(void* data)
      +
    • + +
    • +
      void Shadow_Init(Shadow_Storage* storage, u32 shadowmap_width, u32 shadowmap_height)
      +
    • + +
    • +
      void Shadow_Run(RenderEnt* entities, size_t entity_count)
      +
    • + +
    • +
      void Shadow_DrawDebugQuad()
      +
    • + +
    • +
      TextureHandle Shadow_GetShadowMapTexture(Shadow_Storage* storage)
      +
    • + +
    • +
      void Immdraw_Init(Immdraw_Storage* storage)
      +
    • + +
    • +
      void Immdraw_Shutdown(Immdraw_Storage* storage)
      +
    • + +
    • +
      void Immdraw_Plane(Transform tf, Vec4 colour, bool wireframe)
      +
    • + +
    • +
      void Immdraw_Cuboid(Transform tf, Vec4 colour, bool wireframe)
      +
    • + +
    • +
      void Immdraw_Sphere(Transform tf, f32 size, Vec4 colour, bool wireframe)
      +
    • + +
    • +
      void Immdraw_TransformGizmo(Transform tf, f32 size)
      +
    • + +
    • +
      void EncodeDrawModel(Handle model, Mat4 transform)
      +
    • + +
    • +
      void EncodeDrawMesh(Mesh* mesh, Material* material, Mat4 affine)
      +
    • + +
    • +
      void Renderer_Shutdown(Renderer* renderer)
      +
    • + +
    • +
      size_t Renderer_GetMemReqs()
      +
    • + +
    • +
      void Render_FrameBegin(Renderer* renderer)
      +
    • + +
    • +
      void Render_FrameEnd(Renderer* renderer)
      +
    • + +
    • +
      void Render_RenderEntities(RenderEnt* entities, size_t entity_count)
      +
    • + +
    • +
      TextureData TextureDataLoad(const char* path, bool invert_y)
      +
    • + +
    • +
      void TextureUpload(TextureHandle handle, size_t n_bytes, const void* data)
      +
    • + +
    • +
      TextureHandle TextureLoadFromFile(const char* path)
      +
    • + +
    • +
      ModelHandle ModelLoad(const char* debug_name, const char* filepath)
      +
    • + +
    • +
      Mesh Mesh_Create(Geometry* geometry, bool free_on_upload)
      +
    • + +
    • +
      void Mesh_Delete(Mesh* mesh)
      +
    • + +
    • +
      void DrawMesh(Mesh* mesh, Material* material, Mat4 model)
      +
    • + +
    • +
      void Render_DrawTerrain()
      +
    • +

    Maths

      +
    • +
      Vec3 vec3_normalise(Vec3 a)
      +
    • + +
    • +
      Vec3 vec3_create(f32 x, f32 y, f32 z)
      +
    • + +
    • +
      Vec3 vec3_add(Vec3 a, Vec3 b)
      +
    • + +
    • +
      Vec3 vec3_sub(Vec3 a, Vec3 b)
      +
    • + +
    • +
      Vec3 vec3_mult(Vec3 a, f32 s)
      +
    • + +
    • +
      Vec3 vec3_div(Vec3 a, f32 s)
      +
    • + +
    • +
      f32 vec3_len_squared(Vec3 a)
      +
    • + +
    • +
      f32 vec3_len(Vec3 a)
      +
    • + +
    • +
      Vec3 vec3_negate(Vec3 a)
      +
    • + +
    • +
      Vec3 vec3_normalise(Vec3 a)
      +
    • + +
    • +
      f32 vec3_dot(Vec3 a, Vec3 b)
      +
    • + +
    • +
      Vec3 vec3_cross(Vec3 a, Vec3 b)
      +
    • +

    RAL

      +
    • +
      void GPU_Renderpass_Destroy(GPU_Renderpass* pass)
      +
    • + +
    • +
      void GraphicsPipeline_Destroy(GPU_Pipeline* pipeline)
      +
    • + +
    • +
      GPU_CmdEncoder GPU_CmdEncoder_Create()
      +
    • + +
    • +
      void GPU_CmdEncoder_Destroy(GPU_CmdEncoder* encoder)
      +
    • + +
    • +
      void GPU_CmdEncoder_Begin(GPU_CmdEncoder* encoder)
      +
    • + +
    • +
      void GPU_CmdEncoder_Finish(GPU_CmdEncoder* encoder)
      +
    • + +
    • +
      void GPU_CmdEncoder_BeginRender(GPU_CmdEncoder* encoder, GPU_Renderpass* renderpass)
      +
    • + +
    • +
      void GPU_CmdEncoder_EndRender(GPU_CmdEncoder* encoder)
      +
    • + +
    • +
      void GPU_QueueSubmit(GPU_CmdBuffer* cmd_buffer)
      +
    • + +
    • +
      void GPU_BufferDestroy(BufferHandle handle)
      +
    • + +
    • +
      void GPU_BufferUpload(BufferHandle buffer, size_t n_bytes, const void* data)
      +
    • + +
    • +
      TextureHandle GPU_TextureCreate(TextureDesc desc, bool create_view, const void* data)
      +
    • + +
    • +
      void GPU_TextureDestroy(TextureHandle handle)
      +
    • + +
    • +
      void GPU_TextureUpload(TextureHandle handle, size_t n_bytes, const void* data)
      +
    • + +
    • +
      void GPU_EncodeBindPipeline(GPU_CmdEncoder* encoder, GPU_Pipeline* pipeline)
      +
    • + +
    • +
      void GPU_EncodeBindShaderData(GPU_CmdEncoder* encoder, u32 group, ShaderData data)
      +
    • + +
    • +
      void GPU_EncodeSetVertexBuffer(GPU_CmdEncoder* encoder, BufferHandle buf)
      +
    • + +
    • +
      void GPU_EncodeSetIndexBuffer(GPU_CmdEncoder* encoder, BufferHandle buf)
      +
    • + +
    • +
      void GPU_EncodeDraw(GPU_CmdEncoder* encoder, u64 count)
      +
    • + +
    • +
      void GPU_EncodeDrawIndexed(GPU_CmdEncoder* encoder, u64 index_count)
      +
    • + +
    • +
      bool GPU_Backend_BeginFrame()
      +
    • + +
    • +
      void GPU_Backend_EndFrame()
      +
    • +
    +
    + + diff --git a/src/archive/src/apidocs/modules.md b/src/archive/src/apidocs/modules.md new file mode 100644 index 0000000..7298844 --- /dev/null +++ b/src/archive/src/apidocs/modules.md @@ -0,0 +1,18 @@ + + +- core lifecycle +- memory + - arena + - pool +- containers + - darray + - hashtbl + - ring_queue +- maths +- physics +- platform + - file + - path + - mutex + - thread +- threadpool \ No newline at end of file diff --git a/src/archive/src/apidocs/prism.css b/src/archive/src/apidocs/prism.css new file mode 100644 index 0000000..333e985 --- /dev/null +++ b/src/archive/src/apidocs/prism.css @@ -0,0 +1,3 @@ +/* PrismJS 1.29.0 +https://prismjs.com/download.html#themes=prism&languages=markup+css+clike */ +code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help} diff --git a/src/archive/src/apidocs/prism.js b/src/archive/src/apidocs/prism.js new file mode 100644 index 0000000..d0b4c05 --- /dev/null +++ b/src/archive/src/apidocs/prism.js @@ -0,0 +1,6 @@ +/* PrismJS 1.29.0 +https://prismjs.com/download.html#themes=prism&languages=markup+css+clike */ +var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(e){var n=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,r={},a={manual:e.Prism&&e.Prism.manual,disableWorkerMessageHandler:e.Prism&&e.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof i?new i(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,"&").replace(/=g.reach);A+=w.value.length,w=w.next){var E=w.value;if(n.length>e.length)return;if(!(E instanceof i)){var P,L=1;if(y){if(!(P=l(b,A,e,m))||P.index>=e.length)break;var S=P.index,O=P.index+P[0].length,j=A;for(j+=w.value.length;S>=j;)j+=(w=w.next).value.length;if(A=j-=w.value.length,w.value instanceof i)continue;for(var C=w;C!==n.tail&&(jg.reach&&(g.reach=W);var z=w.prev;if(_&&(z=u(n,z,_),A+=_.length),c(n,z,L),w=u(n,z,new i(f,p?a.tokenize(N,p):N,k,N)),M&&u(n,w,M),L>1){var I={cause:f+","+d,reach:W};o(e,n,t,w.prev,A,I),g&&I.reach>g.reach&&(g.reach=I.reach)}}}}}}function s(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function u(e,n,t){var r=n.next,a={value:t,prev:n,next:r};return n.next=a,r.prev=a,e.length++,a}function c(e,n,t){for(var r=n.next,a=0;a"+i.content+""},!e.document)return e.addEventListener?(a.disableWorkerMessageHandler||e.addEventListener("message",(function(n){var t=JSON.parse(n.data),r=t.language,i=t.code,l=t.immediateClose;e.postMessage(a.highlight(i,a.languages[r],r)),l&&e.close()}),!1),a):a;var g=a.util.currentScript();function f(){a.manual||a.highlightAll()}if(g&&(a.filename=g.src,g.hasAttribute("data-manual")&&(a.manual=!0)),!a.manual){var h=document.readyState;"loading"===h||"interactive"===h&&g&&g.defer?document.addEventListener("DOMContentLoaded",f):window.requestAnimationFrame?window.requestAnimationFrame(f):window.setTimeout(f,16)}return a}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism); +Prism.languages.markup={comment:{pattern://,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern://i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},{pattern:/^(\s*)["']|["']$/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},Prism.languages.markup.tag.inside["attr-value"].inside.entity=Prism.languages.markup.entity,Prism.languages.markup.doctype.inside["internal-subset"].inside=Prism.languages.markup,Prism.hooks.add("wrap",(function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))})),Object.defineProperty(Prism.languages.markup.tag,"addInlined",{value:function(a,e){var s={};s["language-"+e]={pattern:/(^$)/i,lookbehind:!0,inside:Prism.languages[e]},s.cdata=/^$/i;var t={"included-cdata":{pattern://i,inside:s}};t["language-"+e]={pattern:/[\s\S]+/,inside:Prism.languages[e]};var n={};n[a]={pattern:RegExp("(<__[^>]*>)(?:))*\\]\\]>|(?!)".replace(/__/g,(function(){return a})),"i"),lookbehind:!0,greedy:!0,inside:t},Prism.languages.insertBefore("markup","cdata",n)}}),Object.defineProperty(Prism.languages.markup.tag,"addAttribute",{value:function(a,e){Prism.languages.markup.tag.inside["special-attr"].push({pattern:RegExp("(^|[\"'\\s])(?:"+a+")\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s'\">=]+(?=[\\s>]))","i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[e,"language-"+e],inside:Prism.languages[e]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup,Prism.languages.xml=Prism.languages.extend("markup",{}),Prism.languages.ssml=Prism.languages.xml,Prism.languages.atom=Prism.languages.xml,Prism.languages.rss=Prism.languages.xml; +!function(s){var e=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;s.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:RegExp("@[\\w-](?:[^;{\\s\"']|\\s+(?!\\s)|"+e.source+")*?(?:;|(?=\\s*\\{))"),inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+e.source+"|(?:[^\\\\\r\n()\"']|\\\\[^])*)\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+e.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+e.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:e,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},s.languages.css.atrule.inside.rest=s.languages.css;var t=s.languages.markup;t&&(t.tag.addInlined("style","css"),t.tag.addAttribute("style","css"))}(Prism); +Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/}; diff --git a/src/archive/src/apidocs/template.html b/src/archive/src/apidocs/template.html new file mode 100644 index 0000000..1e1c7a7 --- /dev/null +++ b/src/archive/src/apidocs/template.html @@ -0,0 +1,91 @@ + + + + + + + + + +
    +

    Celeritas Core API

    + +
    +
    + arena + arena_create(void* + backing_buffer, + size_t + capacity); +
    +
    + void* + arena_alloc(arena* + a, + size_t + size); +
    + +
    + + + + \ No newline at end of file diff --git a/src/archive/src/collision.c b/src/archive/src/collision.c new file mode 100644 index 0000000..81cbcfc --- /dev/null +++ b/src/archive/src/collision.c @@ -0,0 +1,9 @@ +#include "immdraw.h" +#include "maths.h" +#include "maths_types.h" +#include "physics.h" + +PUB void Debug_DrawOBB(OBB obb) { + Transform t = transform_create(obb.center, obb.rotation, vec3_sub(obb.bbox.max, obb.bbox.min)); + Immdraw_Cuboid(t, vec4(0.0, 0.8, 0.1, 1.0), true); +} diff --git a/src/archive/src/colours.h b/src/archive/src/colours.h new file mode 100644 index 0000000..ac8996a --- /dev/null +++ b/src/archive/src/colours.h @@ -0,0 +1,89 @@ +#pragma once + +#include "defines.h" + +typedef struct rgba { + f32 r, g, b, a; +} rgba; + +#define COLOUR_BLACK ((rgba){ 0.02, 0.02, 0.0, 1.0 }) +#define COLOUR_IMPERIAL_RED ((rgba){ 0.97, 0.09, 0.21, 1.0 }) +#define COLOUR_TRUE_BLUE ((rgba){ 0.11, 0.41, 0.77, 1.0 }) +#define COLOUR_SEA_GREEN ((rgba){ 0.18, 0.77, 0.71, 1.0 }) +#define COLOUR_WHITE ((rgba){ 1.0, 1.0, 1.0, 1.0 }) + +#define rgba_to_vec4(color) (vec4(color.r, color.g, color.b, color.a)) +#define rgba_to_vec3(color) (vec3(color.r, color.g, color.b)) + +// Thanks ChatGPT +#define STONE_50 ((rgba){ 0.980, 0.980, 0.976, 1.0 }) +#define STONE_100 ((rgba){ 0.961, 0.961, 0.957, 1.0 }) +#define STONE_200 ((rgba){ 0.906, 0.898, 0.894, 1.0 }) +#define STONE_300 ((rgba){ 0.839, 0.827, 0.819, 1.0 }) +#define STONE_400 ((rgba){ 0.659, 0.635, 0.620, 1.0 }) +#define STONE_500 ((rgba){ 0.471, 0.443, 0.424, 1.0 }) +#define STONE_600 ((rgba){ 0.341, 0.325, 0.306, 1.0 }) +#define STONE_700 ((rgba){ 0.267, 0.251, 0.235, 1.0 }) +#define STONE_800 ((rgba){ 0.161, 0.145, 0.141, 1.0 }) +#define STONE_900 ((rgba){ 0.110, 0.098, 0.090, 1.0 }) +#define STONE_950 ((rgba){ 0.047, 0.043, 0.035, 1.0 }) + +#define CYAN_50 ((rgba){ 0.930, 1.000, 1.000, 1.0 }) +#define CYAN_100 ((rgba){ 0.810, 0.980, 1.000, 1.0 }) +#define CYAN_200 ((rgba){ 0.650, 0.953, 0.988, 1.0 }) +#define CYAN_300 ((rgba){ 0.404, 0.910, 0.976, 1.0 }) +#define CYAN_400 ((rgba){ 0.133, 0.827, 0.933, 1.0 }) +#define CYAN_500 ((rgba){ 0.023, 0.714, 0.831, 1.0 }) +#define CYAN_600 ((rgba){ 0.031, 0.569, 0.698, 1.0 }) +#define CYAN_700 ((rgba){ 0.055, 0.455, 0.565, 1.0 }) +#define CYAN_800 ((rgba){ 0.082, 0.369, 0.459, 1.0 }) +#define CYAN_900 ((rgba){ 0.086, 0.306, 0.388, 1.0 }) +#define CYAN_950 ((rgba){ 0.033, 0.200, 0.263, 1.0 }) + +#define GRAY_50 ((rgba){ 0.976, 0.980, 0.984, 1.0 }) +#define GRAY_100 ((rgba){ 0.953, 0.957, 0.965, 1.0 }) +#define GRAY_200 ((rgba){ 0.898, 0.906, 0.922, 1.0 }) +#define GRAY_300 ((rgba){ 0.820, 0.835, 0.859, 1.0 }) +#define GRAY_400 ((rgba){ 0.612, 0.639, 0.686, 1.0 }) +#define GRAY_500 ((rgba){ 0.420, 0.447, 0.502, 1.0 }) +#define GRAY_600 ((rgba){ 0.294, 0.333, 0.388, 1.0 }) +#define GRAY_700 ((rgba){ 0.216, 0.255, 0.318, 1.0 }) +#define GRAY_800 ((rgba){ 0.122, 0.161, 0.216, 1.0 }) +#define GRAY_900 ((rgba){ 0.067, 0.094, 0.153, 1.0 }) +#define GRAY_950 ((rgba){ 0.012, 0.027, 0.071, 1.0 }) + +#define RED_50 ((rgba){ 0.996, 0.949, 0.949, 1.0 }) +#define RED_100 ((rgba){ 0.996, 0.886, 0.886, 1.0 }) +#define RED_200 ((rgba){ 0.996, 0.792, 0.792, 1.0 }) +#define RED_300 ((rgba){ 0.988, 0.647, 0.647, 1.0 }) +#define RED_400 ((rgba){ 0.973, 0.443, 0.443, 1.0 }) +#define RED_500 ((rgba){ 0.937, 0.267, 0.267, 1.0 }) +#define RED_600 ((rgba){ 0.863, 0.149, 0.149, 1.0 }) +#define RED_700 ((rgba){ 0.725, 0.110, 0.110, 1.0 }) +#define RED_800 ((rgba){ 0.600, 0.106, 0.106, 1.0 }) +#define RED_900 ((rgba){ 0.498, 0.114, 0.114, 1.0 }) +#define RED_950 ((rgba){ 0.271, 0.039, 0.039, 1.0 }) + +#define ORANGE_50 ((rgba){ 1.000, 0.969, 0.929, 1.0 }) +#define ORANGE_100 ((rgba){ 1.000, 0.929, 0.835, 1.0 }) +#define ORANGE_200 ((rgba){ 0.996, 0.843, 0.667, 1.0 }) +#define ORANGE_300 ((rgba){ 0.992, 0.729, 0.455, 1.0 }) +#define ORANGE_400 ((rgba){ 0.984, 0.573, 0.235, 1.0 }) +#define ORANGE_500 ((rgba){ 0.976, 0.451, 0.086, 1.0 }) +#define ORANGE_600 ((rgba){ 0.918, 0.345, 0.047, 1.0 }) +#define ORANGE_700 ((rgba){ 0.761, 0.255, 0.047, 1.0 }) +#define ORANGE_800 ((rgba){ 0.604, 0.204, 0.071, 1.0 }) +#define ORANGE_900 ((rgba){ 0.486, 0.176, 0.071, 1.0 }) +#define ORANGE_950 ((rgba){ 0.263, 0.078, 0.027, 1.0 }) + +#define AMBER_50 ((rgba){ 1.000, 0.984, 0.922, 1.0 }) +#define AMBER_100 ((rgba){ 0.996, 0.953, 0.780, 1.0 }) +#define AMBER_200 ((rgba){ 0.992, 0.902, 0.541, 1.0 }) +#define AMBER_300 ((rgba){ 0.988, 0.827, 0.302, 1.0 }) +#define AMBER_400 ((rgba){ 0.984, 0.749, 0.141, 1.0 }) +#define AMBER_500 ((rgba){ 0.961, 0.620, 0.043, 1.0 }) +#define AMBER_600 ((rgba){ 0.851, 0.467, 0.024, 1.0 }) +#define AMBER_700 ((rgba){ 0.706, 0.325, 0.035, 1.0 }) +#define AMBER_800 ((rgba){ 0.573, 0.251, 0.055, 1.0 }) +#define AMBER_900 ((rgba){ 0.471, 0.208, 0.059, 1.0 }) +#define AMBER_950 ((rgba){ 0.271, 0.102, 0.012, 1.0 }) diff --git a/src/archive/src/core/README.md b/src/archive/src/core/README.md new file mode 100644 index 0000000..19cc1d0 --- /dev/null +++ b/src/archive/src/core/README.md @@ -0,0 +1,3 @@ +# Core + +Core engine facilities diff --git a/src/archive/src/core/animation.c b/src/archive/src/core/animation.c new file mode 100644 index 0000000..e69de29 diff --git a/src/archive/src/core/camera.c b/src/archive/src/core/camera.c new file mode 100644 index 0000000..77ddad6 --- /dev/null +++ b/src/archive/src/core/camera.c @@ -0,0 +1,90 @@ +#include "camera.h" + +#include "input.h" +#include "keys.h" +#include "maths.h" + +#define CAMERA_SPEED 0.2 +#define CAMERA_SENSITIVITY 0.5 + +Camera Camera_Create(Vec3 pos, Vec3 front, Vec3 up, f32 fov) { + Camera c = { .position = pos, .front = front, .up = up, .fov = fov }; + return c; +} + +Mat4 Camera_ViewProj(Camera* c, f32 lens_height, f32 lens_width, Mat4* out_view, Mat4* out_proj) { + Mat4 proj = mat4_perspective(c->fov, lens_width / lens_height, 0.1, 1000.0); + Vec3 camera_direction = vec3_add(c->position, c->front); + Mat4 view = mat4_look_at(c->position, camera_direction, c->up); + if (out_view) { + *out_view = view; + } + if (out_proj) { + *out_proj = proj; + } + return mat4_mult(view, proj); +} + +void FlyCamera_Update(Camera* camera) { + static f32 yaw = 0.0; + static f32 pitch = 0.0; + + // Keyboard + f32 speed = CAMERA_SPEED; + Vec3 horizontal = vec3_cross(camera->front, camera->up); + if (key_is_pressed(KEYCODE_A) || key_is_pressed(KEYCODE_KEY_LEFT)) { + Vec3 displacement = vec3_mult(horizontal, -speed); + camera->position = vec3_add(camera->position, displacement); + } + if (key_is_pressed(KEYCODE_D) || key_is_pressed(KEYCODE_KEY_RIGHT)) { + Vec3 displacement = vec3_mult(horizontal, speed); + camera->position = vec3_add(camera->position, displacement); + } + if (key_is_pressed(KEYCODE_W) || key_is_pressed(KEYCODE_KEY_UP)) { + Vec3 displacement = vec3_mult(camera->front, speed); + camera->position = vec3_add(camera->position, displacement); + } + if (key_is_pressed(KEYCODE_S) || key_is_pressed(KEYCODE_KEY_DOWN)) { + Vec3 displacement = vec3_mult(camera->front, -speed); + camera->position = vec3_add(camera->position, displacement); + } + if (key_is_pressed(KEYCODE_Q)) { + Vec3 displacement = vec3_mult(camera->up, speed); + camera->position = vec3_add(camera->position, displacement); + } + if (key_is_pressed(KEYCODE_E)) { + Vec3 displacement = vec3_mult(camera->up, -speed); + camera->position = vec3_add(camera->position, displacement); + } + + // Mouse + if (MouseBtn_Held(MOUSEBTN_LEFT)) { + mouse_state mouse = Input_GetMouseState(); + // printf("Delta x: %d Delta y %d\n",mouse.x_delta, mouse.y_delta ); + + f32 x_offset = mouse.x_delta; + f32 y_offset = -mouse.y_delta; + + f32 sensitivity = CAMERA_SENSITIVITY; // change this value to your liking + x_offset *= sensitivity; + y_offset *= sensitivity; + + yaw += x_offset; + pitch += y_offset; + + // make sure that when pitch is out of bounds, screen doesn't get flipped + if (pitch > 89.0f) pitch = 89.0f; + if (pitch < -89.0f) pitch = -89.0f; + + Vec3 front; + front.x = cos(deg_to_rad(yaw) * cos(deg_to_rad(pitch))); + front.y = sin(deg_to_rad(pitch)); + front.z = sin(deg_to_rad(yaw)) * cos(deg_to_rad(pitch)); + front = vec3_normalise(front); + camera->front.x = front.x; + camera->front.y = front.y; + camera->front.z = front.z; + } + + // TODO: Right mouse => pan in screen space +} diff --git a/src/archive/src/core/camera.h b/src/archive/src/core/camera.h new file mode 100644 index 0000000..4300f87 --- /dev/null +++ b/src/archive/src/core/camera.h @@ -0,0 +1,39 @@ +#pragma once + +#include "defines.h" +#include "maths_types.h" + +// TODO: swap to position + quaternion + +typedef struct Camera { + Vec3 position; + Vec3 front; + Vec3 up; + f32 fov; +} Camera; + +/** @brief create a camera */ +PUB Camera Camera_Create(Vec3 pos, Vec3 front, Vec3 up, f32 fov); + +/** + * @brief Get 3D camera transform matrix + * @param out_view optionally stores just the view matrix + * @param out_proj optionally stores just the projection matrix + * @returns the camera's view projection matrix pre-multiplied + */ +PUB Mat4 Camera_ViewProj(Camera* c, f32 lens_height, f32 lens_width, Mat4* out_view, + Mat4* out_proj); + +/** @brief Get 2D camera transform matrix */ +PUB Mat4 Camera_View2D(Camera* c); // TODO: 2D cameras + +struct Input_State; + +PUB void FlyCamera_Update(Camera* camera); + +// TODO: (HIGH) Basic reusable camera controls +/* +Right click + move = pan +Left click = orbit camera +WASD = forward/backward/left/right +*/ diff --git a/src/archive/src/core/core.c b/src/archive/src/core/core.c new file mode 100644 index 0000000..64f59f3 --- /dev/null +++ b/src/archive/src/core/core.c @@ -0,0 +1,81 @@ +#include "core.h" + +#include + +#include "glfw3.h" +#include "input.h" +#include "keys.h" +#include "log.h" +#include "mem.h" +#include "render.h" +#include "render_types.h" + +// These are only the initial window dimensions +#define SCR_WIDTH 1000 +#define SCR_HEIGHT 1000 + +Core g_core; /** @brief global `Core` that other files can use */ + +/** @brief Gets the global `Core` singleton */ +inline Core* GetCore() { return &g_core; } + +void Core_Bringup(const char* window_name, struct GLFWwindow* optional_window) { + INFO("Initiate Core bringup"); + memset(&g_core, 0, sizeof(Core)); + + RendererConfig conf = { .window_name = window_name, + .scr_width = SCR_WIDTH, + .scr_height = SCR_HEIGHT, + .clear_colour = (Vec3){ .08, .08, .1 } }; + + g_core.renderer = malloc(Renderer_GetMemReqs()); + + // Initialise all subsystems + + // renderer config, renderer ptr, ptr to store a window, and optional preexisting glfw window + if (!Renderer_Init(conf, g_core.renderer, &g_core.window, optional_window)) { + // FATAL("Failed to start renderer"); + ERROR_EXIT("Failed to start renderer\n"); + } + if (optional_window != NULL) { + g_core.window = optional_window; + } + + if (!Input_Init(&g_core.input, g_core.window)) { + // the input system needs the glfw window which is created by the renderer + // hence the order here is important + ERROR_EXIT("Failed to start input system\n"); + } + + size_t model_data_max = 1024 * 1024 * 1024; + arena model_arena = arena_create(malloc(model_data_max), model_data_max); + + Model_pool model_pool = Model_pool_create(&model_arena, 256, sizeof(Model)); + g_core.models = model_pool; + INFO("Created model pool allocator"); +} + +void Core_Shutdown() { + Input_Shutdown(&g_core.input); + Renderer_Shutdown(g_core.renderer); + free(g_core.renderer); +} + +bool ShouldExit() { + return key_just_released(KEYCODE_ESCAPE) || glfwWindowShouldClose(g_core.window); +} + +void Frame_Begin() { + Input_Update(&g_core.input); + Render_FrameBegin(g_core.renderer); +} +void Frame_Draw() {} +void Frame_End() { Render_FrameEnd(g_core.renderer); } + +Core* get_global_core() { return &g_core; } + +GLFWwindow* Core_GetGlfwWindowPtr(Core* core) { return g_core.window; } + +struct Renderer* Core_GetRenderer(Core* core) { return core->renderer; } + +Model* Model_Get(ModelHandle h) { return Model_pool_get(&g_core.models, h); } diff --git a/src/archive/src/core/core.h b/src/archive/src/core/core.h new file mode 100644 index 0000000..14ba65d --- /dev/null +++ b/src/archive/src/core/core.h @@ -0,0 +1,43 @@ +#pragma once + +#include "input.h" +#include "mem.h" +#include "render_types.h" +#include "screenspace.h" +#include "terrain.h" +#include "text.h" + +TYPED_POOL(Model, Model) +#define MODEL_GET(h) (Model_pool_get(&g_core.models, h)) +Model* Model_Get(ModelHandle h); + +typedef struct GLFWwindow GLFWwindow; + +typedef struct Core { + const char* app_name; + GLFWwindow* window; + Renderer* renderer; + Input_State input; + // Model_pool models; +} Core; +extern Core g_core; + +struct Renderer; + +Core* get_global_core(); + +/** + @brief Throws error if the core cannot be instantiated + @param [in] optional_window - Leave NULL if you want Celeritas to instantiate its own window with + GLFW, if you want to provide the glfw window then pass it in here. +*/ +void Core_Bringup(const char* window_name, GLFWwindow* optional_window); +void Core_Shutdown(); +bool ShouldExit(); + +GLFWwindow* Core_GetGlfwWindowPtr(Core* core); +struct Renderer* Core_GetRenderer(Core* core); + +void Frame_Begin(); +void Frame_Draw(); +void Frame_End(); diff --git a/src/archive/src/core/input.c b/src/archive/src/core/input.c new file mode 100644 index 0000000..e69de29 diff --git a/src/archive/src/core/vfs.h b/src/archive/src/core/vfs.h new file mode 100644 index 0000000..41033f5 --- /dev/null +++ b/src/archive/src/core/vfs.h @@ -0,0 +1,38 @@ +#pragma once +#include "defines.h" + +#define MAX_VIRTUAL_FILENAME_LEN 256 + +typedef struct VFS_Pack VFS_Pack; + +const char VFS_OpenErr_DoesNotExist[] = "PATH DOES NOT EXIST"; + +typedef struct VFS_File { + size_t n_bytes; + void* data; +} VFS_File; + +// virtual file open result +typedef struct VFS_FileRes { + bool success; + const char* error_reason; + VFS_File file; +} VFS_FileRes; + +VFS_Pack* VFS_Open(const char* filepath); + +bool VFS_Close(VFS_Pack*); + +VFS_FileRes VFS_VirtualRead(VFS_Pack* vfs, const char* unique_path); + +typedef struct VFS_PackBuilder { + const char* pack_filename; +} VFS_PackBuilder; + +typedef struct VFS_FileEntry { + char filename[MAX_VIRTUAL_FILENAME_LEN]; + size_t offset; + size_t size; +} VFS_FileEntry; + +VFS_PackBuilder VFS_Pack_Create(); \ No newline at end of file diff --git a/src/archive/src/empty.c b/src/archive/src/empty.c new file mode 100644 index 0000000..b40cc85 --- /dev/null +++ b/src/archive/src/empty.c @@ -0,0 +1,3 @@ +// For some reason on Mac we need an empty file so that 'ar' has something +// to run. +int add(int a, int b) { return a + b; } \ No newline at end of file diff --git a/src/archive/src/log.c b/src/archive/src/log.c new file mode 100644 index 0000000..8bb7a65 --- /dev/null +++ b/src/archive/src/log.c @@ -0,0 +1,56 @@ +#include "log.h" + +#include +#include +#include + +#include "defines.h" + +// Regular text +#define BLK "\e[0;30m" +#define RED "\e[0;31m" +#define GRN "\e[0;32m" +#define YEL "\e[0;33m" +#define BLU "\e[0;34m" +#define MAG "\e[0;35m" +#define CYN "\e[0;36m" +#define WHT "\e[0;37m" +#define CRESET "\e[0m" + +static const char* level_strings[6] = { "[FATAL]: ", "[ERROR]: ", "[WARN]: ", + "[INFO]: ", "[DEBUG]: ", "[TRACE]: " }; +static const char* level_colours[6] = { RED, RED, YEL, BLU, CYN, MAG }; + +bool logger_init() { + // TODO: create log file + return true; +} + +void logger_shutdown() { + // does nothing right now +} + +void log_output(log_level level, const char* message, ...) { + char out_message[32000]; + memset(out_message, 0, sizeof(out_message)); + + // format original message + __builtin_va_list arg_ptr; + va_start(arg_ptr, message); + vsnprintf(out_message, 32000, message, arg_ptr); + va_end(arg_ptr); + + char out_message2[32006]; + // prepend log level string + sprintf(out_message2, "%s%s%s%s\n", level_colours[level], level_strings[level], out_message, + CRESET); + + // print message to console + printf("%s", out_message2); +} + +void report_assertion_failure(const char* expression, const char* message, const char* file, + int line) { + log_output(LOG_LEVEL_FATAL, "Assertion failure: %s, message: '%s', in file: %s, on line %d\n", + expression, message, file, line); +} diff --git a/src/archive/src/log.h b/src/archive/src/log.h new file mode 100644 index 0000000..537cb6e --- /dev/null +++ b/src/archive/src/log.h @@ -0,0 +1,84 @@ +#pragma once + +#include +#include +#include + +#define ERROR_EXIT(...) \ + { \ + fprintf(stderr, __VA_ARGS__); \ + exit(1); \ + } + +#define TODO(msg) \ + do { \ + ERROR_EXIT("TODO: %s", msg); \ + } while (0) + +#define LOG_WARN_ENABLED 1 +#define LOG_INFO_ENABLED 1 + +#ifdef CRELEASE +#define LOG_DEBUG_ENABLED 0 +#define LOG_TRACE_ENABLED 0 +#else +#define LOG_DEBUG_ENABLED 1 +#define LOG_TRACE_ENABLED 1 +#endif + +typedef enum log_level { + LOG_LEVEL_FATAL = 0, + LOG_LEVEL_ERROR = 1, + LOG_LEVEL_WARN = 2, + LOG_LEVEL_INFO = 3, + LOG_LEVEL_DEBUG = 4, + LOG_LEVEL_TRACE = 5, +} log_level; + +bool logger_init(); +void logger_shutdown(); + +// TODO: macro that outputs logger macros for a specific subsystem or string prefix e.g. "MEMORY" -> +// logs now have more context potentially have line numbers too? + +void log_output(log_level level, const char* message, ...); + +#define FATAL(message, ...) log_output(LOG_LEVEL_FATAL, message, ##__VA_ARGS__) +#define ERROR(message, ...) log_output(LOG_LEVEL_ERROR, message, ##__VA_ARGS__) +#define WARN(message, ...) log_output(LOG_LEVEL_WARN, message, ##__VA_ARGS__) +#define INFO(message, ...) log_output(LOG_LEVEL_INFO, message, ##__VA_ARGS__) + +#if LOG_DEBUG_ENABLED == 1 +#define DEBUG(message, ...) log_output(LOG_LEVEL_DEBUG, message, ##__VA_ARGS__) +#else +#define DEBUG(message, ...) +#endif + +#if LOG_TRACE_ENABLED == 1 +#define TRACE(message, ...) log_output(LOG_LEVEL_TRACE, message, ##__VA_ARGS__) +#else +#define TRACE(message, ...) +#endif + +// TODO: Move this to an asserts file + +void report_assertion_failure(const char* expression, const char* message, const char* file, + int line); + +#define CASSERT(expr) \ + { \ + if (expr) { \ + } else { \ + report_assertion_failure(#expr, "", __FILE__, __LINE__); \ + __builtin_trap(); \ + } \ + } + +#define CASSERT_MSG(expr, msg) \ + { \ + if (expr) { \ + } else { \ + report_assertion_failure(#expr, msg, __FILE__, __LINE__); \ + __builtin_trap(); \ + } \ + } \ No newline at end of file diff --git a/src/archive/src/logos/README.md b/src/archive/src/logos/README.md new file mode 100644 index 0000000..25b7bef --- /dev/null +++ b/src/archive/src/logos/README.md @@ -0,0 +1,6 @@ +# Logos + +Logos is the namespace for threadpool & job system code. This is not a 'system' as it is underlying core unit of the engine. + +Threadpool currently gets initialised at core bringup with a set number of threads and results are processed once per frame +on the main thread. This is subject to change but multithreading is not the highest priority right now. \ No newline at end of file diff --git a/src/archive/src/logos/tasks.h b/src/archive/src/logos/tasks.h new file mode 100644 index 0000000..2e3dc53 --- /dev/null +++ b/src/archive/src/logos/tasks.h @@ -0,0 +1,74 @@ +/** + * Common jobs that get run + */ +#pragma once +#include "defines.h" +#include "logos/threadpool.h" +#include "render_types.h" +#include "str.h" + +typedef enum TaskLifetime { + /** ephemeral tasks must be finished by the end of the frame and thus we use a leak and clear + allocation strategy */ + TASK_EPHEMERAL, + /** multi-frame tasks have a more complex lifetime and must be cleaned up by the caller or in a + separate cleanup callback */ + TASK_MULTIFRAME, + TASK_COUNT +} TaskLifetime; + +typedef enum TaskKind { + TASK_RENDER, + TASK_PHYSICS, + TASK_GAMEPLAY, + TASK_ASSET, + TASK_USERLAND, + TASKKIND_COUNT +} TaskKind; + +typedef struct Task { + char* debug_name; + void* params; + bool is_done; +} Task; + +// Macro : give Params and Result structs and it creates a function that knows +// correct sizes + +typedef struct Task_ModelLoad_Params { + Str8 filepath; // filepath to the model on disk +} Task_ModelLoad_Params; +typedef struct Task_ModelLoad_Result { + Model model; +} Task_ModelLoad_Result; + +// Internally it will allocate data for each + +static bool Task_ModelLoad_Typed(Task_ModelLoad_Params* params, Task_ModelLoad_Result* result, + tpool_task_start run_task, tpool_task_on_complete on_success, + tpool_task_on_complete on_failure) { + threadpool_add_task(pool, , tpool_task_on_complete on_success, tpool_task_on_complete on_fail, + bool buffer_result_for_main_thread, void* param_data, u32 param_data_size, + u32 result_data_size) +} + +// do task +// success +void model_load_success(task_globals* globals, void* result) { + Task_ModelLoad_Result* load_res = result; + + // push into render -> renderables ? +} +// fail + +// we can define our custom task here that wraps the more verbose function pointers +static Task Task_ModelLoad(Task_ModelLoad_Params* params, Task_ModelLoad_Result* result) { + Task task; + task.debug_name = "Load Model"; + task.params = params; + + Task_ModelLoad_Typed(params, result, tpool_task_start run_task, tpool_task_on_complete on_success, + tpool_task_on_complete on_failure) + + return task; +} diff --git a/src/archive/src/logos/threadpool.c b/src/archive/src/logos/threadpool.c new file mode 100644 index 0000000..0e82d98 --- /dev/null +++ b/src/archive/src/logos/threadpool.c @@ -0,0 +1,141 @@ +#include "threadpool.h" + +#include + +#include "defines.h" +#include "log.h" +#include "ring_queue.h" + +static void* worker_factory(void* arg) { + threadpool_worker* worker = arg; + // INFO("Starting job thread %d", worker->id); + + // Run forever, waiting for jobs. + while (true) { + pthread_mutex_lock(&worker->pool->mutex); + pthread_cond_wait(&worker->pool->has_tasks, &worker->pool->mutex); // wait for work to be ready + + task t; + if (ring_queue_dequeue(worker->pool->task_queue, &t)) { + DEBUG("Job thread %d picked up task %d", worker->id, t.task_id); + } else { + WARN("Job thread %d didnt pick up a task as queue was empty", worker->id); + pthread_mutex_unlock(&worker->pool->mutex); + break; + } + + pthread_mutex_unlock(&worker->pool->mutex); + + // Do the work + bool result = t.do_task(t.params, t.result_data); + + // INFO("Task result was %s", result ? "success" : "failure"); + if (result) { + pthread_mutex_lock(&worker->pool->mutex); + if (t.buffer_result_for_main_thread) { + deferred_task_result dtr = { .task_id = t.task_id, + .callback = t.on_success, + .result_data = t.result_data, + .result_data_size = t.result_data_size }; + deferred_task_result_darray_push(worker->pool->results, dtr); + } else { + // call on complete from here. + } + } else { + // TODO + } + pthread_mutex_unlock(&worker->pool->mutex); + } + + return NULL; +} + +bool threadpool_create(threadpool* pool, u8 thread_count, u32 queue_size) { + INFO("Threadpool init"); + pool->next_task_id = 0; + pool->context = NULL; + + u8 num_worker_threads = thread_count; + if (thread_count > MAX_NUM_THREADS) { + ERROR_EXIT("Threadpool has a hard limit of %d threads, you tried to start one with %d", + MAX_NUM_THREADS, thread_count) + num_worker_threads = MAX_NUM_THREADS; + } + + DEBUG("creating task queue with max length %d", queue_size); + pool->task_queue = ring_queue_new(sizeof(task), queue_size, NULL); + + DEBUG("creating mutex and condition"); + pthread_mutex_init(&pool->mutex, NULL); + pthread_cond_init(&pool->has_tasks, NULL); + + pool->results = deferred_task_result_darray_new(256); + + DEBUG("Spawning %d threads for the threadpool", thread_count); + for (u8 i = 0; i < num_worker_threads; i++) { + pool->workers[i].id = i; + pool->workers[i].pool = pool; + if (pthread_create(&pool->workers[i].thread, NULL, worker_factory, &pool->workers[i]) != 0) { + FATAL("OS error creating job thread"); + return false; + }; + } + + return true; +} + +bool threadpool_add_task(threadpool* pool, tpool_task_start do_task, + tpool_task_on_complete on_success, tpool_task_on_complete on_fail, + bool buffer_result_for_main_thread, void* param_data, u32 param_data_size, + u32 result_data_size) { + void* result_data = malloc(result_data_size); + + task* work_task = malloc(sizeof(task)); + work_task->task_id = 0; + work_task->do_task = do_task; + work_task->on_success = on_success; + work_task->on_failure = on_fail; + work_task->buffer_result_for_main_thread = buffer_result_for_main_thread; + work_task->param_size = param_data_size; + work_task->params = param_data; + work_task->result_data_size = result_data_size; + work_task->result_data = result_data; + + // START critical section + if (pthread_mutex_lock(&pool->mutex) != 0) { + ERROR("Unable to get threadpool lock."); + return false; + } + + work_task->task_id = pool->next_task_id; + pool->next_task_id++; + + ring_queue_enqueue(pool->task_queue, work_task); + DEBUG("Enqueued job"); + pthread_cond_broadcast(&pool->has_tasks); + + if (pthread_mutex_unlock(&pool->mutex) != 0) { + ERROR("couldnt unlock threadpool after adding task."); + return false; // ? + } + // END critical section + + return true; +} + +void threadpool_process_results(threadpool* pool, int _num_to_process) { + pthread_mutex_lock(&pool->mutex); + size_t num_results = deferred_task_result_darray_len(pool->results); + if (num_results > 0) { + u32 _size = ((deferred_task_result*)pool->results->data)[num_results].result_data_size; + deferred_task_result res; + deferred_task_result_darray_pop(pool->results, &res); + pthread_mutex_unlock(&pool->mutex); + task_globals globals = { .pool = pool, .ctx = pool->context }; + res.callback(&globals, res.result_data); + } else { + pthread_mutex_unlock(&pool->mutex); + } +} + +void threadpool_set_ctx(threadpool* pool, void* ctx) { pool->context = ctx; } \ No newline at end of file diff --git a/src/archive/src/logos/threadpool.h b/src/archive/src/logos/threadpool.h new file mode 100644 index 0000000..6390a38 --- /dev/null +++ b/src/archive/src/logos/threadpool.h @@ -0,0 +1,96 @@ +/** + A Threadpool has a number of "workers", each which process "tasks" +*/ +#pragma once + +#include + +#include "darray.h" +#include "defines.h" +#include "ring_queue.h" + +#define MAX_NUM_THREADS 16 + +struct threadpool; +typedef struct threadpool threadpool; + +typedef struct task_globals { + threadpool* pool; + void* ctx; +} task_globals; + +/* function pointer */ +typedef bool (*tpool_task_start)(void*, void*); + +/* function pointer */ +typedef void (*tpool_task_on_complete)(task_globals*, void*); + +typedef struct threadpool_worker { + u16 id; + pthread_t thread; + threadpool* pool; // pointer back to the pool so we can get the mutex and cond +} threadpool_worker; + +typedef enum tpool_task_status { + TASK_STATUS_READY, +} task_status; + +typedef struct tpool_task { + u64 task_id; + tpool_task_start do_task; + tpool_task_on_complete on_success; + tpool_task_on_complete on_failure; + bool buffer_result_for_main_thread; + /** @brief a pointer to the parameters data that will be passed into the task. */ + void* params; + u32 param_size; + void* result_data; + u32 result_data_size; +} task; + +typedef struct deferred_task_result { + u64 task_id; + tpool_task_on_complete callback; + u32 result_data_size; + // this gets passed to the void* argument of `tpool_task_on_complete` + void* result_data; +} deferred_task_result; + +#ifndef TYPED_TASK_RESULT_ARRAY +KITC_DECL_TYPED_ARRAY(deferred_task_result) // creates "deferred_task_result_darray" +#define TYPED_TASK_RESULT_ARRAY +#endif + +struct threadpool { + ring_queue* task_queue; + pthread_mutex_t mutex; + pthread_cond_t has_tasks; + threadpool_worker workers[MAX_NUM_THREADS]; + deferred_task_result_darray* results; + u64 next_task_id; + + void* context; +}; + +/** + * @param pool where to store the created threadpool + * @param thread_count how many threads to spawn + * @param queue_size max size of task queue + */ +bool threadpool_create(threadpool* pool, u8 thread_count, u32 queue_size); +void threadpool_destroy(threadpool* pool); + +/** @brief set a context variable for the threadpool that task data has access to */ +void threadpool_set_ctx(threadpool* pool, void* ctx); + +/** + * @brief Add a task to the threadpool + */ +bool threadpool_add_task(threadpool* pool, tpool_task_start do_task, + tpool_task_on_complete on_success, tpool_task_on_complete on_fail, + bool buffer_result_for_main_thread, void* param_data, u32 param_data_size, + u32 result_data_size); + +void threadpool_process_results(threadpool* pool, int num_to_process); + +u32 Tpool_GetNumWorkers(); // how many threads are we using \ No newline at end of file diff --git a/src/archive/src/maths/geometry.h b/src/archive/src/maths/geometry.h new file mode 100644 index 0000000..532651c --- /dev/null +++ b/src/archive/src/maths/geometry.h @@ -0,0 +1,50 @@ +/** + * @file geometry.h + * @author your name (you@domain.com) + * @brief Shapes and intersections between them + * @version 0.1 + * @date 2024-02-24 + * + * @copyright Copyright (c) 2024 + */ +#pragma once + +#include "maths.h" + +// typedef struct line_3d { +// vec3 start, end; +// } line_3d; + +// typedef struct plane { +// vec3 normal; +// } plane; + +typedef struct Cuboid { + Vec3 half_extents; +} Cuboid; + +typedef struct Sphere { + f32 radius; +} Sphere; + +// typedef struct cylinder { +// f32 radius; +// f32 half_height; +// } cylinder; + +// typedef struct cone { +// f32 radius; +// f32 half_height; +// } cone; + +// TODO: +// capsule +// torus +// ray +// frustum +// conical frustum +// wedge + +// 2d... +// line +// circle diff --git a/src/archive/src/maths/maths.c b/src/archive/src/maths/maths.c new file mode 100644 index 0000000..19052fe --- /dev/null +++ b/src/archive/src/maths/maths.c @@ -0,0 +1,35 @@ +#include "maths.h" + +#define c_static_inline + +c_static_inline Vec3 vec3_create(f32 x, f32 y, f32 z) { return (Vec3){ x, y, z }; } +c_static_inline Vec3 vec3_add(Vec3 a, Vec3 b) { return (Vec3){ a.x + b.x, a.y + b.y, a.z + b.z }; } +c_static_inline Vec3 vec3_sub(Vec3 a, Vec3 b) { return (Vec3){ a.x - b.x, a.y - b.y, a.z - b.z }; } +c_static_inline Vec3 vec3_mult(Vec3 a, f32 s) { return (Vec3){ a.x * s, a.y * s, a.z * s }; } +c_static_inline Vec3 vec3_div(Vec3 a, f32 s) { return (Vec3){ a.x / s, a.y / s, a.z / s }; } + +c_static_inline f32 vec3_len_squared(Vec3 a) { return (a.x * a.x) + (a.y * a.y) + (a.z * a.z); } +c_static_inline f32 vec3_len(Vec3 a) { return sqrtf(vec3_len_squared(a)); } +c_static_inline Vec3 vec3_negate(Vec3 a) { return (Vec3){ -a.x, -a.y, -a.z }; } +PUB c_static_inline Vec3 vec3_normalise(Vec3 a) { + f32 length = vec3_len(a); + return vec3_div(a, length); +} + +c_static_inline f32 vec3_dot(Vec3 a, Vec3 b) { return a.x * b.x + a.y * b.y + a.z * b.z; } +c_static_inline Vec3 vec3_cross(Vec3 a, Vec3 b) { + return ( + Vec3){ .x = a.y * b.z - a.z * b.y, .y = a.z * b.x - a.x * b.z, .z = a.x * b.y - a.y * b.x }; +} + +Mat4 mat4_ident() { + return (Mat4){ .data = { 1.0, 0., 0., 0., 0., 1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 1.0 } }; +} + +Mat4 transform_to_mat(Transform* tf) { + Mat4 scale = mat4_scale(tf->scale); + Mat4 rotation = mat4_rotation(tf->rotation); + Mat4 translation = mat4_translation(tf->position); + // return mat4_mult(translation, mat4_mult(rotation, scale)); + return mat4_mult(mat4_mult(scale, rotation), translation); +} \ No newline at end of file diff --git a/src/archive/src/maths/maths.h b/src/archive/src/maths/maths.h new file mode 100644 index 0000000..e77b81a --- /dev/null +++ b/src/archive/src/maths/maths.h @@ -0,0 +1,321 @@ +/** + * @file maths.h + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-02-24 + * @copyright Copyright (c) 2024 + */ +#pragma once + +#include +#include +#include "defines.h" +#include "maths_types.h" + +// #undef c_static_inline +// #define c_static_inline static + +// --- Helpers +#define deg_to_rad(x) (x * 3.14 / 180.0) +#define MIN(a, b) (a < b ? a : b) +#define MAX(a, b) (a > b ? a : b) + +// --- Vector Implementations + +// Dimension 3 +PUB c_static_inline Vec3 vec3_create(f32 x, f32 y, f32 z); +#define vec3(x, y, z) ((Vec3){ x, y, z }) +PUB c_static_inline Vec3 vec3_add(Vec3 a, Vec3 b); +PUB c_static_inline Vec3 vec3_sub(Vec3 a, Vec3 b); +PUB c_static_inline Vec3 vec3_mult(Vec3 a, f32 s); +PUB c_static_inline Vec3 vec3_div(Vec3 a, f32 s); + +PUB c_static_inline f32 vec3_len_squared(Vec3 a); +PUB c_static_inline f32 vec3_len(Vec3 a); +PUB c_static_inline Vec3 vec3_negate(Vec3 a); +PUB c_static_inline Vec3 vec3_normalise(Vec3 a); + +PUB c_static_inline f32 vec3_dot(Vec3 a, Vec3 b); +PUB c_static_inline Vec3 vec3_cross(Vec3 a, Vec3 b); + +static const Vec3 VEC3_X = vec3(1.0, 0.0, 0.0); +static const Vec3 VEC3_NEG_X = vec3(-1.0, 0.0, 0.0); +static const Vec3 VEC3_Y = vec3(0.0, 1.0, 0.0); +static const Vec3 VEC3_NEG_Y = vec3(0.0, -1.0, 0.0); +static const Vec3 VEC3_Z = vec3(0.0, 0.0, 1.0); +static const Vec3 VEC3_NEG_Z = vec3(0.0, 0.0, -1.0); +static const Vec3 VEC3_ZERO = vec3(0.0, 0.0, 0.0); +static const Vec3 VEC3_ONES = vec3(1.0, 1.0, 1.0); + +static void print_vec3(Vec3 v) { + printf("{ x: %f, y: %f, z: %f )\n", (f64)v.x, (f64)v.y, (f64)v.z); +} + +// TODO: Dimension 2 +static Vec2 vec2_create(f32 x, f32 y) { return (Vec2){ x, y }; } +#define vec2(x, y) ((Vec2){ x, y }) +static Vec2 vec2_div(Vec2 a, f32 s) { return (Vec2){ a.x / s, a.y / s }; } + +// TODO: Dimension 4 +static Vec4 vec4_create(f32 x, f32 y, f32 z, f32 w) { return (Vec4){ x, y, z, w }; } +#define vec4(x, y, z, w) (vec4_create(x, y, z, w)) +#define VEC4_ZERO ((Vec4){ .x = 0.0, .y = 0.0, .z = 0.0, .w = 0.0 }) + +// --- Quaternion Implementations + +static f32 quat_dot(Quat a, Quat b) { return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; } + +static Quat quat_normalise(Quat a) { + f32 length = sqrtf(quat_dot(a, a)); // same as len squared + + return (Quat){ a.x / length, a.y / length, a.z / length, a.w / length }; +} + +static Quat quat_ident() { return (Quat){ .x = 0.0, .y = 0.0, .z = 0.0, .w = 1.0 }; } + +static Quat quat_from_axis_angle(Vec3 axis, f32 angle, bool normalize) { + const f32 half_angle = 0.5f * angle; + f32 s = sinf(half_angle); + f32 c = cosf(half_angle); + + Quat q = (Quat){ s * axis.x, s * axis.y, s * axis.z, c }; + if (normalize) { + return quat_normalise(q); + } + return q; +} + +// TODO: grok this. +static Quat quat_slerp(Quat a, Quat b, f32 percentage) { + Quat out_quaternion; + + Quat q0 = quat_normalise(a); + Quat q1 = quat_normalise(b); + + // Compute the cosine of the angle between the two vectors. + f32 dot = quat_dot(q0, q1); + + // If the dot product is negative, slerp won't take + // the shorter path. Note that v1 and -v1 are equivalent when + // the negation is applied to all four components. Fix by + // reversing one quaternion. + if (dot < 0.0f) { + q1.x = -q1.x; + q1.y = -q1.y; + q1.z = -q1.z; + q1.w = -q1.w; + dot = -dot; + } + + const f32 DOT_THRESHOLD = 0.9995f; + if (dot > DOT_THRESHOLD) { + // If the inputs are too close for comfort, linearly interpolate + // and normalize the result. + out_quaternion = + (Quat){ q0.x + ((q1.x - q0.x) * percentage), q0.y + ((q1.y - q0.y) * percentage), + q0.z + ((q1.z - q0.z) * percentage), q0.w + ((q1.w - q0.w) * percentage) }; + + return quat_normalise(out_quaternion); + } + + // TODO: Are there math functions that take floats instead of doubles? + + // Since dot is in range [0, DOT_THRESHOLD], acos is safe + f64 theta_0 = cos((f64)dot); // theta_0 = angle between input vectors + f64 theta = theta_0 * (f64)percentage; // theta = angle between v0 and result + f64 sin_theta = sin((f64)theta); // compute this value only once + f64 sin_theta_0 = sin((f64)theta_0); // compute this value only once + + f32 s0 = + cos(theta) - (f64)dot * sin_theta / sin_theta_0; // == sin(theta_0 - theta) / sin(theta_0) + f32 s1 = sin_theta / sin_theta_0; + + return (Quat){ (q0.x * s0) + (q1.x * s1), (q0.y * s0) + (q1.y * s1), (q0.z * s0) + (q1.z * s1), + (q0.w * s0) + (q1.w * s1) }; +} + +// --- Matrix Implementations + +Mat4 mat4_ident(); + +static Mat4 mat4_translation(Vec3 position) { + Mat4 out_matrix = mat4_ident(); + out_matrix.data[12] = position.x; + out_matrix.data[13] = position.y; + out_matrix.data[14] = position.z; + return out_matrix; +} + +static Mat4 mat4_scale(Vec3 scale) { + Mat4 out_matrix = mat4_ident(); + out_matrix.data[0] = scale.x; + out_matrix.data[5] = scale.y; + out_matrix.data[10] = scale.z; + return out_matrix; +} + +// TODO: double check this +static Mat4 mat4_rotation(Quat rotation) { + Mat4 out_matrix = mat4_ident(); + Quat n = quat_normalise(rotation); + + out_matrix.data[0] = 1.0f - 2.0f * n.y * n.y - 2.0f * n.z * n.z; + out_matrix.data[1] = 2.0f * n.x * n.y - 2.0f * n.z * n.w; + out_matrix.data[2] = 2.0f * n.x * n.z + 2.0f * n.y * n.w; + + out_matrix.data[4] = 2.0f * n.x * n.y + 2.0f * n.z * n.w; + out_matrix.data[5] = 1.0f - 2.0f * n.x * n.x - 2.0f * n.z * n.z; + out_matrix.data[6] = 2.0f * n.y * n.z - 2.0f * n.x * n.w; + + out_matrix.data[8] = 2.0f * n.x * n.z - 2.0f * n.y * n.w; + out_matrix.data[9] = 2.0f * n.y * n.z + 2.0f * n.x * n.w; + out_matrix.data[10] = 1.0f - 2.0f * n.x * n.x - 2.0f * n.y * n.y; + + return out_matrix; +} + +static Mat4 mat4_mult(Mat4 lhs, Mat4 rhs) { + Mat4 out_matrix = mat4_ident(); + + const f32* m1_ptr = lhs.data; + const f32* m2_ptr = rhs.data; + f32* dst_ptr = out_matrix.data; + + for (i32 i = 0; i < 4; ++i) { + for (i32 j = 0; j < 4; ++j) { + *dst_ptr = m1_ptr[0] * m2_ptr[0 + j] + m1_ptr[1] * m2_ptr[4 + j] + m1_ptr[2] * m2_ptr[8 + j] + + m1_ptr[3] * m2_ptr[12 + j]; + dst_ptr++; + } + m1_ptr += 4; + } + + return out_matrix; +} + +static Mat4 mat4_transposed(Mat4 matrix) { + Mat4 out_matrix = mat4_ident(); + out_matrix.data[0] = matrix.data[0]; + out_matrix.data[1] = matrix.data[4]; + out_matrix.data[2] = matrix.data[8]; + out_matrix.data[3] = matrix.data[12]; + out_matrix.data[4] = matrix.data[1]; + out_matrix.data[5] = matrix.data[5]; + out_matrix.data[6] = matrix.data[9]; + out_matrix.data[7] = matrix.data[13]; + out_matrix.data[8] = matrix.data[2]; + out_matrix.data[9] = matrix.data[6]; + out_matrix.data[10] = matrix.data[10]; + out_matrix.data[11] = matrix.data[14]; + out_matrix.data[12] = matrix.data[3]; + out_matrix.data[13] = matrix.data[7]; + out_matrix.data[14] = matrix.data[11]; + out_matrix.data[15] = matrix.data[15]; + return out_matrix; +} + +#if defined(CEL_REND_BACKEND_VULKAN) +/** @brief Creates a perspective projection matrix compatible with Vulkan */ +c_static_inline Mat4 mat4_perspective(f32 fov_radians, f32 aspect_ratio, f32 near_clip, + f32 far_clip) { + f32 half_tan_fov = tanf(fov_radians * 0.5f); + Mat4 out_matrix = { .data = { 0 } }; + + out_matrix.data[0] = 1.0f / (aspect_ratio * half_tan_fov); + out_matrix.data[5] = -1.0f / half_tan_fov; // Flip Y-axis for Vulkan + out_matrix.data[10] = -((far_clip + near_clip) / (far_clip - near_clip)); + out_matrix.data[11] = -1.0f; + out_matrix.data[14] = -((2.0f * far_clip * near_clip) / (far_clip - near_clip)); + + return out_matrix; +} +#else +/** @brief Creates a perspective projection matrix */ +static inline Mat4 mat4_perspective(f32 fov_radians, f32 aspect_ratio, f32 near_clip, + f32 far_clip) { + f32 half_tan_fov = tanf(fov_radians * 0.5f); + Mat4 out_matrix = { .data = { 0 } }; + out_matrix.data[0] = 1.0f / (aspect_ratio * half_tan_fov); + out_matrix.data[5] = 1.0f / half_tan_fov; + out_matrix.data[10] = -((far_clip + near_clip) / (far_clip - near_clip)); + out_matrix.data[11] = -1.0f; + out_matrix.data[14] = -((2.0f * far_clip * near_clip) / (far_clip - near_clip)); + return out_matrix; +} +#endif + +/** @brief Creates an orthographic projection matrix */ +static inline Mat4 mat4_orthographic(f32 left, f32 right, f32 bottom, f32 top, f32 near_clip, + f32 far_clip) { + // source: kohi game engine. + Mat4 out_matrix = mat4_ident(); + + f32 lr = 1.0f / (left - right); + f32 bt = 1.0f / (bottom - top); + f32 nf = 1.0f / (near_clip - far_clip); + + out_matrix.data[0] = -2.0f * lr; + out_matrix.data[5] = -2.0f * bt; + out_matrix.data[10] = 2.0f * nf; + + out_matrix.data[12] = (left + right) * lr; + out_matrix.data[13] = (top + bottom) * bt; + out_matrix.data[14] = (far_clip + near_clip) * nf; + + return out_matrix; +} + +static inline Mat4 mat4_look_at(Vec3 position, Vec3 target, Vec3 up) { + Mat4 out_matrix; + Vec3 z_axis; + z_axis.x = target.x - position.x; + z_axis.y = target.y - position.y; + z_axis.z = target.z - position.z; + + z_axis = vec3_normalise(z_axis); + Vec3 x_axis = vec3_normalise(vec3_cross(z_axis, up)); + Vec3 y_axis = vec3_cross(x_axis, z_axis); + + out_matrix.data[0] = x_axis.x; + out_matrix.data[1] = y_axis.x; + out_matrix.data[2] = -z_axis.x; + out_matrix.data[3] = 0; + out_matrix.data[4] = x_axis.y; + out_matrix.data[5] = y_axis.y; + out_matrix.data[6] = -z_axis.y; + out_matrix.data[7] = 0; + out_matrix.data[8] = x_axis.z; + out_matrix.data[9] = y_axis.z; + out_matrix.data[10] = -z_axis.z; + out_matrix.data[11] = 0; + out_matrix.data[12] = -vec3_dot(x_axis, position); + out_matrix.data[13] = -vec3_dot(y_axis, position); + out_matrix.data[14] = vec3_dot(z_axis, position); + out_matrix.data[15] = 1.0f; + + return out_matrix; +} + +// ... + +// --- Transform Implementations + +#define TRANSFORM_DEFAULT \ + ((Transform){ .position = VEC3_ZERO, \ + .rotation = (Quat){ .x = 0., .y = 0., .z = 0., .w = 1. }, \ + .scale = 1.0, \ + .is_dirty = false }) + +static Transform transform_create(Vec3 pos, Quat rot, Vec3 scale) { + return (Transform){ .position = pos, .rotation = rot, .scale = scale, .is_dirty = true }; +} + +Mat4 transform_to_mat(Transform* tf); + +// --- Sizing asserts + +_Static_assert(alignof(Vec3) == 4, "Vec3 is 4 byte aligned"); +_Static_assert(sizeof(Vec3) == 12, "Vec3 is 12 bytes so has no padding"); + +_Static_assert(alignof(Vec4) == 4, "Vec4 is 4 byte aligned"); diff --git a/src/archive/src/maths/maths_types.h b/src/archive/src/maths/maths_types.h new file mode 100644 index 0000000..c0ab8e0 --- /dev/null +++ b/src/archive/src/maths/maths_types.h @@ -0,0 +1,33 @@ +/** + * @file maths_types.h + * @author Omniscient + * @brief Maths types + * @date 2024-02-24 + * @copyright Copyright (c) 2024 + */ +#pragma once + +#include "defines.h" + +// --- Types + + + +/** @brief Three dimensional bounding box */ +typedef struct Bbox_3D { + Vec3 min; // minimum point of the box + Vec3 max; // maximum point of the box +} Bbox_3D; + +/** @brief 3D Axis-aligned bounding box */ +typedef Bbox_3D Aabb_3D; + + + +typedef struct Vec4i { + i32 x, y, z, w; +} Vec4i; + +typedef struct Vec4u { + u32 x, y, z, w; +} Vec4u; diff --git a/src/archive/src/maths/primitives.c b/src/archive/src/maths/primitives.c new file mode 100644 index 0000000..c24d1e2 --- /dev/null +++ b/src/archive/src/maths/primitives.c @@ -0,0 +1,343 @@ +#include "primitives.h" +#include "colours.h" +#include "log.h" +#include "maths.h" +#include "maths_types.h" +#include "ral_types.h" +#include "render_types.h" + +// --- Helpers + +void push_triangle(u32_darray* arr, u32 i0, u32 i1, u32 i2) { + u32_darray_push(arr, i0); + u32_darray_push(arr, i1); + u32_darray_push(arr, i2); +} + +Vec3 plane_vertex_positions[] = { + (Vec3){ -0.5, 0, -0.5 }, + (Vec3){ 0.5, 0, -0.5 }, + (Vec3){ -0.5, 0, 0.5 }, + (Vec3){ 0.5, 0, 0.5 }, +}; + +Geometry Geo_CreatePlane(f32x2 extents, u32 tiling_u, u32 tiling_v) { + CASSERT(tiling_u >= 1 && tiling_v >= 1); + Vertex_darray* vertices = Vertex_darray_new(4); + u32_darray* indices = u32_darray_new(vertices->len); + + Vec3 vert_pos[4]; + memcpy(&vert_pos, plane_vertex_positions, sizeof(plane_vertex_positions)); + for (int i = 0; i < 4; i++) { + vert_pos[i].x *= extents.x; + vert_pos[i].z *= extents.y; + } + VERT_3D(vertices, vert_pos[0], VEC3_Y, vec2(0, 0)); // back left + VERT_3D(vertices, vert_pos[1], VEC3_Y, vec2(1 * tiling_u, 0 * tiling_v)); // back right + VERT_3D(vertices, vert_pos[2], VEC3_Y, vec2(0, 1 * tiling_v)); // front left + VERT_3D(vertices, vert_pos[3], VEC3_Y, vec2(1 * tiling_u, 1 * tiling_v)); // front right + + // push_triangle(indices, 0, 1, 2); + // push_triangle(indices, 2, 1, 3); + push_triangle(indices, 2, 1, 0); + push_triangle(indices, 1, 2, 3); + + for (int i = 0; i < 4; i++) { + printf("Vertex %d: (%f, %f, %f)\n", i, vert_pos[i].x, vert_pos[i].y, vert_pos[i].z); + } + + Geometry geo = { .format = VERTEX_STATIC_3D, + .vertices = vertices, + .has_indices = true, + .index_count = indices->len, + .indices = indices }; + + return geo; +} + +Geometry Geo_CreateCuboid(f32x3 extents) { + Vertex_darray* vertices = Vertex_darray_new(36); + + // back faces + VERT_3D(vertices, BACK_TOP_RIGHT, VEC3_NEG_Z, vec2(1, 0)); + VERT_3D(vertices, BACK_BOT_LEFT, VEC3_NEG_Z, vec2(0, 1)); + VERT_3D(vertices, BACK_TOP_LEFT, VEC3_NEG_Z, vec2(0, 0)); + VERT_3D(vertices, BACK_TOP_RIGHT, VEC3_NEG_Z, vec2(1, 0)); + VERT_3D(vertices, BACK_BOT_RIGHT, VEC3_NEG_Z, vec2(1, 1)); + VERT_3D(vertices, BACK_BOT_LEFT, VEC3_NEG_Z, vec2(0, 1)); + + // front faces + VERT_3D(vertices, FRONT_BOT_LEFT, VEC3_Z, vec2(0, 1)); + VERT_3D(vertices, FRONT_TOP_RIGHT, VEC3_Z, vec2(1, 0)); + VERT_3D(vertices, FRONT_TOP_LEFT, VEC3_Z, vec2(0, 0)); + VERT_3D(vertices, FRONT_BOT_LEFT, VEC3_Z, vec2(0, 1)); + VERT_3D(vertices, FRONT_BOT_RIGHT, VEC3_Z, vec2(1, 1)); + VERT_3D(vertices, FRONT_TOP_RIGHT, VEC3_Z, vec2(1, 0)); + + // top faces + VERT_3D(vertices, BACK_TOP_LEFT, VEC3_Y, vec2(0, 0)); + VERT_3D(vertices, FRONT_TOP_LEFT, VEC3_Y, vec2(0, 1)); + VERT_3D(vertices, FRONT_TOP_RIGHT, VEC3_Y, vec2(1, 1)); + VERT_3D(vertices, BACK_TOP_LEFT, VEC3_Y, vec2(0, 0)); + VERT_3D(vertices, FRONT_TOP_RIGHT, VEC3_Y, vec2(1, 1)); + VERT_3D(vertices, BACK_TOP_RIGHT, VEC3_Y, vec2(1, 0)); + + // bottom faces + VERT_3D(vertices, BACK_BOT_LEFT, VEC3_NEG_Y, vec2(0, 1)); + VERT_3D(vertices, FRONT_BOT_RIGHT, VEC3_NEG_Y, vec2(1, 1)); + VERT_3D(vertices, FRONT_BOT_LEFT, VEC3_NEG_Y, vec2(0, 1)); + VERT_3D(vertices, BACK_BOT_LEFT, VEC3_NEG_Y, vec2(0, 1)); + VERT_3D(vertices, BACK_BOT_RIGHT, VEC3_NEG_Y, vec2(1, 1)); + VERT_3D(vertices, FRONT_BOT_RIGHT, VEC3_NEG_Y, vec2(0, 1)); + + // right faces + VERT_3D(vertices, FRONT_TOP_RIGHT, VEC3_X, vec2(0, 0)); + VERT_3D(vertices, BACK_BOT_RIGHT, VEC3_X, vec2(1, 1)); + VERT_3D(vertices, BACK_TOP_RIGHT, VEC3_X, vec2(1, 0)); + VERT_3D(vertices, BACK_BOT_RIGHT, VEC3_X, vec2(1, 1)); + VERT_3D(vertices, FRONT_TOP_RIGHT, VEC3_X, vec2(0, 0)); + VERT_3D(vertices, FRONT_BOT_RIGHT, VEC3_X, vec2(0, 1)); + + // left faces + VERT_3D(vertices, FRONT_TOP_LEFT, VEC3_NEG_X, vec2(0, 0)); + VERT_3D(vertices, BACK_TOP_LEFT, VEC3_NEG_X, vec2(0, 0)); + VERT_3D(vertices, BACK_BOT_LEFT, VEC3_NEG_X, vec2(0, 0)); + VERT_3D(vertices, BACK_BOT_LEFT, VEC3_NEG_X, vec2(0, 0)); + VERT_3D(vertices, FRONT_BOT_LEFT, VEC3_NEG_X, vec2(0, 0)); + VERT_3D(vertices, FRONT_TOP_LEFT, VEC3_NEG_X, vec2(0, 0)); + + u32_darray* indices = u32_darray_new(vertices->len); + + for (u32 i = 0; i < vertices->len; i++) { + u32_darray_push(indices, i); + vertices->data[i].static_3d.position = + vec3_sub(vertices->data[i].static_3d.position, + vec3(0.5, 0.5, 0.5)); // make center of the cube is the origin of mesh space + } + + Geometry geo = { + .format = VERTEX_STATIC_3D, + .vertices = vertices, + .has_indices = true, + .index_count = indices->len, + .indices = indices, // FIXME: make darray methods that return stack allocated struct + }; + + return geo; +} + +// --- Spheres + +Vec3 spherical_to_cartesian_coords(f32 rho, f32 theta, f32 phi) { + f32 x = rho * sin(phi) * cos(theta); + f32 y = rho * cos(phi); + f32 z = rho * sin(phi) * sin(theta); + return vec3(x, y, z); +} + +Geometry Geo_CreateUVsphere(f32 radius, u32 north_south_lines, u32 east_west_lines) { + assert(east_west_lines >= 3); // sphere will be degenerate and look gacked without at least 3 + assert(north_south_lines >= 3); + + Vertex_darray* vertices = Vertex_darray_new(2 + (east_west_lines - 1) * north_south_lines); + + // Create a UV sphere with spherical coordinates + // a point P on the unit sphere can be represented P(r, theta, phi) + // for each vertex we must convert that to a cartesian R3 coordinate + + // Top point + Vertex top = { .static_3d = { .position = vec3(0, radius, 0), + .normal = vec3_normalise(vec3(0, radius, 0)), + .tex_coords = vec2(0, 0) } }; + Vertex_darray_push(vertices, top); + + // parallels + for (u32 i = 0; i < (east_west_lines - 1); i++) { + // phi should range from 0 to pi + f32 phi = PI * (((f32)i + 1) / (f32)east_west_lines); + + // meridians + for (u32 j = 0; j < east_west_lines; j++) { + // theta should range from 0 to 2PI + f32 theta = TAU * ((f32)j / (f32)north_south_lines); + Vec3 position = spherical_to_cartesian_coords(radius, theta, phi); + // f32 d = vec3_len(position); + // print_vec3(position); + // printf("Phi %f Theta %f d %d\n", phi, theta, d); + // assert(d == radius); // all points on the sphere should be 'radius' away from the origin + Vertex v = { .static_3d = { + .position = position, + .normal = + vec3_normalise(position), // normal vector on sphere is same as position + .tex_coords = vec2(0, 0) // TODO + } }; + Vertex_darray_push(vertices, v); + } + } + + // Bottom point + Vertex bot = { .static_3d = { .position = vec3(0, -radius, 0), + .normal = vec3_normalise(vec3(0, -radius, 0)), + .tex_coords = vec2(0, 0) } }; + Vertex_darray_push(vertices, bot); + + u32_darray* indices = u32_darray_new(1); + + // top bottom rings + for (u32 i = 0; i < north_south_lines; i++) { + u32 i1 = i + 1; + u32 i2 = (i + 1) % north_south_lines + 1; + push_triangle(indices, 0, i2, i1); + /* TRACE("Push triangle (%.2f %.2f %.2f)->(%.2f %.2f %.2f)->(%.2f %.2f %.2f)\n", */ + /* vertices->data[0].static_3d.position.x, vertices->data[0].static_3d.position.y, */ + /* vertices->data[0].static_3d.position.z, vertices->data[i1].static_3d.position.x, */ + /* vertices->data[i1].static_3d.position.y, vertices->data[i1].static_3d.position.z, */ + /* vertices->data[i2].static_3d.position.x, vertices->data[i2].static_3d.position.y, */ + /* vertices->data[i2].static_3d.position.z); */ + u32 bot = vertices->len - 1; + u32 i3 = i + north_south_lines * (east_west_lines - 2) + 1; + u32 i4 = (i + 1) % north_south_lines + north_south_lines * (east_west_lines - 2) + 1; + push_triangle(indices, bot, i3, i4); + } + + // quads + for (u32 i = 0; i < east_west_lines - 2; i++) { + u32 ring_start = i * north_south_lines + 1; + u32 next_ring_start = (i + 1) * north_south_lines + 1; + /* printf("ring start %d next ring start %d\n", ring_start, next_ring_start); */ + /* print_vec3(vertices->data[ring_start].static_3d.position); */ + /* print_vec3(vertices->data[next_ring_start].static_3d.position); */ + for (u32 j = 0; j < north_south_lines; j++) { + u32 i0 = ring_start + j; + u32 i1 = next_ring_start + j; + u32 i2 = ring_start + (j + 1) % north_south_lines; + u32 i3 = next_ring_start + (j + 1) % north_south_lines; + push_triangle(indices, i0, i2, i1); + /* TRACE("Push triangle (%.2f %.2f %.2f)->(%.2f %.2f %.2f)->(%.2f %.2f %.2f)\n", */ + /* vertices->data[i0].static_3d.position.x, vertices->data[i0].static_3d.position.y, */ + /* vertices->data[i0].static_3d.position.z, vertices->data[i1].static_3d.position.x, */ + /* vertices->data[i1].static_3d.position.y, vertices->data[i1].static_3d.position.z, */ + /* vertices->data[i2].static_3d.position.x, vertices->data[i2].static_3d.position.y, */ + /* vertices->data[i2].static_3d.position.z); */ + push_triangle(indices, i1, i2, i3); + } + } + + Geometry geo = { + .format = VERTEX_STATIC_3D, + .vertices = vertices, + .has_indices = true, + .index_count = indices->len, + .indices = indices, + }; + + return geo; +} + +Geometry Geo_CreateCone(f32 radius, f32 height, u32 resolution) { + Vertex_darray* vertices = Vertex_darray_new((resolution + 1) * 2); + u32_darray* indices = u32_darray_new(resolution * 2 * 3); + + // TODO: decide how UVs are unwrapped + + // tip + VERT_3D(vertices, vec3(0.0, height, 0.0), VEC3_Y, vec2(0, 0)); + + // sides + f32 step = TAU / resolution; + + for (u32 i = 0; i < resolution; i++) { + f32 x = cos(step * i) * radius; + f32 z = sin(step * i) * radius; + Vec3 pos = vec3(x, 0.0, z); + Vec3 tip_to_vertex = vec3_sub(pos, vertices->data[0].static_3d.position); + Vec3 center_to_vertex = pos; + Vec3 tangent = vec3_cross(VEC3_Y, center_to_vertex); + Vec3 normal_dir = vec3_cross(tangent, tip_to_vertex); + Vec3 normal = vec3_normalise(normal_dir); + VERT_3D(vertices, pos, normal, vec2(0, 0)); + } + for (u32 i = 1; i < resolution; i++) { + push_triangle(indices, 0, i + 1, i); + } + push_triangle(indices, 0, 1, resolution); + + // base center + u32 center_idx = vertices->len; + VERT_3D(vertices, VEC3_ZERO, VEC3_NEG_Y, vec2(0, 0)); + + // base circle + for (u32 i = 0; i < resolution; i++) { + f32 x = cos(step * i) * radius; + f32 z = sin(step * i) * radius; + VERT_3D(vertices, vec3(x, 0.0, z), VEC3_NEG_Z, vec2(0, 0)); + } + for (u32 i = 1; i < resolution; i++) { + push_triangle(indices, center_idx, center_idx + i, center_idx + i + 1); + } + push_triangle(indices, center_idx, center_idx + resolution, center_idx + 1); + + Geometry geo = { + .format = VERTEX_STATIC_3D, + .vertices = vertices, + .has_indices = true, + .index_count = indices->len, + .indices = indices, + }; + return geo; +} + +Geometry Geo_CreateCylinder(f32 radius, f32 height, u32 resolution) { + Vertex_darray* vertices = Vertex_darray_new(1); + u32_darray* indices = u32_darray_new(1); + + f32 step = TAU / resolution; + + // bot cap + VERT_3D(vertices, VEC3_ZERO, VEC3_NEG_Y, vec2(0, 0)); + for (u32 i = 0; i < resolution; i++) { + VERT_3D(vertices, vec3(cos(step * i) * radius, 0.0, sin(step * i) * radius), VEC3_NEG_Y, + vec2(0, 0)); + } + for (u32 i = 1; i < resolution; i++) { + push_triangle(indices, 0, i, i + 1); + } + push_triangle(indices, 0, resolution, 1); + + // top cap + u32 center_idx = vertices->len; + VERT_3D(vertices, vec3(0.0, height, 0.0), VEC3_Y, vec2(0, 0)); + for (u32 i = 0; i < resolution; i++) { + VERT_3D(vertices, vec3(cos(step * i) * radius, height, sin(step * i) * radius), VEC3_Y, + vec2(0, 0)); + } + for (u32 i = 1; i < resolution; i++) { + push_triangle(indices, center_idx, center_idx + i + 1, center_idx + i); + } + push_triangle(indices, center_idx, center_idx + 1, center_idx + resolution); + + // sides + u32 sides_start = vertices->len; + for (u32 i = 0; i < resolution; i++) { + f32 x = cos(step * i) * radius; + f32 z = sin(step * i) * radius; + // top then bottom + VERT_3D(vertices, vec3(x, height, z), vec3_normalise(vec3(x, 0.0, z)), vec2(0, 0)); + VERT_3D(vertices, vec3(x, 0.0, z), vec3_normalise(vec3(x, 0.0, z)), vec2(0, 0)); + } + for (u32 i = 0; i < resolution; i++) { + u32 current = sides_start + i * 2; + u32 next = sides_start + ((i + 1) % resolution) * 2; + push_triangle(indices, current, next, current + 1); + push_triangle(indices, current + 1, next, next + 1); + } + + Geometry geo = { + .format = VERTEX_STATIC_3D, + .vertices = vertices, + .has_indices = true, + .index_count = indices->len, + .indices = indices, + }; + return geo; +} diff --git a/src/archive/src/maths/primitives.h b/src/archive/src/maths/primitives.h new file mode 100644 index 0000000..4965545 --- /dev/null +++ b/src/archive/src/maths/primitives.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include "core.h" +#include "maths_types.h" +#include "render_types.h" + +Geometry Geo_CreatePlane(f32x2 extents, u32 tiling_u, u32 tiling_v); +Geometry Geo_CreateCuboid(f32x3 extents); +Geometry Geo_CreateCylinder(f32 radius, f32 height, u32 resolution); +Geometry Geo_CreateCone(f32 radius, f32 height, u32 resolution); +Geometry Geo_CreateUVsphere(f32 radius, u32 north_south_lines, u32 east_west_lines); +Geometry Geo_CreateIcosphere(f32 radius, f32 n_subdivisions); + +static const Vec3 BACK_BOT_LEFT = (Vec3){ 0, 0, 0 }; +static const Vec3 BACK_BOT_RIGHT = (Vec3){ 1, 0, 0 }; +static const Vec3 BACK_TOP_LEFT = (Vec3){ 0, 1, 0 }; +static const Vec3 BACK_TOP_RIGHT = (Vec3){ 1, 1, 0 }; +static const Vec3 FRONT_BOT_LEFT = (Vec3){ 0, 0, 1 }; +static const Vec3 FRONT_BOT_RIGHT = (Vec3){ 1, 0, 1 }; +static const Vec3 FRONT_TOP_LEFT = (Vec3){ 0, 1, 1 }; +static const Vec3 FRONT_TOP_RIGHT = (Vec3){ 1, 1, 1 }; + +#define VERT_3D(arr, pos, norm, uv) \ + { \ + Vertex v = { .static_3d = { .position = pos, .normal = norm, .tex_coords = uv } }; \ + Vertex_darray_push(arr, v); \ + } \ No newline at end of file diff --git a/src/archive/src/physics.h b/src/archive/src/physics.h new file mode 100644 index 0000000..134f08b --- /dev/null +++ b/src/archive/src/physics.h @@ -0,0 +1,44 @@ +#pragma once + +#include "geometry.h" +#include "maths_types.h" + +// 'system' means that it gets called per frame + +typedef struct physics_settings { + f32 gravity_strength; +} physics_settings; + +// What else do I need? +// intersection methods + +typedef struct physics_world { + physics_settings settings; +} physics_world; + +physics_world physics_init(physics_settings settings); +void physics_shutdown(physics_world* phys_world); + +/** @brief perform one or more simulation steps */ +void physics_system_update(physics_world* phys_world, f64 deltatime); + +// enum ColliderType { +// CuboidCollider, +// SphereCollider, +// }; + +/** @brief Oriented Bounding Box */ +typedef struct OBB { + Vec3 center; + Bbox_3D bbox; + Quat rotation; +} OBB; + +PUB void Debug_DrawOBB(OBB obb); + +/** @brief generic collider structure */ +typedef struct Collider { + u64 id; // ? Replace with handle? + OBB shape; // NOTE: We're only supporting the one collider type for now + bool on_ground; +} Collider; diff --git a/src/archive/src/platform/file.c b/src/archive/src/platform/file.c new file mode 100644 index 0000000..91daa4f --- /dev/null +++ b/src/archive/src/platform/file.c @@ -0,0 +1,93 @@ +#include "file.h" + +#include +#include +#include +#include +#include + +#include "log.h" +#include "mem.h" +#include "str.h" + +const char* string_from_file(const char* path) { + FILE* f = fopen(path, "rb"); + if (f == NULL) { + ERROR("Error reading file: %s. errno: %d", path, errno); + return NULL; + } + if (ferror(f)) { + ERROR("Error reading file: %s. errno: %d", path, errno); + return NULL; + } + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + rewind(f); + + char* string = malloc(fsize + 1); + fread(string, fsize, 1, f); + fclose(f); + + string[fsize] = '\0'; + + return string; +} + +str8_opt str8_from_file(arena* a, Str8 path) { + char* p = cstr(a, path); + str8_opt result = { .has_value = false }; + + FILE* f = fopen(p, "rb"); + if (f == NULL) { + ERROR("Error reading file: %s. errno: %d", path, errno); + return result; + } + if (ferror(f)) { + ERROR("Error reading file: %s. errno: %d", path, errno); + return result; + } + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + rewind(f); + + u8* raw = arena_alloc(a, fsize + 1); + Str8 contents = Str8_create(raw, fsize); + contents.buf[contents.len] = '\0'; + + fread(raw, fsize, 1, f); + fclose(f); + result.contents = contents; + result.has_value = true; + + return result; +} + +FileData load_spv_file(const char* path) { + FILE* f = fopen(path, "rb"); + if (f == NULL) { + perror("Error opening file"); + return (FileData){ NULL, 0 }; + } + + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + rewind(f); + + char* data = (char*)malloc(fsize); + if (data == NULL) { + perror("Memory allocation failed"); + fclose(f); + return (FileData){ NULL, 0 }; + } + + size_t bytesRead = fread(data, 1, fsize, f); + if (bytesRead < fsize) { + perror("Failed to read the entire file"); + free(data); + fclose(f); + return (FileData){ NULL, 0 }; + } + + fclose(f); + return (FileData){ data, bytesRead }; +} diff --git a/src/archive/src/platform/file.h b/src/archive/src/platform/file.h new file mode 100644 index 0000000..5e5e1e1 --- /dev/null +++ b/src/archive/src/platform/file.h @@ -0,0 +1,26 @@ +/** + * @file file.h + * @brief File I/O utilities + * @date 2024-02-24 + * @copyright Copyright (c) 2024 + */ +#pragma once + +#include "defines.h" +#include "str.h" + +typedef struct str8_opt { + Str8 contents; + bool has_value; +} str8_opt; + +const char* string_from_file(const char* path); + +str8_opt str8_from_file(arena* a, Str8 path); + +typedef struct { + char* data; + size_t size; +} FileData; + +FileData load_spv_file(const char* path); diff --git a/src/archive/src/platform/platform.h b/src/archive/src/platform/platform.h new file mode 100644 index 0000000..c2be630 --- /dev/null +++ b/src/archive/src/platform/platform.h @@ -0,0 +1,37 @@ +#pragma once + +#include "defines.h" +#include "str.h" + +// -- Paths +typedef struct path_opt { + Str8 path; + bool has_value; +} path_opt; + +// TODO: convert to using str8 +// TODO: use uppercase code style +path_opt path_parent(arena* a, const char* path); + +// --- Threads +typedef struct CelThread CelThread; + +CelThread Thread_Create(); +void Thread_Destroy(CelThread* thread); + +// --- Mutexes +typedef struct CelMutex CelMutex; + +CelMutex Mutex_Create(); +void Mutex_Destroy(CelMutex* mutex); + +/** @brief Blocks until the mutex can be acquired. if returns false then an error occurred and can + * be checked (TODO) */ +bool Mutex_Lock(CelMutex* mutex); + +/** @brief Tries to acquire the mutex like `mutex_lock` but returns immediately if the mutex has + * already been locked */ +bool Mutex_TryLock(CelMutex* mutex); + +/** @brief Releases a mutex. If it is already unlocked then does nothing */ +void Mutex_Unlock(CelMutex* mutex); diff --git a/src/archive/src/platform/platform_unix.c b/src/archive/src/platform/platform_unix.c new file mode 100644 index 0000000..86ac170 --- /dev/null +++ b/src/archive/src/platform/platform_unix.c @@ -0,0 +1,16 @@ +#include "platform.h" + +#if defined(CEL_PLATFORM_LINUX) || defined(CEL_PLATFORM_MAC) + +#include +#include + +path_opt path_parent(arena* a, const char* path) { + // Duplicate the string because dirname doesnt like const literals + char* path_copy = arena_alloc(a, strlen(path) + 1); + strcpy(path_copy, path); + char* path_dirname = dirname(path_copy); + return (path_opt){ .path = Str8_cstr_view(path_dirname), .has_value = true }; +} + +#endif diff --git a/src/archive/src/platform/platform_windows.c b/src/archive/src/platform/platform_windows.c new file mode 100644 index 0000000..21ef359 --- /dev/null +++ b/src/archive/src/platform/platform_windows.c @@ -0,0 +1,22 @@ +#include "platform.h" + +#if defined(CEL_PLATFORM_WINDOWS) + +#include +#include +#pragma comment(lib, "Shlwapi.lib") + +path_opt path_parent(arena* a, const char* path) { + // Duplicate the string because PathRemoveFileSpec mutates in-place + size_t len = strlen(path) + 1; + char* path_copy = arena_alloc(a, len); + strcpy_s(path_copy, len, path); + + if (PathRemoveFileSpecA(path_copy)) { + return (path_opt){ .path = Str8_cstr_view(path_copy), .has_value = true }; + } else { + return (path_opt){ .has_value = false }; + } +} + +#endif diff --git a/src/archive/src/ral/README.md b/src/archive/src/ral/README.md new file mode 100644 index 0000000..f66b95a --- /dev/null +++ b/src/archive/src/ral/README.md @@ -0,0 +1,5 @@ +# RAL + +**Render Abstraction Layer** is a thin abstraction over graphics APIs. Everything in `render` builds on top of the code in +this folder in order to be API-agnostic. It also makes writing graphics code easier as it smooths over some of the discrepancies +between APIs like texture/buffer creation and updating shader values. \ No newline at end of file diff --git a/src/archive/src/ral/backends/metal/backend_metal.h b/src/archive/src/ral/backends/metal/backend_metal.h new file mode 100644 index 0000000..e69de29 diff --git a/src/archive/src/ral/backends/opengl/backend_opengl.c b/src/archive/src/ral/backends/opengl/backend_opengl.c new file mode 100644 index 0000000..613d7e1 --- /dev/null +++ b/src/archive/src/ral/backends/opengl/backend_opengl.c @@ -0,0 +1,449 @@ +#include "backend_opengl.h" +#include "colours.h" +#include "maths_types.h" +#if defined(CEL_REND_BACKEND_OPENGL) +#include +#include "log.h" +#include "mem.h" +#include "opengl_helpers.h" +#include "ral_common.h" +#include "ral_impl.h" +#include "ral_types.h" + +#include +#include + +typedef struct OpenglCtx { + GLFWwindow* window; + arena pool_arena; + GPU_Swapchain swapchain; + GPU_CmdEncoder main_encoder; + GPU_BackendPools gpu_pools; + ResourcePools* resource_pools; +} OpenglCtx; + +static OpenglCtx context; + +bool GPU_Backend_Init(const char* window_name, struct GLFWwindow* window, + struct ResourcePools* res_pools) { + INFO("loading OpenGL backend"); + + memset(&context, 0, sizeof(context)); + context.window = window; + + size_t pool_buffer_size = 1024 * 1024; + context.pool_arena = arena_create(malloc(pool_buffer_size), pool_buffer_size); + + BackendPools_Init(&context.pool_arena, &context.gpu_pools); + context.resource_pools = res_pools; + + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + + // glad: load all opengl function pointers + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { + ERROR("Failed to initialise GLAD \n"); + return false; + } + + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + + context.swapchain = (GPU_Swapchain){ .dimensions = u32x2(1000, 1000) }; + + return true; +} + +// All of these are no-ops in OpenGL +void GPU_Backend_Shutdown() { /* TODO */ } +bool GPU_Device_Create(GPU_Device* out_device) { return true; } +void GPU_Device_Destroy(GPU_Device* device) {} +bool GPU_Swapchain_Create(GPU_Swapchain* out_swapchain) { return true; } +void GPU_Swapchain_Destroy(GPU_Swapchain* swapchain) {} +void GPU_CmdEncoder_Destroy(GPU_CmdEncoder* encoder) {} + +void GPU_CmdEncoder_BeginRender(GPU_CmdEncoder* encoder, GPU_Renderpass* renderpass) { + glBindFramebuffer(GL_FRAMEBUFFER, renderpass->fbo); + // rgba clear_colour = STONE_800; + // glClearColor(clear_colour.r, clear_colour.g, clear_colour.b, 1.0f); + // if (renderpass->description.has_depth_stencil) { + // glClear(GL_DEPTH_BUFFER_BIT); + // } else { + // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + // } +} + +void GPU_CmdEncoder_EndRender(GPU_CmdEncoder* encoder) { glBindFramebuffer(GL_FRAMEBUFFER, 0); } + +GPU_CmdEncoder* GPU_GetDefaultEncoder() { return &context.main_encoder; } +void GPU_QueueSubmit(GPU_CmdBuffer* cmd_buffer) {} + +void GPU_Swapchain_Resize(i32 new_width, i32 new_height) { + context.swapchain.dimensions = u32x2(new_width, new_height); +} + +u32x2 GPU_Swapchain_GetDimensions() { return context.swapchain.dimensions; } + +GPU_Renderpass* GPU_Renderpass_Create(GPU_RenderpassDesc description) { + // allocate new pass + GPU_Renderpass* renderpass = Renderpass_pool_alloc(&context.gpu_pools.renderpasses, NULL); + renderpass->description = description; + + if (!description.default_framebuffer) { + // If we're not using the default framebuffer we need to generate a new one + GLuint gl_fbo_id; + glGenFramebuffers(1, &gl_fbo_id); + renderpass->fbo = gl_fbo_id; + } else { + renderpass->fbo = OPENGL_DEFAULT_FRAMEBUFFER; + assert(!description.has_color_target); + assert(!description.has_depth_stencil); + } + glBindFramebuffer(GL_FRAMEBUFFER, renderpass->fbo); + + if (description.has_color_target && !description.default_framebuffer) { + GPU_Texture* colour_attachment = TEXTURE_GET(description.color_target); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + colour_attachment->id, 0); + } + if (description.has_depth_stencil && !description.default_framebuffer) { + GPU_Texture* depth_attachment = TEXTURE_GET(description.depth_stencil); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_attachment->id, + 0); + } + + if (description.has_depth_stencil && !description.has_color_target) { + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + } + + glBindFramebuffer(GL_FRAMEBUFFER, 0); // reset to default framebuffer + + return renderpass; +} + +void GPU_Renderpass_Destroy(GPU_Renderpass* pass) { glDeleteFramebuffers(1, &pass->fbo); } + +GPU_Pipeline* GPU_GraphicsPipeline_Create(GraphicsPipelineDesc description, + GPU_Renderpass* renderpass) { + GPU_Pipeline* pipeline = Pipeline_pool_alloc(&context.gpu_pools.pipelines, NULL); + + // Create shader program + u32 shader_id = shader_create_separate(description.vs.filepath.buf, description.fs.filepath.buf); + pipeline->shader_id = shader_id; + + // Vertex format + pipeline->vertex_desc = description.vertex_desc; + + // Allocate uniform buffers if needed + u32 ubo_count = 0; + // printf("data layouts %d\n", description.data_layouts_count); + for (u32 layout_i = 0; layout_i < description.data_layouts_count; layout_i++) { + ShaderDataLayout sdl = description.data_layouts[layout_i]; + TRACE("Got shader data layout %d's bindings! . found %d", layout_i, sdl.binding_count); + + for (u32 binding_j = 0; binding_j < sdl.binding_count; binding_j++) { + u32 binding_id = binding_j; + assert(binding_id < MAX_PIPELINE_UNIFORM_BUFFERS); + ShaderBinding binding = sdl.bindings[binding_j]; + // Do I want Buffer vs Bytes? + if (binding.kind == BINDING_BYTES) { + static u32 s_binding_point = 0; + BufferHandle ubo_handle = GPU_BufferCreate(binding.data.bytes.size, BUFFER_UNIFORM, + BUFFER_FLAG_GPU, NULL); // no data right now + pipeline->uniform_bindings[ubo_count++] = ubo_handle; + GPU_Buffer* ubo_buf = BUFFER_GET(ubo_handle); + + i32 blockIndex = glGetUniformBlockIndex(pipeline->shader_id, binding.label); + printf("Block index for %s: %d", binding.label, blockIndex); + if (blockIndex < 0) { + WARN("Couldn't retrieve block index for uniform block '%s'", binding.label); + } else { + // DEBUG("Retrived block index %d for %s", blockIndex, binding.label); + } + u32 blocksize; + glGetActiveUniformBlockiv(pipeline->shader_id, blockIndex, GL_UNIFORM_BLOCK_DATA_SIZE, + &blocksize); + printf("\t with size %d bytes\n", blocksize); + + glBindBufferBase(GL_UNIFORM_BUFFER, s_binding_point, ubo_buf->id.ubo); + if (blockIndex != GL_INVALID_INDEX) { + glUniformBlockBinding(pipeline->shader_id, blockIndex, s_binding_point); + } + ubo_buf->ubo_binding_point = s_binding_point++; + ubo_buf->name = binding.label; + assert(s_binding_point < GL_MAX_UNIFORM_BUFFER_BINDINGS); + } + } + } + pipeline->uniform_count = ubo_count; + + pipeline->renderpass = renderpass; + pipeline->wireframe = description.wireframe; + + return pipeline; +} + +void GraphicsPipeline_Destroy(GPU_Pipeline* pipeline) {} + +GPU_CmdEncoder GPU_CmdEncoder_Create() { + GPU_CmdEncoder encoder = { 0 }; + return encoder; +} + +BufferHandle GPU_BufferCreate(u64 size, GPU_BufferType buf_type, GPU_BufferFlags flags, + const void* data) { + // "allocating" the cpu-side buffer struct + BufferHandle handle; + GPU_Buffer* buffer = Buffer_pool_alloc(&context.resource_pools->buffers, &handle); + buffer->size = size; + buffer->vao = 0; + + // Opengl buffer + GLuint gl_buffer_id; + glGenBuffers(1, &gl_buffer_id); + + GLenum gl_buf_type; + GLenum gl_buf_usage = GL_STATIC_DRAW; + + switch (buf_type) { + case BUFFER_UNIFORM: + DEBUG("Creating Uniform buffer"); + gl_buf_type = GL_UNIFORM_BUFFER; + /* gl_buf_usage = GL_DYNAMIC_DRAW; */ + buffer->id.ubo = gl_buffer_id; + break; + case BUFFER_DEFAULT: + case BUFFER_VERTEX: + DEBUG("Creating Vertex buffer"); + gl_buf_type = GL_ARRAY_BUFFER; + buffer->id.vbo = gl_buffer_id; + break; + case BUFFER_INDEX: + DEBUG("Creating Index buffer"); + gl_buf_type = GL_ELEMENT_ARRAY_BUFFER; + buffer->id.ibo = gl_buffer_id; + break; + default: + WARN("Unimplemented gpu_buffer_type provided %s", buffer_type_names[buf_type]); + break; + } + // bind buffer + glBindBuffer(gl_buf_type, gl_buffer_id); + + if (data) { + TRACE("Upload data (%d bytes) as part of buffer creation", size); + glBufferData(gl_buf_type, buffer->size, data, gl_buf_usage); + } else { + TRACE("Allocating but not uploading (%d bytes)", size); + glBufferData(gl_buf_type, buffer->size, NULL, gl_buf_usage); + } + + glBindBuffer(gl_buf_type, 0); + + return handle; +} + +void GPU_BufferDestroy(BufferHandle handle) { glDeleteBuffers(1, &handle.raw); } + +TextureHandle GPU_TextureCreate(TextureDesc desc, bool create_view, const void* data) { + // "allocating" the cpu-side struct + TextureHandle handle; + GPU_Texture* texture = Texture_pool_alloc(&context.resource_pools->textures, &handle); + DEBUG("Allocated texture with handle %d", handle.raw); + + GLuint gl_texture_id; + glGenTextures(1, &gl_texture_id); + texture->id = gl_texture_id; + + GLenum gl_tex_type = opengl_tex_type(desc.tex_type); + texture->type = desc.tex_type; + printf("Creating texture of type %s\n", texture_type_names[desc.tex_type]); + glBindTexture(gl_tex_type, gl_texture_id); + + GLint internal_format; + if (desc.format == TEXTURE_FORMAT_DEPTH_DEFAULT) { + internal_format = GL_DEPTH_COMPONENT; + } else if (desc.format == TEXTURE_FORMAT_8_8_8_8_RGBA_UNORM) { + internal_format = GL_RGBA; + } else { + internal_format = GL_RGB; + } + + GLint format = internal_format; + // FIXME: GLint format = desc.format == TEXTURE_FORMAT_DEPTH_DEFAULT ? GL_DEPTH_COMPONENT : + // GL_RGBA; + GLenum data_type = desc.format == TEXTURE_FORMAT_DEPTH_DEFAULT ? GL_FLOAT : GL_UNSIGNED_BYTE; + + if (desc.format == TEXTURE_FORMAT_DEPTH_DEFAULT) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + } else { + // set the texture wrapping parameters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, + GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + // set texture filtering parameters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + + if (data) { + glTexImage2D(GL_TEXTURE_2D, 0, internal_format, desc.extents.x, desc.extents.y, 0, format, + data_type, data); + if (desc.tex_type == TEXTURE_TYPE_2D) { + glGenerateMipmap(GL_TEXTURE_2D); + } + } else { + WARN("No image data provided"); + glTexImage2D(GL_TEXTURE_2D, 0, internal_format, desc.extents.x, desc.extents.y, 0, format, + data_type, NULL); + } + + glBindTexture(GL_TEXTURE_2D, 0); + + return handle; +} + +GPU_Texture* GPU_TextureAlloc(TextureHandle* out_handle) { + TextureHandle handle; + GPU_Texture* texture = Texture_pool_alloc(&context.resource_pools->textures, &handle); + DEBUG("Allocated texture with handle %d", handle.raw); + + GLuint gl_texture_id; + glGenTextures(1, &gl_texture_id); + texture->id = gl_texture_id; + + if (out_handle != NULL) { + *out_handle = handle; + } + + return texture; +} + +void GPU_TextureDestroy(TextureHandle handle) { glDeleteTextures(1, &handle.raw); } + +// TODO: void GPU_TextureUpload(TextureHandle handle, size_t n_bytes, const void* data) + +void GPU_EncodeBindPipeline(GPU_CmdEncoder* encoder, GPU_Pipeline* pipeline) { + encoder->pipeline = pipeline; + + // In OpenGL binding a pipeline is more or less equivalent to just setting the shader + glUseProgram(pipeline->shader_id); + + if (pipeline->wireframe) { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + } else { + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } +} + +void GPU_EncodeBindShaderData(GPU_CmdEncoder* encoder, u32 group, ShaderDataLayout layout) { + for (u32 binding_i = 0; binding_i < layout.binding_count; binding_i++) { + ShaderBinding binding = layout.bindings[binding_i]; + + switch (binding.kind) { + case BINDING_BYTES: { +#ifdef RAL_ASSERTS + CASSERT_MSG(binding.data.bytes.data, "void* data pointer should be non null"); + CASSERT_MSG(binding.data.bytes.size > 0, "size should be greater than 0 bytes"); +#endif + BufferHandle b; + GPU_Buffer* ubo_buf; + bool found = false; + for (u32 i = 0; i < encoder->pipeline->uniform_count; i++) { + b = encoder->pipeline->uniform_bindings[i]; + ubo_buf = BUFFER_GET(b); + assert(ubo_buf->name != NULL); + if (strcmp(ubo_buf->name, binding.label) == 0) { + found = true; + break; + } + } + if (!found) { + ERROR("Couldnt find uniform buffer object for %s!!", binding.label); + break; + } + + i32 blockIndex = glGetUniformBlockIndex(encoder->pipeline->shader_id, binding.label); + if (blockIndex < 0) { + WARN("Couldn't retrieve block index for uniform block '%s'", binding.label); + break; + } + + glBindBuffer(GL_UNIFORM_BUFFER, ubo_buf->id.ubo); + glBufferSubData(GL_UNIFORM_BUFFER, 0, ubo_buf->size, binding.data.bytes.data); + break; + } + case BINDING_TEXTURE: { + GPU_Texture* tex = TEXTURE_GET(binding.data.texture.handle); + GLint tex_slot = glGetUniformLocation(encoder->pipeline->shader_id, binding.label); + if (tex_slot == GL_INVALID_VALUE || tex_slot < 0) { + WARN("Invalid binding label for texture %s - couldn't fetch texture slot uniform", + binding.label); + } + glUniform1i(tex_slot, binding_i); + glActiveTexture(GL_TEXTURE0 + binding_i); + glBindTexture(opengl_tex_type(tex->type), tex->id); + break; + } + default: + WARN("Unsupported binding kind"); + } + } +} + +void GPU_EncodeSetDefaults(GPU_CmdEncoder* encoder) {} + +void GPU_EncodeSetVertexBuffer(GPU_CmdEncoder* encoder, BufferHandle buf) { + GPU_Buffer* buffer = BUFFER_GET(buf); + if (buffer->vao == 0) { // if no VAO for this vertex buffer, create it + INFO("Setting up VAO"); + buffer->vao = opengl_bindcreate_vao(buffer, encoder->pipeline->vertex_desc); + } + glBindVertexArray(buffer->vao); +} +void GPU_EncodeSetIndexBuffer(GPU_CmdEncoder* encoder, BufferHandle buf) { + GPU_Buffer* buffer = BUFFER_GET(buf); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer->id.ibo); +} +void GPU_EncodeDrawTris(GPU_CmdEncoder* encoder, u64 count) { + glDrawArrays(GL_TRIANGLES, 0, count); +} +void GPU_EncodeDrawIndexedTris(GPU_CmdEncoder* encoder, u64 index_count) { + glDrawElements(GL_TRIANGLES, index_count, GL_UNSIGNED_INT, 0); +} + +PUB void GPU_EncodeDraw(GPU_CmdEncoder* encoder, PrimitiveTopology topology, u64 count) { + glDrawArrays(opengl_prim_topology(topology), 0, count); +} +PUB void GPU_EncodeDrawIndexed(GPU_CmdEncoder* encoder, PrimitiveTopology topology, + u64 index_count) { + glDrawElements(opengl_prim_topology(topology), index_count, GL_UNSIGNED_INT, 0); +} + +PUB void GPU_WriteTextureRegion(GPU_CmdEncoder* encoder, TextureHandle dst, u32 x_offset, + u32 y_offset, u32 width, u32 height, const void* data) { + CASSERT_MSG(data, "const void* data must not be NULL"); + + GPU_Texture* tex = TEXTURE_GET(dst); + + glBindTexture(GL_TEXTURE_2D, tex->id); + glTexSubImage2D(GL_TEXTURE_2D, 0, x_offset, y_offset, width, height, GL_RGBA, GL_UNSIGNED_BYTE, + data); +} + +bool GPU_Backend_BeginFrame() { + glViewport(0, 0, context.swapchain.dimensions.x * 2, context.swapchain.dimensions.y * 2); + glClearColor(0.1f, 0.1f, 0.1f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + return true; +} + +void GPU_Backend_EndFrame() { glfwSwapBuffers(context.window); } + +#endif diff --git a/src/archive/src/ral/backends/opengl/backend_opengl.h b/src/archive/src/ral/backends/opengl/backend_opengl.h new file mode 100644 index 0000000..7bd1b81 --- /dev/null +++ b/src/archive/src/ral/backends/opengl/backend_opengl.h @@ -0,0 +1,109 @@ +#pragma once +#include "defines.h" + +#if defined(CEL_REND_BACKEND_OPENGL) + +#include "maths_types.h" +#include "ral_impl.h" +#include "ral_types.h" + +#define MAX_PIPELINE_UNIFORM_BUFFERS 32 + +#define OPENGL_DEFAULT_FRAMEBUFFER 0 + +typedef struct GPU_Swapchain { + u32x2 dimensions; +} GPU_Swapchain; + +typedef struct GPU_Device { + u32 pad; +} GPU_Device; + +typedef struct GPU_PipelineLayout { + void* pad; +} GPU_PipelineLayout; + +typedef struct GPU_Pipeline { + u32 shader_id; + GPU_Renderpass* renderpass; + VertexDescription vertex_desc; + BufferHandle uniform_bindings[MAX_PIPELINE_UNIFORM_BUFFERS]; + u32 uniform_count; + bool wireframe; +} GPU_Pipeline; + +typedef struct GPU_Renderpass { + u32 fbo; + GPU_RenderpassDesc description; +} GPU_Renderpass; + +typedef struct GPU_CmdEncoder { + GPU_Pipeline* pipeline; +} GPU_CmdEncoder; // Recording + +typedef struct GPU_CmdBuffer { + void* pad; +} GPU_CmdBuffer; // Ready for submission + +typedef struct GPU_Buffer { + union { + u32 vbo; + u32 ibo; + u32 ubo; + } id; + union { + u32 vao; + u32 ubo_binding_point; + }; // Optional + char* name; + u64 size; +} GPU_Buffer; + +typedef struct GPU_Texture { + u32 id; + GPU_TextureType type; +} GPU_Texture; + +typedef struct opengl_support { + u32 pad; +} opengl_support; + +void uniform_vec3f(u32 program_id, const char* uniform_name, Vec3* value); +void uniform_f32(u32 program_id, const char* uniform_name, f32 value); +void uniform_i32(u32 program_id, const char* uniform_name, i32 value); +void uniform_mat4f(u32 program_id, const char* uniform_name, Mat4* value); + +typedef enum GlCommandType { + GLCMD_DRAW, + GLCMD_DRAW_INDEXED, + GLCMD_BIND_VBUF, + GLCMD_BIND_IBUF, + GLCMD_SET_PROGRAM, +} GlCommandType; + +typedef struct GlCommand { + GlCommandType cmd_type; + union { + struct { + PrimitiveTopology topology; + u32 start_vertex; + u32 vertex_count; + // TODO: instance + } draw; + struct { + PrimitiveTopology topology; + u32 index_count; + } draw_indexed; + struct { + u32 buffer_id; + } bind_vbuf; + struct { + u32 buffer_id; + } bind_ibuf; + struct { + u32 program_id; + } set_program; + } data; +} GlCommand; + +#endif diff --git a/src/archive/src/ral/backends/opengl/opengl_helpers.h b/src/archive/src/ral/backends/opengl/opengl_helpers.h new file mode 100644 index 0000000..706e2a0 --- /dev/null +++ b/src/archive/src/ral/backends/opengl/opengl_helpers.h @@ -0,0 +1,159 @@ +#pragma once +#include "defines.h" +#include "ral_common.h" +#include "ral_impl.h" +#if defined(CEL_REND_BACKEND_OPENGL) +#include "backend_opengl.h" +#include "file.h" +#include "log.h" +#include "ral_types.h" + +#include +#include +#include "ral_types.h" + +typedef struct opengl_vertex_attr { + u32 count; + GLenum data_type; +} opengl_vertex_attr; + +static opengl_vertex_attr format_from_vertex_attr(VertexAttribType attr) { + switch (attr) { + case ATTR_F32: + return (opengl_vertex_attr){ .count = 1, .data_type = GL_FLOAT }; + case ATTR_U32: + return (opengl_vertex_attr){ .count = 1, .data_type = GL_UNSIGNED_INT }; + case ATTR_I32: + return (opengl_vertex_attr){ .count = 1, .data_type = GL_INT }; + case ATTR_F32x2: + return (opengl_vertex_attr){ .count = 2, .data_type = GL_FLOAT }; + case ATTR_U32x2: + // return VK_FORMAT_R32G32_UINT; + case ATTR_I32x2: + // return VK_FORMAT_R32G32_UINT; + case ATTR_F32x3: + return (opengl_vertex_attr){ .count = 3, .data_type = GL_FLOAT }; + case ATTR_U32x3: + // return VK_FORMAT_R32G32B32_UINT; + case ATTR_I32x3: + // return VK_FORMAT_R32G32B32_SINT; + case ATTR_F32x4: + return (opengl_vertex_attr){ .count = 4, .data_type = GL_FLOAT }; + case ATTR_U32x4: + // return VK_FORMAT_R32G32B32A32_UINT; + case ATTR_I32x4: + return (opengl_vertex_attr){ .count = 4, .data_type = GL_INT }; + } +} + +static u32 opengl_bindcreate_vao(GPU_Buffer* buf, VertexDescription desc) { + DEBUG("Vertex format name %s", desc.debug_label); + // 1. Bind the buffer + glBindBuffer(GL_ARRAY_BUFFER, buf->id.vbo); + // 2. Create new VAO + u32 vao; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + // Attributes + u32 attr_count = desc.attributes_count; + // printf("N attributes %d\n", attr_count); + u64 offset = 0; + size_t vertex_size = desc.use_full_vertex_size ? sizeof(Vertex) : VertexDesc_CalcStride(&desc); + for (u32 i = 0; i < desc.attributes_count; i++) { + opengl_vertex_attr format = format_from_vertex_attr(desc.attributes[i]); + glVertexAttribPointer(i, format.count, format.data_type, GL_FALSE, vertex_size, (void*)offset); + TRACE(" %d %d %d %d %d %s", i, format.count, format.data_type, vertex_size, offset, + desc.attr_names[i]); + glEnableVertexAttribArray(i); // nth index + size_t this_offset = VertexAttribSize(desc.attributes[i]); + // printf("offset total %lld this attr %zu\n", offset, this_offset); + offset += this_offset; + } + glBindBuffer(GL_ARRAY_BUFFER, 0); + + return vao; +} + +static u32 shader_create_separate(const char* vert_shader, const char* frag_shader) { + INFO("Load shaders at %s and %s", vert_shader, frag_shader); + int success; + char info_log[512]; + + u32 vertex = glCreateShader(GL_VERTEX_SHADER); + const char* vertex_shader_src = string_from_file(vert_shader); + if (vertex_shader_src == NULL) { + ERROR("EXIT: couldnt load shader"); + exit(-1); + } + glShaderSource(vertex, 1, &vertex_shader_src, NULL); + glCompileShader(vertex); + glGetShaderiv(vertex, GL_COMPILE_STATUS, &success); + if (!success) { + glGetShaderInfoLog(vertex, 512, NULL, info_log); + printf("%s\n", info_log); + ERROR("EXIT: vertex shader compilation failed"); + exit(-1); + } + + // fragment shader + u32 fragment = glCreateShader(GL_FRAGMENT_SHADER); + const char* fragment_shader_src = string_from_file(frag_shader); + if (fragment_shader_src == NULL) { + ERROR("EXIT: couldnt load shader"); + exit(-1); + } + glShaderSource(fragment, 1, &fragment_shader_src, NULL); + glCompileShader(fragment); + glGetShaderiv(fragment, GL_COMPILE_STATUS, &success); + if (!success) { + glGetShaderInfoLog(fragment, 512, NULL, info_log); + printf("%s\n", info_log); + ERROR("EXIT: fragment shader compilation failed"); + exit(-1); + } + + u32 shader_prog; + shader_prog = glCreateProgram(); + + glAttachShader(shader_prog, vertex); + glAttachShader(shader_prog, fragment); + glLinkProgram(shader_prog); + glDeleteShader(vertex); + glDeleteShader(fragment); + free((char*)vertex_shader_src); + free((char*)fragment_shader_src); + + return shader_prog; +} + +static GLenum opengl_tex_type(GPU_TextureType tex_type) { + switch (tex_type) { + case TEXTURE_TYPE_2D: + return GL_TEXTURE_2D; + case TEXTURE_TYPE_CUBE_MAP: + return GL_TEXTURE_CUBE_MAP; + default: + return GL_TEXTURE_2D; + } +} + +static GLenum opengl_prim_topology(PrimitiveTopology t) { + switch (t) { + case CEL_POINT: + return GL_POINT; + case CEL_LINE: + return GL_LINES; + case CEL_LINE_STRIP: + return GL_LINE_STRIP; + case CEL_TRI: + return GL_TRIANGLES; + case CEL_TRI_STRIP: + return GL_TRIANGLE_STRIP; + case PRIMITIVE_TOPOLOGY_COUNT: + WARN("Invalid PrimitiveTopology value"); + break; + } +} + +#endif diff --git a/src/archive/src/ral/backends/vulkan/backend_vulkan.c b/src/archive/src/ral/backends/vulkan/backend_vulkan.c new file mode 100644 index 0000000..e69de29 diff --git a/src/archive/src/ral/backends/vulkan/backend_vulkan.h b/src/archive/src/ral/backends/vulkan/backend_vulkan.h new file mode 100644 index 0000000..f31bed2 --- /dev/null +++ b/src/archive/src/ral/backends/vulkan/backend_vulkan.h @@ -0,0 +1,44 @@ +#pragma once + +#ifdef CEL_REND_BACKEND_VULKAN +#include "defines.h" +#include "maths_types.h" +#include "ral.h" +#include "ral_impl.h" +#include "ral_types.h" + +#include +#include +#include + +// Provide definitions for RAL structs + +struct GPU_Swapchain { + VkSwapchainKHR handle; +}; + +struct GPU_Device { + VkPhysicalDevice physical_device; + VkDevice logical_device; +}; + +struct GPU_PipelineLayout {}; +struct GPU_Pipeline {}; +struct GPU_Renderpass {}; +struct GPU_CmdEncoder {}; +struct GPU_CmdBuffer {}; +struct GPU_Buffer { + VkBuffer handle; + VkDeviceMemory memory; + u64 size; +}; +struct GPU_Texture { + VkImage handle; + VkDeviceMemory memory; + u64 size; + VkImageView view; + VkSampler sampler; + char* debug_label; +}; + +#endif diff --git a/src/archive/src/ral/backends/vulkan/vulkan_glossary.md b/src/archive/src/ral/backends/vulkan/vulkan_glossary.md new file mode 100644 index 0000000..4214f9d --- /dev/null +++ b/src/archive/src/ral/backends/vulkan/vulkan_glossary.md @@ -0,0 +1,18 @@ +# Vulkan Glossary + +*from https://vkguide.dev/docs/introduction/vulkan_execution/* + +- **VkInstance**: The Vulkan context, used to access drivers. +- **VkPhysicalDevice**: A GPU. Used to query physical GPU details, like features, capabilities, memory size, etc. +- **VkDevice**: The “logical” GPU context that you actually execute things on. +- **VkBuffer**: A chunk of GPU visible memory. +- **VkImage**: A texture you can write to and read from. +- **VkPipeline**: Holds the state of the gpu needed to draw. For example: shaders, rasterization options, depth settings. +- **VkRenderPass**: Holds information about the images you are rendering into. All drawing commands have to be done inside a renderpass. Only used in legacy vkguide. +- **VkFrameBuffer**: Holds the target images for a renderpass. Only used in legacy vkguide. +- **VkCommandBuffer**: Encodes GPU commands. All execution that is performed on the GPU itself (not in the driver) has to be encoded in a VkCommandBuffer. +- **VkQueue**: Execution “port” for commands. GPUs will have a set of queues with different properties. Some allow only graphics commands, others only allow memory commands, etc. Command buffers are executed by submitting them into a queue, which will copy the rendering commands onto the GPU for execution. +- **VkDescriptorSet**: Holds the binding information that connects shader inputs to data such as VkBuffer resources and VkImage textures. Think of it as a set of gpu-side pointers that you bind once. +- **VkSwapchainKHR**: Holds the images for the screen. It allows you to render things into a visible window. The KHR suffix shows that it comes from an extension, which in this case is VK_KHR_swapchain. +- **VkSemaphore**: Synchronizes GPU to GPU execution of commands. Used for syncing multiple command buffer submissions one after another. +- **VkFence**: Synchronizes GPU to CPU execution of commands. Used to know if a command buffer has finished being executed on the GPU. diff --git a/src/archive/src/ral/backends/vulkan/vulkan_helpers.h b/src/archive/src/ral/backends/vulkan/vulkan_helpers.h new file mode 100644 index 0000000..23666c6 --- /dev/null +++ b/src/archive/src/ral/backends/vulkan/vulkan_helpers.h @@ -0,0 +1,199 @@ +#pragma once + +#include +#include +#include + +#include "darray.h" +#include "defines.h" +#include "log.h" +#include "str.h" + +#define VULKAN_PHYS_DEVICE_MAX_EXTENSION_NAMES 36 + +DECL_TYPED_ARRAY(const char*, cstr) + +static void plat_get_required_extension_names(cstr_darray* extensions) { +#ifdef CEL_PLATFORM_LINUX + cstr_darray_push(extensions, "VK_KHR_xcb_surface"); +#endif +} + +// TODO(omni): port to using internal assert functions +#define VK_CHECK(vulkan_expr) \ + do { \ + VkResult res = vulkan_expr; \ + if (res != VK_SUCCESS) { \ + ERROR_EXIT("Vulkan error: %u (%s:%d)", res, __FILE__, __LINE__); \ + } \ + } while (0) + +// TODO: typedef struct vk_debugger {} vk_debugger; + +typedef struct vulkan_physical_device_requirements { + bool graphics; + bool present; + bool compute; + bool transfer; + str8 device_ext_names[VULKAN_PHYS_DEVICE_MAX_EXTENSION_NAMES]; + size_t device_ext_name_count; + bool sampler_anistropy; + bool discrete_gpu; +} vulkan_physical_device_requirements; + +#define VULKAN_MAX_DEFAULT 32 + +typedef struct vulkan_swapchain_support_info { + VkSurfaceCapabilitiesKHR capabilities; + VkSurfaceFormatKHR formats[VULKAN_MAX_DEFAULT]; + u32 format_count; + VkPresentModeKHR present_modes[VULKAN_MAX_DEFAULT]; + u32 mode_count; +} vulkan_swapchain_support_info; + +VKAPI_ATTR VkBool32 VKAPI_CALL vk_debug_callback( + VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT flags, + const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* user_data); + +static void vulkan_device_query_swapchain_support(VkPhysicalDevice device, VkSurfaceKHR surface, + vulkan_swapchain_support_info* out_support_info) { + // TODO: add VK_CHECK to these calls! + + // Surface capabilities + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &out_support_info->capabilities); + + // Surface formats + vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &out_support_info->format_count, + 0); // Get number of formats + if (out_support_info->format_count > 0) { + vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &out_support_info->format_count, + out_support_info->formats); + } + + // Present Modes + vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &out_support_info->mode_count, + 0); // Get number of formats + if (out_support_info->mode_count > 0) { + vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &out_support_info->mode_count, + out_support_info->present_modes); + } +} + +static VkSurfaceFormatKHR choose_swapchain_format( + vulkan_swapchain_support_info* swapchain_support) { + assert(swapchain_support->format_count > 0); + // find a format + for (u32 i = 0; i < swapchain_support->format_count; i++) { + VkSurfaceFormatKHR format = swapchain_support->formats[i]; + if (format.format == VK_FORMAT_B8G8R8A8_SRGB && + format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + return format; + } + } + return swapchain_support->formats[0]; +} + +// static bool physical_device_meets_requirements( +// VkPhysicalDevice device, VkSurfaceKHR surface, const VkPhysicalDeviceProperties* properties, +// const VkPhysicalDeviceFeatures* features, +// const vulkan_physical_device_requirements* requirements, +// vulkan_physical_device_queue_family_info* out_queue_info, +// vulkan_swapchain_support_info* out_swapchain_support) { +// // TODO: pass in an arena + +// out_queue_info->graphics_family_index = -1; +// out_queue_info->present_family_index = -1; +// out_queue_info->compute_family_index = -1; +// out_queue_info->transfer_family_index = -1; + +// if (requirements->discrete_gpu) { +// if (properties->deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) { +// TRACE("Device is not a physical GPU. Skipping."); +// return false; +// } +// } + +// u32 queue_family_count = 0; +// vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, 0); +// VkQueueFamilyProperties queue_families[queue_family_count]; +// vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, queue_families); + +// INFO("Graphics | Present | Compute | Transfer | Name"); +// u8 min_transfer_score = 255; +// for (u32 i = 0; i < queue_family_count; i++) { +// u8 current_transfer_score = 0; + +// // Graphics queue +// if (queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { +// out_queue_info->graphics_family_index = i; +// current_transfer_score++; +// } + +// // Compute queue +// if (queue_families[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { +// out_queue_info->compute_family_index = i; +// current_transfer_score++; +// } + +// // Transfer queue +// if (queue_families[i].queueFlags & VK_QUEUE_TRANSFER_BIT) { +// // always take the lowest score transfer index +// if (current_transfer_score <= min_transfer_score) { +// min_transfer_score = current_transfer_score; +// out_queue_info->transfer_family_index = i; +// } +// } + +// // Present Queue +// VkBool32 supports_present = VK_FALSE; +// vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &supports_present); +// if (supports_present) { +// out_queue_info->present_family_index = i; +// } +// } + +// INFO(" %d | %d | %d | %d | %s", +// out_queue_info->graphics_family_index != -1, out_queue_info->present_family_index != -1, +// out_queue_info->compute_family_index != -1, out_queue_info->transfer_family_index != -1, +// properties->deviceName); +// TRACE("Graphics Family queue index: %d", out_queue_info->graphics_family_index); +// TRACE("Present Family queue index: %d", out_queue_info->present_family_index); +// TRACE("Compute Family queue index: %d", out_queue_info->compute_family_index); +// TRACE("Transfer Family queue index: %d", out_queue_info->transfer_family_index); + +// if ((!requirements->graphics || +// (requirements->graphics && out_queue_info->graphics_family_index != -1))) { +// INFO("Physical device meets our requirements! Proceed."); + +// vulkan_device_query_swapchain_support( +// device, surface, out_swapchain_support + +// // TODO: error handling i.e. format count = 0 or present mode = 0 + +// ); +// return true; +// } + +// return false; +// } + +VKAPI_ATTR VkBool32 VKAPI_CALL vk_debug_callback( + VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT flags, + const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* user_data) { + switch (severity) { + default: + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: + ERROR("%s", callback_data->pMessage); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: + WARN("%s", callback_data->pMessage); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: + INFO("%s", callback_data->pMessage); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: + TRACE("%s", callback_data->pMessage); + break; + } + return VK_FALSE; +} \ No newline at end of file diff --git a/src/archive/src/ral/ral.h b/src/archive/src/ral/ral.h new file mode 100644 index 0000000..fdbadd3 --- /dev/null +++ b/src/archive/src/ral/ral.h @@ -0,0 +1,5 @@ +#pragma once + +#include "ral_common.h" +#include "ral_impl.h" +#include "ral_types.h" \ No newline at end of file diff --git a/src/archive/src/ral/ral_common.c b/src/archive/src/ral/ral_common.c new file mode 100644 index 0000000..d921ac4 --- /dev/null +++ b/src/archive/src/ral/ral_common.c @@ -0,0 +1,70 @@ +#include "ral_common.h" +#include "ral_impl.h" + +void BackendPools_Init(arena* a, GPU_BackendPools* backend_pools) { + PipelineLayout_pool pipeline_layout_pool = + PipelineLayout_pool_create(a, MAX_PIPELINES, sizeof(GPU_PipelineLayout)); + backend_pools->pipeline_layouts = pipeline_layout_pool; + Pipeline_pool pipeline_pool = Pipeline_pool_create(a, MAX_PIPELINES, sizeof(GPU_Pipeline)); + backend_pools->pipelines = pipeline_pool; + Renderpass_pool rpass_pool = Renderpass_pool_create(a, MAX_RENDERPASSES, sizeof(GPU_Renderpass)); + backend_pools->renderpasses = rpass_pool; +} + +void ResourcePools_Init(arena* a, struct ResourcePools* res_pools) { + Buffer_pool buf_pool = Buffer_pool_create(a, MAX_BUFFERS, sizeof(GPU_Buffer)); + res_pools->buffers = buf_pool; + Texture_pool tex_pool = Texture_pool_create(a, MAX_TEXTURES, sizeof(GPU_Texture)); + res_pools->textures = tex_pool; +} + +VertexDescription static_3d_vertex_description() { + VertexDescription builder = { .debug_label = "Standard static 3d vertex format" }; + VertexDesc_AddAttr(&builder, "inPosition", ATTR_F32x3); + VertexDesc_AddAttr(&builder, "inNormal", ATTR_F32x3); + VertexDesc_AddAttr(&builder, "inTexCoords", ATTR_F32x2); + builder.use_full_vertex_size = true; + return builder; +} + +void VertexDesc_AddAttr(VertexDescription* builder, const char* name, VertexAttribType type) { + u32 i = builder->attributes_count; + + size_t size = VertexAttribSize(type); + builder->attributes[i] = type; + // builder->stride += size; + builder->attr_names[i] = name; + + builder->attributes_count++; +} + +size_t VertexAttribSize(VertexAttribType attr) { + switch (attr) { + case ATTR_F32: + case ATTR_U32: + case ATTR_I32: + return 4; + case ATTR_F32x2: + case ATTR_U32x2: + case ATTR_I32x2: + return 8; + case ATTR_F32x3: + case ATTR_U32x3: + case ATTR_I32x3: + return 12; + case ATTR_F32x4: + case ATTR_U32x4: + case ATTR_I32x4: + return 16; + break; + } +} + +size_t VertexDesc_CalcStride(VertexDescription* desc) { + size_t stride = 0; + for (int i = 0; i < desc->attributes_count; i++) { + size_t size = VertexAttribSize(desc->attributes[i]); + stride += size; + } + return stride; +} diff --git a/src/archive/src/ral/ral_common.h b/src/archive/src/ral/ral_common.h new file mode 100644 index 0000000..5a797e5 --- /dev/null +++ b/src/archive/src/ral/ral_common.h @@ -0,0 +1,61 @@ +/** + * @brief Common functions that don't actually depend on the specific backend + */ +#pragma once +#include "buf.h" +#include "defines.h" +#include "mem.h" +#include "ral_types.h" +// #include "ral_impl.h" + +// Concrete implementation +#if defined(CEL_REND_BACKEND_OPENGL) +#include "backend_opengl.h" +#endif + +TYPED_POOL(GPU_Buffer, Buffer); +TYPED_POOL(GPU_Texture, Texture); +TYPED_POOL(GPU_PipelineLayout, PipelineLayout); +TYPED_POOL(GPU_Pipeline, Pipeline); +TYPED_POOL(GPU_Renderpass, Renderpass); + +// --- Handy macros +#define BUFFER_GET(h) (Buffer_pool_get(&context.resource_pools->buffers, h)) +#define TEXTURE_GET(h) (Texture_pool_get(&context.resource_pools->textures, h)) + +// --- Views +typedef struct GPU_BufferView { + BufferHandle buf; + size_t offset; + size_t bytes; +} GPU_BufferView; + +// --- Pools +typedef struct GPU_BackendPools { + Pipeline_pool pipelines; + PipelineLayout_pool pipeline_layouts; + Renderpass_pool renderpasses; +} GPU_BackendPools; +void BackendPools_Init(arena* a, GPU_BackendPools* backend_pools); + +struct ResourcePools { + Buffer_pool buffers; + Texture_pool textures; +}; +typedef struct ResourcePools ResourcePools; +void ResourcePools_Init(arena* a, struct ResourcePools* res_pools); + +PUB GPU_Renderpass* GPU_GetDefaultRenderpass(); // returns a renderpass that draws directly to + // default framebuffer with default depth + +// -- +// window resize callback +void GPU_WindowResizedCallback(u32 x, u32 y); + +// --- Vertex formats +VertexDescription static_3d_vertex_description(); + +void VertexDesc_AddAttr(VertexDescription* builder, const char* name, VertexAttribType type); +size_t VertexDesc_CalcStride(VertexDescription* desc); + +size_t VertexAttribSize(VertexAttribType attr); diff --git a/src/archive/src/ral/ral_impl.h b/src/archive/src/ral/ral_impl.h new file mode 100644 index 0000000..16c9767 --- /dev/null +++ b/src/archive/src/ral/ral_impl.h @@ -0,0 +1,102 @@ +/** + * @brief + */ +#pragma once +#include "buf.h" +#include "defines.h" +#include "ral_types.h" + +struct GLFWwindow; +struct ResourcePools; + +// Forward declare structs - these must be defined in the backend implementation +typedef struct GPU_Swapchain GPU_Swapchain; +typedef struct GPU_Device GPU_Device; +typedef struct GPU_PipelineLayout GPU_PipelineLayout; +typedef struct GPU_Pipeline GPU_Pipeline; +typedef struct GPU_Renderpass GPU_Renderpass; +typedef struct GPU_CmdEncoder GPU_CmdEncoder; // Recording +typedef struct GPU_CmdBuffer GPU_CmdBuffer; // Ready for submission +typedef struct GPU_Buffer GPU_Buffer; +typedef struct GPU_Texture GPU_Texture; + +bool GPU_Backend_Init(const char* window_name, struct GLFWwindow* window, + struct ResourcePools* res_pools); +void GPU_Backend_Shutdown(); + +bool GPU_Device_Create(GPU_Device* out_device); +void GPU_Device_Destroy(GPU_Device* device); + +bool GPU_Swapchain_Create(GPU_Swapchain* out_swapchain); +void GPU_Swapchain_Destroy(GPU_Swapchain* swapchain); +void GPU_Swapchain_Resize(i32 new_width, i32 new_height); +u32x2 GPU_Swapchain_GetDimensions(); + +PUB GPU_Renderpass* GPU_Renderpass_Create(GPU_RenderpassDesc description); +PUB void GPU_Renderpass_Destroy(GPU_Renderpass* pass); + +PUB GPU_Pipeline* GPU_GraphicsPipeline_Create(GraphicsPipelineDesc description, + GPU_Renderpass* renderpass); +PUB void GraphicsPipeline_Destroy(GPU_Pipeline* pipeline); + +// --- Command buffer +PUB GPU_CmdEncoder GPU_CmdEncoder_Create(); +PUB void GPU_CmdEncoder_Destroy(GPU_CmdEncoder* encoder); +PUB void GPU_CmdEncoder_Begin(GPU_CmdEncoder* encoder); +PUB void GPU_CmdEncoder_Finish(GPU_CmdEncoder* encoder); +PUB void GPU_CmdEncoder_BeginRender(GPU_CmdEncoder* encoder, GPU_Renderpass* renderpass); +PUB void GPU_CmdEncoder_EndRender(GPU_CmdEncoder* encoder); +PUB GPU_CmdEncoder* GPU_GetDefaultEncoder(); +PUB void GPU_QueueSubmit(GPU_CmdBuffer* cmd_buffer); + +// --- Buffers +PUB BufferHandle GPU_BufferCreate(u64 size, GPU_BufferType buf_type, GPU_BufferFlags flags, + const void* data); +PUB void GPU_BufferDestroy(BufferHandle handle); +PUB void GPU_BufferUpload(BufferHandle buffer, size_t n_bytes, const void* data); + +// --- Textures +PUB TextureHandle GPU_TextureCreate(TextureDesc desc, bool create_view, const void* data); +PUB GPU_Texture* GPU_TextureAlloc(TextureHandle* out_handle); +PUB void GPU_TextureDestroy(TextureHandle handle); +PUB void GPU_TextureUpload(TextureHandle handle, size_t n_bytes, const void* data); + +// --- Data copy commands +PUB void GPU_EncodeCopyBufToBuf(GPU_CmdEncoder* encoder, BufferHandle src, u64 src_offset, + BufferHandle dst, u64 dst_offset, u64 copy_size); + +// PUB void GPU_EncodeCopyBufToTex(GPU_CmdEncoder* encoder, BufferHandle src, TextureHandle dst, +// u32 x_offset, u32 y_offset, u32 width, u32 height, const void* data); +/** @brief Convenience method for writing data directly into a texture. Staging memory is handled + * internally. */ +PUB void GPU_WriteTextureRegion(GPU_CmdEncoder* encoder, TextureHandle dst, u32 x_offset, + u32 y_offset, u32 width, u32 height, const void* data); +PUB void GPU_WriteBuffer(GPU_CmdEncoder* encoder, BufferHandle buf, u64 offset, u64 size, + const void* data); + +// --- Render commands +PUB void GPU_EncodeBindPipeline(GPU_CmdEncoder* encoder, GPU_Pipeline* pipeline); +PUB void GPU_EncodeBindShaderData(GPU_CmdEncoder* encoder, u32 group, ShaderDataLayout layout); +void GPU_EncodeSetDefaults(GPU_CmdEncoder* encoder); +PUB void GPU_EncodeSetVertexBuffer(GPU_CmdEncoder* encoder, BufferHandle buf); +PUB void GPU_EncodeSetIndexBuffer(GPU_CmdEncoder* encoder, BufferHandle buf); + +PUB void GPU_EncodeDraw(GPU_CmdEncoder* encoder, PrimitiveTopology topology, u64 count); +PUB void GPU_EncodeDrawIndexed(GPU_CmdEncoder* encoder, PrimitiveTopology topology, + u64 index_count); +// convenience versions of the above +PUB void GPU_EncodeDrawTris(GPU_CmdEncoder* encoder, u64 count); +PUB void GPU_EncodeDrawIndexedTris(GPU_CmdEncoder* encoder, u64 index_count); +PUB void GPU_EncodeDrawInstanced(GPU_CmdEncoder* encoder, u64 index_count, + u64 instance_count); // TODO: implement instanced rendering + +// --- Frame cycle +PUB bool GPU_Backend_BeginFrame(); +PUB void GPU_Backend_EndFrame(); + +// Concrete implementation +#if defined(CEL_REND_BACKEND_OPENGL) +#include "backend_opengl.h" +#elif defined(CEL_REND_BACKEND_VULKAN) +#include "backend_vulkan.h" +#endif diff --git a/src/archive/src/ral/ral_types.h b/src/archive/src/ral/ral_types.h new file mode 100644 index 0000000..fde3bed --- /dev/null +++ b/src/archive/src/ral/ral_types.h @@ -0,0 +1,168 @@ +#pragma once +#include "darray.h" +#include "defines.h" +#include "maths_types.h" +#include "str.h" + +// --- Max size constants +#define MAX_SHADER_DATA_LAYOUTS 8 +#define MAX_SHADER_BINDINGS 8 +#define MAX_BUFFERS 256 +#define MAX_TEXTURES 256 +#define MAX_PIPELINES 128 +#define MAX_RENDERPASSES 128 +#define MAX_VERTEX_ATTRIBUTES 16 + +// --- Handle types +CORE_DEFINE_HANDLE(BufferHandle); +CORE_DEFINE_HANDLE(TextureHandle); +CORE_DEFINE_HANDLE(SamplerHandle); +CORE_DEFINE_HANDLE(ShaderHandle); +CORE_DEFINE_HANDLE(PipelineLayoutHandle); +CORE_DEFINE_HANDLE(PipelineHandle); +CORE_DEFINE_HANDLE(RenderpassHandle); +#define INVALID_TEX_HANDLE ((TextureHandle){ .raw = 9999981 }) + +// --- Buffers +typedef enum GPU_BufferType { + BUFFER_DEFAULT, // on Vulkan this would be a storage buffer? + BUFFER_VERTEX, + BUFFER_INDEX, + BUFFER_UNIFORM, + BUFFER_COUNT +} GPU_BufferType; + +static const char* buffer_type_names[] = { + "RAL Buffer Default", "RAL Buffer Vertex", "RAL Buffer Index", + "RAL Buffer Uniform", "RAL Buffer Count", +}; + +typedef enum GPU_BufferFlag { + BUFFER_FLAG_CPU = 1 << 0, + BUFFER_FLAG_GPU = 1 << 1, + BUFFER_FLAG_STORAGE = 1 << 2, + BUFFER_FLAG_COUNT +} GPU_BufferFlag; +typedef u32 GPU_BufferFlags; + +static const char* texture_type_names[] = { + "RAL Texture 2D", "RAL Texture 3D", "RAL Texture 2D Array", + "RAL Texture Cubemap", "RAL Texture Count", +}; + +typedef enum GPU_TextureFormat { + TEXTURE_FORMAT_8_8_8_8_RGBA_UNORM, + TEXTURE_FORMAT_8_8_8_RGB_UNORM, + TEXTURE_FORMAT_DEPTH_DEFAULT, + TEXTURE_FORMAT_COUNT +} GPU_TextureFormat; + +// --- Vertices + +typedef enum VertexFormat { + VERTEX_STATIC_3D, + VERTEX_SPRITE, + VERTEX_SKINNED, + VERTEX_COLOURED_STATIC_3D, + VERTEX_RAW_POS_COLOUR, + VERTEX_POS_ONLY, + VERTEX_COUNT +} VertexFormat; + +#ifndef TYPED_VERTEX_ARRAY +KITC_DECL_TYPED_ARRAY(Vertex); +KITC_DECL_TYPED_ARRAY(u32) +#define TYPED_VERTEX_ARRAY +#endif + +/// @strip_prefix(ATTR_) +typedef enum VertexAttribType { + ATTR_F32, + ATTR_F32x2, + ATTR_F32x3, + ATTR_F32x4, + ATTR_U32, + ATTR_U32x2, + ATTR_U32x3, + ATTR_U32x4, + ATTR_I32, + ATTR_I32x2, + ATTR_I32x3, + ATTR_I32x4, +} VertexAttribType; + +typedef struct VertexDescription { + const char* debug_label; + const char* attr_names[MAX_VERTEX_ATTRIBUTES]; + VertexAttribType attributes[MAX_VERTEX_ATTRIBUTES]; + u32 attributes_count; + // size_t stride; + bool use_full_vertex_size; +} VertexDescription; + +// --- Shaders +typedef enum PipelineKind { + PIPELINE_GRAPHICS, + PIPELINE_COMPUTE, +} PipelineKind; + +typedef struct ShaderDesc { + const char* debug_name; + Str8 filepath; // Where it came from + Str8 code; // Either GLSL or SPIRV bytecode + bool is_spirv; + bool is_combined_vert_frag; // Contains both vertex and fragment stages +} ShaderDesc; + +typedef ShaderDataLayout (*FN_GetBindingLayout)(void* data); + +/** @brief takes a `ShaderDataLayout` without data, and puts the correct data into each binding */ +typedef void (*FN_BindShaderData)(ShaderDataLayout* layout, const void* data); + +// typedef struct ShaderData { +// FN_GetBindingLayout get_layout; +// void* data; +// } ShaderData; + +typedef enum PrimitiveTopology { +#ifdef TOPOLOGY_SHORT_NAMES + CEL_POINT, + CEL_LINE, + CEL_LINE_STRIP, + CEL_TRI, + CEL_TRI_STRIP, + PRIMITIVE_TOPOLOGY_COUNT +#else + PRIMITIVE_TOPOLOGY_POINT, + PRIMITIVE_TOPOLOGY_LINE, + PRIMITIVE_TOPOLOGY_LINE_STRIP, + PRIMITIVE_TOPOLOGY_TRIANGLE, + PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, + PRIMITIVE_TOPOLOGY_COUNT +#endif +} PrimitiveTopology; + +typedef enum Winding { WINDING_CCW, WINDING_CW } Winding; + +// based on https://registry.khronos.org/OpenGL-Refpages/gl4/html/glDepthFunc.xhtml +typedef enum CompareFunc { + COMPARE_NEVER, + COMPARE_LESS, + COMPARE_EQUAL, + COMPARE_LESS_EQUAL, + COMPARE_GREATER, + COMPARE_NOT_EQUAL, + COMPARE_GREATER_EQUAL, + COMPARE_ALWAYS, + COMPARE_COUNT +} CompareFunc; + +bool GraphicsPipelineDesc_AddShaderDataLayout(GraphicsPipelineDesc* desc, ShaderDataLayout layout); + +typedef struct GPU_RenderpassDesc { + bool default_framebuffer; + bool has_color_target; + TextureHandle color_target; // for now only support one + bool has_depth_stencil; + TextureHandle depth_stencil; +} GPU_RenderpassDesc; diff --git a/src/archive/src/render/archive/backends/backend_test.c b/src/archive/src/render/archive/backends/backend_test.c new file mode 100644 index 0000000..6347e27 --- /dev/null +++ b/src/archive/src/render/archive/backends/backend_test.c @@ -0,0 +1 @@ +// #FUTURE \ No newline at end of file diff --git a/src/archive/src/render/archive/backends/metal/README.md b/src/archive/src/render/archive/backends/metal/README.md new file mode 100644 index 0000000..f87f5c1 --- /dev/null +++ b/src/archive/src/render/archive/backends/metal/README.md @@ -0,0 +1 @@ +# TODO \ No newline at end of file diff --git a/src/archive/src/render/archive/backends/metal/backend_metal.h b/src/archive/src/render/archive/backends/metal/backend_metal.h new file mode 100644 index 0000000..9561bb6 --- /dev/null +++ b/src/archive/src/render/archive/backends/metal/backend_metal.h @@ -0,0 +1,74 @@ +#pragma once +// #define CEL_REND_BACKEND_METAL +#if defined(CEL_REND_BACKEND_METAL) + +#include "defines.h" +#include "maths_types.h" +#ifdef __OBJC__ +#import +#import +#import +#import +#else +typedef void* id; +#endif + +typedef struct gpu_swapchain { + u32x2 dimensions; +#ifdef __OBJC__ + CAMetalLayer* swapchain; +#else + void* swapchain; +#endif +} gpu_swapchain; +typedef struct gpu_device { +/** @brief `device` gives us access to our GPU */ +#ifdef __OBJC__ + id id; +#else + void* id; +#endif +} gpu_device; +typedef struct gpu_pipeline_layout { + void* pad; +} gpu_pipeline_layout; +typedef struct gpu_pipeline { +#ifdef __OBJC__ + id pipeline_state; +#else + void* pipeline_state; +#endif +} gpu_pipeline; +typedef struct gpu_renderpass { +#ifdef __OBJC__ + MTLRenderPassDescriptor* rpass_descriptor; +#else + void* rpass_descriptor; +#endif +} gpu_renderpass; +typedef struct gpu_cmd_encoder { +#ifdef __OBJC__ + id cmd_buffer; + id render_encoder; +#else + void* cmd_buffer; + void* render_encoder; +#endif +} gpu_cmd_encoder; +typedef struct gpu_cmd_buffer { + void* pad; +} gpu_cmd_buffer; + +typedef struct gpu_buffer { +#ifdef __OBJC__ + id id; +#else + void* id; +#endif + u64 size; +} gpu_buffer; +typedef struct gpu_texture { + void* pad; +} gpu_texture; + +#endif \ No newline at end of file diff --git a/src/archive/src/render/archive/backends/metal/backend_metal.m b/src/archive/src/render/archive/backends/metal/backend_metal.m new file mode 100644 index 0000000..0e9399e --- /dev/null +++ b/src/archive/src/render/archive/backends/metal/backend_metal.m @@ -0,0 +1,285 @@ +#include +#define CEL_REND_BACKEND_METAL +#if defined(CEL_REND_BACKEND_METAL) +#include +#include "ral_types.h" +#include "colours.h" +#include +#include "camera.h" +#include "defines.h" +#include "file.h" +#include "log.h" +#include "maths_types.h" +#include "ral.h" + +#define GLFW_INCLUDE_NONE +#define GLFW_EXPOSE_NATIVE_COCOA + +#include +#include + +#import +#import +#import +#import +#include "backend_metal.h" + +// --- Handy macros +#define BUFFER_GET(h) (buffer_pool_get(&context.resource_pools->buffers, h)) +#define TEXTURE_GET(h) (texture_pool_get(&context.resource_pools->textures, h)) + +typedef struct metal_context { + GLFWwindow* window; + NSWindow* metal_window; + arena pool_arena; + + gpu_device* device; + gpu_swapchain* swapchain; + id surface; + + id command_queue; + gpu_cmd_encoder main_command_buf; + gpu_backend_pools gpu_pools; + struct resource_pools* resource_pools; +} metal_context; + +static metal_context context; + +struct GLFWwindow; + +bool gpu_backend_init(const char *window_name, struct GLFWwindow *window) { + INFO("loading Metal backend"); + + memset(&context, 0, sizeof(metal_context)); + context.window = window; + + size_t pool_buffer_size = 1024 * 1024; + context.pool_arena = arena_create(malloc(pool_buffer_size), pool_buffer_size); + + backend_pools_init(&context.pool_arena, &context.gpu_pools); + context.resource_pools = malloc(sizeof(struct resource_pools)); + resource_pools_init(&context.pool_arena, context.resource_pools); + + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + + glfwMakeContextCurrent(window); + // FIXME: glfwSetFramebufferSizeCallback(ren->window, framebuffer_size_callback); + + // get a NSWindow pointer from GLFWwindow + NSWindow *nswindow = glfwGetCocoaWindow(window); + context.metal_window = nswindow; + + // const id queue = [gpu newCommandQueue]; + // CAMetalLayer *swapchain = [CAMetalLayer layer]; + // swapchain.device = gpu; + // swapchain.opaque = YES; + + // // set swapchain for the window + // nswindow.contentView.layer = swapchain; + // nswindow.contentView.wantsLayer = YES; + + // MTLClearColor color = MTLClearColorMake(0.7, 0.1, 0.2, 1.0); + + // // set all our state properties + // state->device = gpu; + // state->cmd_queue = queue; + // state->swapchain = swapchain; + // state->clear_color = color; + + // NSError *err = 0x0; // TEMPORARY + + // WARN("About to try loading metallib"); + // id defaultLibrary = [state->device newLibraryWithFile: @"build/gfx.metallib" error:&err]; + // CASSERT(defaultLibrary); + // state->default_lib = defaultLibrary; + // if (!state->default_lib) { + // NSLog(@"Failed to load library"); + // exit(0); + // } + + // create_render_pipeline(state); + + return true; +} + +void gpu_backend_shutdown() {} + +bool gpu_device_create(gpu_device* out_device) { + TRACE("GPU Device creation"); + const id gpu = MTLCreateSystemDefaultDevice(); + out_device->id = gpu; + context.device = out_device; + + const id queue = [gpu newCommandQueue]; + context.command_queue = queue; + + return true; +} +void gpu_device_destroy() {} + +// --- Render Pipeline +gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc description) { + TRACE("GPU Graphics Pipeline creation"); + // Allocate + // gpu_pipeline_layout* layout = + // pipeline_layout_pool_alloc(&context.gpu_pools.pipeline_layouts, NULL); + gpu_pipeline* pipeline = pipeline_pool_alloc(&context.gpu_pools.pipelines, NULL); + + WARN("About to try loading metallib"); + assert(description.vs.is_combined_vert_frag); + // Ignore fragment shader data, as vert shader data contains both + NSError *err = 0x0; // TEMPORARY + NSString *myNSString = [NSString stringWithUTF8String:(char*)description.vs.filepath.buf]; + id default_library = [context.device->id newLibraryWithFile:myNSString error:&err]; + assert(default_library); + + // setup vertex and fragment shaders + id ren_vert = [default_library newFunctionWithName:@"basic_vertex"]; + assert(ren_vert); + id ren_frag = [default_library newFunctionWithName:@"basic_fragment"]; + assert(ren_frag); + + // create pipeline descriptor + @autoreleasepool { + NSError *err = 0x0; + MTLRenderPipelineDescriptor *pld = [[MTLRenderPipelineDescriptor alloc] init]; + NSString *pipeline_name = [NSString stringWithUTF8String: description.debug_name]; + pld.label = pipeline_name; + pld.vertexFunction = ren_vert; + pld.fragmentFunction = ren_frag; + pld.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm; + pld.colorAttachments[0].blendingEnabled = YES; + + MTLDepthStencilDescriptor *depthStencilDescriptor = [MTLDepthStencilDescriptor new]; + depthStencilDescriptor.depthCompareFunction = MTLCompareFunctionLess; + depthStencilDescriptor.depthWriteEnabled = YES; + pld.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8; + + id depth_descriptor = [context.device->id newDepthStencilStateWithDescriptor:depthStencilDescriptor]; + // FIXME: state->depth_state = depth_descriptor; + + id pipeline_state = [context.device->id newRenderPipelineStateWithDescriptor:pld error:&err]; + TRACE("created renderpipelinestate"); + pipeline->pipeline_state = pipeline_state; + + } + + return pipeline; +} +void gpu_pipeline_destroy(gpu_pipeline* pipeline) {} + +// --- Renderpass +gpu_renderpass* gpu_renderpass_create(const gpu_renderpass_desc* description) { + gpu_renderpass* renderpass = renderpass_pool_alloc(&context.gpu_pools.renderpasses, NULL); + + // TODO: Configure based on description + // set up render pass + context.surface = [context.swapchain->swapchain nextDrawable]; + MTLRenderPassDescriptor *renderPassDescriptor = [[MTLRenderPassDescriptor alloc] init]; + MTLRenderPassColorAttachmentDescriptor *cd = renderPassDescriptor.colorAttachments[0]; + [cd setTexture:context.surface.texture]; + [cd setLoadAction:MTLLoadActionClear]; + MTLClearColor clearColor = MTLClearColorMake(0.1, 0.1, 0.0, 1.0); + [cd setClearColor:clearColor]; + [cd setStoreAction:MTLStoreActionStore]; + + renderpass->rpass_descriptor = renderPassDescriptor; + + return renderpass; +} + +void gpu_renderpass_destroy(gpu_renderpass* pass) {} + +// --- Swapchain +bool gpu_swapchain_create(gpu_swapchain* out_swapchain) { + TRACE("GPU Swapchain creation"); + CAMetalLayer *swapchain = [CAMetalLayer layer]; + swapchain.device = context.device->id; + swapchain.opaque = YES; + out_swapchain->swapchain = swapchain; + + // set swapchain for the window + context.metal_window.contentView.layer = swapchain; + context.metal_window.contentView.wantsLayer = YES; + + context.swapchain = out_swapchain; + return true; +} +void gpu_swapchain_destroy(gpu_swapchain* swapchain) {} + +// --- Command buffer +gpu_cmd_encoder gpu_cmd_encoder_create() { + id cmd_buffer = [context.command_queue commandBuffer]; + + return (gpu_cmd_encoder) { + .cmd_buffer = cmd_buffer + }; +} +void gpu_cmd_encoder_destroy(gpu_cmd_encoder* encoder) {} +void gpu_cmd_encoder_begin(gpu_cmd_encoder encoder) { /* no-op */ } +void gpu_cmd_encoder_begin_render(gpu_cmd_encoder* encoder, gpu_renderpass* renderpass) { + DEBUG("Create Render Command Encoder"); + id render_encoder = [encoder->cmd_buffer renderCommandEncoderWithDescriptor:renderpass->rpass_descriptor]; + encoder->render_encoder = render_encoder; + // [encoder setDepthStencilState:state->depth_state]; +} +void gpu_cmd_encoder_end_render(gpu_cmd_encoder* encoder) {} +void gpu_cmd_encoder_begin_compute() {} +gpu_cmd_encoder* gpu_get_default_cmd_encoder() { + return &context.main_command_buf; +} + +/** @brief Finish recording and return a command buffer that can be submitted to a queue */ +gpu_cmd_buffer gpu_cmd_encoder_finish(gpu_cmd_encoder* encoder) {} + +void gpu_queue_submit(gpu_cmd_buffer* buffer) {} + +void encode_buffer_copy(gpu_cmd_encoder* encoder, buffer_handle src, u64 src_offset, + buffer_handle dst, u64 dst_offset, u64 copy_size); +void buffer_upload_bytes(buffer_handle gpu_buf, bytebuffer cpu_buf, u64 offset, u64 size); + +void copy_buffer_to_buffer_oneshot(buffer_handle src, u64 src_offset, buffer_handle dst, + u64 dst_offset, u64 copy_size); +void copy_buffer_to_image_oneshot(buffer_handle src, texture_handle dst); + +void encode_bind_pipeline(gpu_cmd_encoder* encoder, pipeline_kind kind, gpu_pipeline* pipeline) {} +void encode_bind_shader_data(gpu_cmd_encoder* encoder, u32 group, shader_data* data) {} +void encode_set_default_settings(gpu_cmd_encoder* encoder) { + [encoder->render_encoder setCullMode:MTLCullModeBack]; +} +void encode_set_vertex_buffer(gpu_cmd_encoder* encoder, buffer_handle buf) { + gpu_buffer* vertex_buf = BUFFER_GET(buf); + [encoder->render_encoder setVertexBuffer:vertex_buf->id offset:0 atIndex:0]; +} +void encode_set_index_buffer(gpu_cmd_encoder* encoder, buffer_handle buf) {} +void encode_set_bind_group() {} +void encode_draw(gpu_cmd_encoder* encoder) {} +void encode_draw_indexed(gpu_cmd_encoder* encoder, u64 index_count) {} +void encode_clear_buffer(gpu_cmd_encoder* encoder, buffer_handle buf) {} + +buffer_handle gpu_buffer_create(u64 size, gpu_buffer_type buf_type, gpu_buffer_flags flags, + const void* data) { + buffer_handle handle; + gpu_buffer* buffer = buffer_pool_alloc(&context.resource_pools->buffers, &handle); + buffer->size = size; + + id mtl_vert_buf = [context.device->id newBufferWithBytes:data + length: size + options:MTLResourceStorageModeShared]; + return handle; +} +void gpu_buffer_destroy(buffer_handle buffer) {} +void gpu_buffer_upload(const void* data) {} + +texture_handle gpu_texture_create(texture_desc desc, bool create_view, const void* data) {} +void gpu_texture_destroy(texture_handle) {} +void gpu_texture_upload(texture_handle texture, const void* data) {} + +bool gpu_backend_begin_frame() { + context.main_command_buf.cmd_buffer = [context.command_queue commandBuffer]; + return true; + } +void gpu_backend_end_frame() {} +void gpu_temp_draw(size_t n_verts) {} + +#endif \ No newline at end of file diff --git a/src/archive/src/render/archive/backends/opengl/backend_opengl.c b/src/archive/src/render/archive/backends/opengl/backend_opengl.c new file mode 100644 index 0000000..43105e2 --- /dev/null +++ b/src/archive/src/render/archive/backends/opengl/backend_opengl.c @@ -0,0 +1,521 @@ +#include +#include +#include +#include "colours.h" +#include "maths.h" +#include "opengl_helpers.h" +#include "ral_types.h" +#define CEL_REND_BACKEND_OPENGL +#if defined(CEL_REND_BACKEND_OPENGL) +#include +#include + +#include "backend_opengl.h" +#include "defines.h" +#include "file.h" +#include "log.h" +#include "maths_types.h" +#include "ral.h" + +#include +#include + +typedef struct opengl_context { + GLFWwindow* window; + arena pool_arena; + gpu_cmd_encoder command_buffer; + gpu_backend_pools gpu_pools; + struct resource_pools* resource_pools; +} opengl_context; + +static opengl_context context; + +struct GLFWwindow; + +bool gpu_backend_init(const char* window_name, struct GLFWwindow* window) { + INFO("loading OpenGL backend"); + + memset(&context, 0, sizeof(opengl_context)); + context.window = window; + + size_t pool_buffer_size = 1024 * 1024; + context.pool_arena = arena_create(malloc(pool_buffer_size), pool_buffer_size); + + backend_pools_init(&context.pool_arena, &context.gpu_pools); + context.resource_pools = malloc(sizeof(struct resource_pools)); + resource_pools_init(&context.pool_arena, context.resource_pools); + + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + + // glad: load all opengl function pointers + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { + ERROR("Failed to initialise GLAD \n"); + return false; + } + + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + + return true; +} + +// --- Render Pipeline +gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc description) { + gpu_pipeline* pipeline = pipeline_pool_alloc(&context.gpu_pools.pipelines, NULL); + + // Create shader program + u32 shader_id = shader_create_separate(description.vs.filepath.buf, description.fs.filepath.buf); + pipeline->shader_id = shader_id; + + // Vertex format + pipeline->vertex_desc = description.vertex_desc; + + // Allocate uniform buffers if needed + u32 ubo_count = 0; + // printf("data layouts %d\n", description.data_layouts_count); + for (u32 layout_i = 0; layout_i < description.data_layouts_count; layout_i++) { + shader_data_layout sdl = description.data_layouts[layout_i].shader_data_get_layout(NULL); + TRACE("Got shader data layout %d's bindings! . found %d", layout_i, sdl.bindings_count); + + for (u32 binding_j = 0; binding_j < sdl.bindings_count; binding_j++) { + u32 binding_id = binding_j; + assert(binding_id < MAX_PIPELINE_UNIFORM_BUFFERS); + shader_binding binding = sdl.bindings[binding_j]; + if (binding.type == SHADER_BINDING_BYTES) { + static u32 s_binding_point = 0; + buffer_handle ubo_handle = + gpu_buffer_create(binding.data.bytes.size, CEL_BUFFER_UNIFORM, CEL_BUFFER_FLAG_GPU, + NULL); // no data right now + pipeline->uniform_bindings[ubo_count++] = ubo_handle; + gpu_buffer* ubo_buf = BUFFER_GET(ubo_handle); + + i32 blockIndex = glGetUniformBlockIndex(pipeline->shader_id, binding.label); + printf("Block index for %s: %d", binding.label, blockIndex); + if (blockIndex < 0) { + WARN("Couldn't retrieve block index for uniform block '%s'", binding.label); + } else { + // DEBUG("Retrived block index %d for %s", blockIndex, binding.label); + } + u32 blocksize; + glGetActiveUniformBlockiv(pipeline->shader_id, blockIndex, GL_UNIFORM_BLOCK_DATA_SIZE, + &blocksize); + printf("\t with size %d bytes\n", blocksize); + + glBindBufferBase(GL_UNIFORM_BUFFER, s_binding_point, ubo_buf->id.ubo); + if (blockIndex != GL_INVALID_INDEX) { + glUniformBlockBinding(pipeline->shader_id, blockIndex, s_binding_point); + } + ubo_buf->ubo_binding_point = s_binding_point++; + ubo_buf->name = binding.label; + assert(s_binding_point < GL_MAX_UNIFORM_BUFFER_BINDINGS); + } + } + } + pipeline->uniform_count = ubo_count; + + pipeline->renderpass = description.renderpass; + pipeline->wireframe = description.wireframe; + + return pipeline; +} +void gpu_pipeline_destroy(gpu_pipeline* pipeline) {} + +// --- Renderpass +gpu_renderpass* gpu_renderpass_create(const gpu_renderpass_desc* description) { + gpu_renderpass* renderpass = renderpass_pool_alloc(&context.gpu_pools.renderpasses, NULL); + memcpy(&renderpass->description, description, sizeof(gpu_renderpass_desc)); + bool default_framebuffer = description->default_framebuffer; + + if (!default_framebuffer) { + GLuint gl_fbo_id; + glGenFramebuffers(1, &gl_fbo_id); + renderpass->fbo = gl_fbo_id; + } else { + renderpass->fbo = OPENGL_DEFAULT_FRAMEBUFFER; + assert(!description->has_color_target); + assert(!description->has_depth_stencil); + } + glBindFramebuffer(GL_FRAMEBUFFER, renderpass->fbo); + + if (description->has_color_target && !default_framebuffer) { + gpu_texture* colour_attachment = TEXTURE_GET(description->color_target); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + colour_attachment->id, 0); + } + if (description->has_depth_stencil && !default_framebuffer) { + gpu_texture* depth_attachment = TEXTURE_GET(description->depth_stencil); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_attachment->id, + 0); + } + + if (description->has_depth_stencil && !description->has_color_target) { + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + } + + glBindFramebuffer(GL_FRAMEBUFFER, 0); // reset to default framebuffer + + return renderpass; +} +void gpu_renderpass_destroy(gpu_renderpass* pass) { glDeleteFramebuffers(1, &pass->fbo); } + +// --- Command buffer +gpu_cmd_encoder gpu_cmd_encoder_create() { + gpu_cmd_encoder encoder = { 0 }; + return encoder; +} +void gpu_cmd_encoder_destroy(gpu_cmd_encoder* encoder) {} +void gpu_cmd_encoder_begin(gpu_cmd_encoder encoder) {} +void gpu_cmd_encoder_begin_render(gpu_cmd_encoder* encoder, gpu_renderpass* renderpass) { + glBindFramebuffer(GL_FRAMEBUFFER, renderpass->fbo); + rgba clear_colour = STONE_800; + glClearColor(clear_colour.r, clear_colour.g, clear_colour.b, 1.0f); + if (renderpass->description.has_depth_stencil) { + glClear(GL_DEPTH_BUFFER_BIT); + } else { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } +} +void gpu_cmd_encoder_end_render(gpu_cmd_encoder* encoder) { glBindFramebuffer(GL_FRAMEBUFFER, 0); } +void gpu_cmd_encoder_begin_compute() {} +gpu_cmd_encoder* gpu_get_default_cmd_encoder() { return &context.command_buffer; } + +/** @brief Finish recording and return a command buffer that can be submitted to a queue */ +gpu_cmd_buffer gpu_cmd_encoder_finish(gpu_cmd_encoder* encoder) {} + +void gpu_queue_submit(gpu_cmd_buffer* buffer) {} + +// --- Data copy commands +/** @brief Copy data from one buffer to another */ +void encode_buffer_copy(gpu_cmd_encoder* encoder, buffer_handle src, u64 src_offset, + buffer_handle dst, u64 dst_offset, u64 copy_size) {} +/** @brief Upload CPU-side data as array of bytes to a GPU buffer */ +void buffer_upload_bytes(buffer_handle gpu_buf, bytebuffer cpu_buf, u64 offset, u64 size) { + // TODO: finish implementing this + gpu_buffer* buf = BUFFER_GET(gpu_buf); +} + +/** @brief Copy data from buffer to buffer using a one time submit command buffer and a wait */ +void copy_buffer_to_buffer_oneshot(buffer_handle src, u64 src_offset, buffer_handle dst, + u64 dst_offset, u64 copy_size) {} +/** @brief Copy data from buffer to an image using a one time submit command buffer */ +void copy_buffer_to_image_oneshot(buffer_handle src, texture_handle dst) {} + +// --- Render commands +void encode_bind_pipeline(gpu_cmd_encoder* encoder, pipeline_kind kind, gpu_pipeline* pipeline) { + encoder->pipeline = pipeline; + + if (pipeline->wireframe) { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + } else { + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + + // In OpenGL binding a pipeline is more or less equivalent to just setting the shader + glUseProgram(pipeline->shader_id); +} +void encode_bind_shader_data(gpu_cmd_encoder* encoder, u32 group, shader_data* data) { + shader_data_layout sdl = data->shader_data_get_layout(data->data); + // printf("Binding %s shader data\n", sdl.name); + + for (u32 i = 0; i < sdl.bindings_count; i++) { + shader_binding binding = sdl.bindings[i]; + /* print_shader_binding(binding); */ + + if (binding.type == SHADER_BINDING_BYTES) { + buffer_handle b; + gpu_buffer* ubo_buf; + bool found = false; + for (u32 i = 0; i < encoder->pipeline->uniform_count; i++) { + b = encoder->pipeline->uniform_bindings[i]; + ubo_buf = BUFFER_GET(b); + assert(ubo_buf->name != NULL); + if (strcmp(ubo_buf->name, binding.label) == 0) { + found = true; + break; + } + } + if (!found) { + ERROR("Couldnt find uniform buffer object!!"); + } + + i32 blockIndex = glGetUniformBlockIndex(encoder->pipeline->shader_id, binding.label); + if (blockIndex < 0) { + WARN("Couldn't retrieve block index for uniform block '%s'", binding.label); + } else { + // DEBUG("Retrived block index %d for %s", blockIndex, binding.label); + } + + glBindBuffer(GL_UNIFORM_BUFFER, ubo_buf->id.ubo); + glBufferSubData(GL_UNIFORM_BUFFER, 0, ubo_buf->size, binding.data.bytes.data); + + } else if (binding.type == SHADER_BINDING_TEXTURE) { + gpu_texture* tex = TEXTURE_GET(binding.data.texture.handle); + GLint tex_slot = glGetUniformLocation(encoder->pipeline->shader_id, binding.label); + // printf("%d slot \n", tex_slot); + if (tex_slot == GL_INVALID_VALUE || tex_slot < 0) { + WARN("Invalid binding label for texture %s - couldn't fetch texture slot uniform", + binding.label); + } + glUniform1i(tex_slot, i); + glActiveTexture(GL_TEXTURE0 + i); + glBindTexture(GL_TEXTURE_2D, tex->id); + } + } +} +void encode_set_default_settings(gpu_cmd_encoder* encoder) {} +void encode_set_vertex_buffer(gpu_cmd_encoder* encoder, buffer_handle buf) { + gpu_buffer* buffer = BUFFER_GET(buf); + if (buffer->vao == 0) { // if no VAO for this vertex buffer, create it + INFO("Setting up VAO"); + buffer->vao = opengl_bindcreate_vao(buffer, encoder->pipeline->vertex_desc); + } + glBindVertexArray(buffer->vao); +} +void encode_set_index_buffer(gpu_cmd_encoder* encoder, buffer_handle buf) { + gpu_buffer* buffer = BUFFER_GET(buf); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer->id.ibo); +} +void encode_draw(gpu_cmd_encoder* encoder, u64 count) { glDrawArrays(GL_TRIANGLES, 0, count); } +void encode_draw_indexed(gpu_cmd_encoder* encoder, u64 index_count) { + /* printf("Draw %ld indices\n", index_count); */ + glDrawElements(GL_TRIANGLES, index_count, GL_UNSIGNED_INT, 0); +} +void encode_clear_buffer(gpu_cmd_encoder* encoder, buffer_handle buf) {} + +// --- Buffers +buffer_handle gpu_buffer_create(u64 size, gpu_buffer_type buf_type, gpu_buffer_flags flags, + const void* data) { + // "allocating" the cpu-side buffer struct + buffer_handle handle; + gpu_buffer* buffer = buffer_pool_alloc(&context.resource_pools->buffers, &handle); + buffer->size = size; + buffer->vao = 0; // When we create a new buffer, there will be no VAO. + + // Opengl buffer + GLuint gl_buffer_id; + glGenBuffers(1, &gl_buffer_id); + + GLenum gl_buf_type; + GLenum gl_buf_usage = GL_STATIC_DRAW; + + switch (buf_type) { + case CEL_BUFFER_UNIFORM: + DEBUG("Creating Uniform buffer"); + gl_buf_type = GL_UNIFORM_BUFFER; + /* gl_buf_usage = GL_DYNAMIC_DRAW; */ + buffer->id.ubo = gl_buffer_id; + break; + case CEL_BUFFER_DEFAULT: + case CEL_BUFFER_VERTEX: + DEBUG("Creating Vertex buffer"); + gl_buf_type = GL_ARRAY_BUFFER; + buffer->id.vbo = gl_buffer_id; + break; + case CEL_BUFFER_INDEX: + DEBUG("Creating Index buffer"); + gl_buf_type = GL_ELEMENT_ARRAY_BUFFER; + buffer->id.ibo = gl_buffer_id; + break; + default: + WARN("Unimplemented gpu_buffer_type provided %s", buffer_type_names[buf_type]); + break; + } + // bind buffer + glBindBuffer(gl_buf_type, gl_buffer_id); + + if (data) { + TRACE("Upload data (%d bytes) as part of buffer creation", size); + glBufferData(gl_buf_type, buffer->size, data, gl_buf_usage); + } else { + TRACE("Allocating but not uploading (%d bytes)", size); + glBufferData(gl_buf_type, buffer->size, NULL, gl_buf_usage); + } + + glBindBuffer(gl_buf_type, 0); + + return handle; +} + +texture_handle gpu_texture_create(texture_desc desc, bool create_view, const void* data) { + // "allocating" the cpu-side struct + texture_handle handle; + gpu_texture* texture = texture_pool_alloc(&context.resource_pools->textures, &handle); + DEBUG("Allocated texture with handle %d", handle.raw); + + GLuint gl_texture_id; + glGenTextures(1, &gl_texture_id); + texture->id = gl_texture_id; + + glBindTexture(GL_TEXTURE_2D, gl_texture_id); + + GLint internal_format = + desc.format == CEL_TEXTURE_FORMAT_DEPTH_DEFAULT ? GL_DEPTH_COMPONENT : GL_RGB; + GLenum format = desc.format == CEL_TEXTURE_FORMAT_DEPTH_DEFAULT ? GL_DEPTH_COMPONENT : GL_RGBA; + GLenum data_type = desc.format == CEL_TEXTURE_FORMAT_DEPTH_DEFAULT ? GL_FLOAT : GL_UNSIGNED_BYTE; + + if (desc.format == CEL_TEXTURE_FORMAT_DEPTH_DEFAULT) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + } else { + // set the texture wrapping parameters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, + GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + // set texture filtering parameters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + + if (data) { + glTexImage2D(GL_TEXTURE_2D, 0, internal_format, desc.extents.x, desc.extents.y, 0, format, + data_type, data); + glGenerateMipmap(GL_TEXTURE_2D); + } else { + WARN("No image data provided"); + glTexImage2D(GL_TEXTURE_2D, 0, internal_format, desc.extents.x, desc.extents.y, 0, format, + data_type, NULL); + } + + glBindTexture(GL_TEXTURE_2D, 0); + + return handle; +} + +void gpu_texture_destroy(texture_handle) {} +void gpu_texture_upload(texture_handle texture, const void* data) {} + +// --- Vertex formats +bytebuffer vertices_as_bytebuffer(arena* a, vertex_format format, vertex_darray* vertices) {} + +// --- TEMP +bool gpu_backend_begin_frame() { + glClearColor(0.1f, 0.1f, 0.1f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + return true; +} +void gpu_backend_end_frame() { + // TODO: Reset all bindings + glfwSwapBuffers(context.window); +} +void gpu_temp_draw(size_t n_verts) {} + +u32 shader_create_separate(const char* vert_shader, const char* frag_shader) { + INFO("Load shaders at %s and %s", vert_shader, frag_shader); + int success; + char info_log[512]; + + u32 vertex = glCreateShader(GL_VERTEX_SHADER); + const char* vertex_shader_src = string_from_file(vert_shader); + if (vertex_shader_src == NULL) { + ERROR("EXIT: couldnt load shader"); + exit(-1); + } + glShaderSource(vertex, 1, &vertex_shader_src, NULL); + glCompileShader(vertex); + glGetShaderiv(vertex, GL_COMPILE_STATUS, &success); + if (!success) { + glGetShaderInfoLog(vertex, 512, NULL, info_log); + printf("%s\n", info_log); + ERROR("EXIT: vertex shader compilation failed"); + exit(-1); + } + + // fragment shader + u32 fragment = glCreateShader(GL_FRAGMENT_SHADER); + const char* fragment_shader_src = string_from_file(frag_shader); + if (fragment_shader_src == NULL) { + ERROR("EXIT: couldnt load shader"); + exit(-1); + } + glShaderSource(fragment, 1, &fragment_shader_src, NULL); + glCompileShader(fragment); + glGetShaderiv(fragment, GL_COMPILE_STATUS, &success); + if (!success) { + glGetShaderInfoLog(fragment, 512, NULL, info_log); + printf("%s\n", info_log); + ERROR("EXIT: fragment shader compilation failed"); + exit(-1); + } + + u32 shader_prog; + shader_prog = glCreateProgram(); + + glAttachShader(shader_prog, vertex); + glAttachShader(shader_prog, fragment); + glLinkProgram(shader_prog); + glDeleteShader(vertex); + glDeleteShader(fragment); + free((char*)vertex_shader_src); + free((char*)fragment_shader_src); + + return shader_prog; +} + +inline void uniform_vec3f(u32 program_id, const char* uniform_name, vec3* value) { + glUniform3fv(glGetUniformLocation(program_id, uniform_name), 1, &value->x); +} +inline void uniform_f32(u32 program_id, const char* uniform_name, f32 value) { + glUniform1f(glGetUniformLocation(program_id, uniform_name), value); +} +inline void uniform_i32(u32 program_id, const char* uniform_name, i32 value) { + glUniform1i(glGetUniformLocation(program_id, uniform_name), value); +} +inline void uniform_mat4f(u32 program_id, const char* uniform_name, mat4* value) { + glUniformMatrix4fv(glGetUniformLocation(program_id, uniform_name), 1, GL_FALSE, value->data); +} + +// void clear_screen(vec3 colour) { +// glClearColor(colour.x, colour.y, colour.z, 1.0f); +// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +// } + +// void texture_data_upload(texture *tex) { +// printf("Texture name %s\n", tex->name); +// TRACE("Upload texture data"); +// u32 texture_id; +// glGenTextures(1, &texture_id); +// glBindTexture(GL_TEXTURE_2D, texture_id); +// tex->texture_id = texture_id; + +// // set the texture wrapping parameters +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, +// GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method) +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); +// // set texture filtering parameters +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + +// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex->width, tex->height, 0, tex->channel_type, +// GL_UNSIGNED_BYTE, tex->image_data); +// glGenerateMipmap(GL_TEXTURE_2D); +// DEBUG("Freeing texture image data after uploading to GPU"); +// // stbi_image_free(tex->image_data); // data is on gpu now so we dont need it around +// } + +// void bind_texture(shader s, texture *tex, u32 slot) { +// // printf("bind texture slot %d with texture id %d \n", slot, tex->texture_id); +// glActiveTexture(GL_TEXTURE0 + slot); +// glBindTexture(GL_TEXTURE_2D, tex->texture_id); +// } + +// void bind_mesh_vertex_buffer(void *_backend, mesh *mesh) { glBindVertexArray(mesh->vao); } + +// static inline GLenum to_gl_prim_topology(enum cel_primitive_topology primitive) { +// switch (primitive) { +// case CEL_PRIMITIVE_TOPOLOGY_TRIANGLE: +// return GL_TRIANGLES; +// case CEL_PRIMITIVE_TOPOLOGY_POINT: +// case CEL_PRIMITIVE_TOPOLOGY_LINE: +// case CEL_PRIMITIVE_TOPOLOGY_LINE_STRIP: +// case CEL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: +// case CEL_PRIMITIVE_TOPOLOGY_COUNT: +// break; +// } +// } +#endif diff --git a/src/archive/src/render/archive/backends/opengl/backend_opengl.h b/src/archive/src/render/archive/backends/opengl/backend_opengl.h new file mode 100644 index 0000000..14b44af --- /dev/null +++ b/src/archive/src/render/archive/backends/opengl/backend_opengl.h @@ -0,0 +1,68 @@ +#pragma once + +#ifdef CEL_REND_BACKEND_OPENGL + +#include "defines.h" +#include "maths_types.h" +#include "ral.h" +#include "ral_types.h" + +#define MAX_PIPELINE_UNIFORM_BUFFERS 32 + +#define OPENGL_DEFAULT_FRAMEBUFFER 0 + +typedef struct gpu_swapchain { + u32x2 dimensions; +} gpu_swapchain; +typedef struct gpu_device { +} gpu_device; +typedef struct gpu_pipeline_layout { + void* pad +} gpu_pipeline_layout; +typedef struct gpu_pipeline { + u32 shader_id; + gpu_renderpass* renderpass; + vertex_description vertex_desc; + buffer_handle uniform_bindings[MAX_PIPELINE_UNIFORM_BUFFERS]; + u32 uniform_count; + bool wireframe; +} gpu_pipeline; +typedef struct gpu_renderpass { + u32 fbo; + gpu_renderpass_desc description; +} gpu_renderpass; +typedef struct gpu_cmd_encoder { + gpu_pipeline* pipeline; +} gpu_cmd_encoder; // Recording +typedef struct gpu_cmd_buffer { + void* pad; +} gpu_cmd_buffer; // Ready for submission + +typedef struct gpu_buffer { + union { + u32 vbo; + u32 ibo; + u32 ubo; + } id; + union { + u32 vao; + u32 ubo_binding_point + }; // Optional + char* name; + u64 size; +} gpu_buffer; +typedef struct gpu_texture { + u32 id; + void* pad; +} gpu_texture; + +typedef struct opengl_support { +} opengl_support; + +u32 shader_create_separate(const char* vert_shader, const char* frag_shader); + +void uniform_vec3f(u32 program_id, const char* uniform_name, vec3* value); +void uniform_f32(u32 program_id, const char* uniform_name, f32 value); +void uniform_i32(u32 program_id, const char* uniform_name, i32 value); +void uniform_mat4f(u32 program_id, const char* uniform_name, mat4* value); +#endif diff --git a/src/archive/src/render/archive/backends/vulkan/README.md b/src/archive/src/render/archive/backends/vulkan/README.md new file mode 100644 index 0000000..220ed64 --- /dev/null +++ b/src/archive/src/render/archive/backends/vulkan/README.md @@ -0,0 +1 @@ +# Vulkan Backend Overview \ No newline at end of file diff --git a/src/archive/src/render/archive/backends/vulkan/backend_vulkan.c b/src/archive/src/render/archive/backends/vulkan/backend_vulkan.c new file mode 100644 index 0000000..8801230 --- /dev/null +++ b/src/archive/src/render/archive/backends/vulkan/backend_vulkan.c @@ -0,0 +1,1705 @@ +#include "defines.h" +#if defined(CEL_REND_BACKEND_VULKAN) + +#define GLFW_INCLUDE_VULKAN +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "backend_vulkan.h" +#include "buf.h" +#include "darray.h" +#include "maths_types.h" +#include "mem.h" +#include "ral_types.h" +#include "str.h" +#include "vulkan_helpers.h" + +#include "file.h" +#include "log.h" +#include "ral.h" +#include "utils.h" + +// TEMP +#define SCREEN_WIDTH 1000 +#define SCREEN_HEIGHT 1000 +#define VULKAN_QUEUES_COUNT 2 +#define MAX_DESCRIPTOR_SETS 10 + +const char* queue_names[VULKAN_QUEUES_COUNT] = { "GRAPHICS", "TRANSFER" }; + +KITC_DECL_TYPED_ARRAY(VkDescriptorSet) + +typedef struct vulkan_context { + VkInstance instance; + VkAllocationCallbacks* allocator; + VkSurfaceKHR surface; + vulkan_swapchain_support_info swapchain_support; + + arena temp_arena; + arena pool_arena; + gpu_device* device; + gpu_swapchain* swapchain; + u32 framebuffer_count; + VkFramebuffer* + swapchain_framebuffers; // TODO: Move this data into the swapchain as its own struct + + u32 current_img_index; + u32 current_frame; // super important + gpu_cmd_encoder main_cmd_bufs[MAX_FRAMES_IN_FLIGHT]; + VkSemaphore image_available_semaphores[MAX_FRAMES_IN_FLIGHT]; + VkSemaphore render_finished_semaphores[MAX_FRAMES_IN_FLIGHT]; + VkFence in_flight_fences[MAX_FRAMES_IN_FLIGHT]; + + // HACK + VkRenderPass main_renderpass; + + u32 screen_width; + u32 screen_height; + bool is_resizing; + GLFWwindow* window; + + // Storage + gpu_buffer buffers[1024]; + size_t buffer_count; + VkDescriptorSet_darray* free_set_queue; + struct resource_pools* resource_pools; + gpu_backend_pools gpu_pools; + + VkDebugUtilsMessengerEXT vk_debugger; +} vulkan_context; + +static vulkan_context context; + +// --- Function forward declarations + +void backend_pools_init(arena* a, gpu_backend_pools* backend_pools); + +/** @brief Enumerates and selects the most appropriate graphics device */ +bool select_physical_device(gpu_device* out_device); + +bool is_physical_device_suitable(VkPhysicalDevice device); + +queue_family_indices find_queue_families(VkPhysicalDevice device); + +bool create_logical_device(gpu_device* out_device); +void create_swapchain_framebuffers(); +void create_sync_objects(); +void create_descriptor_pools(); +size_t vertex_attrib_size(vertex_attrib_type attr); + +VkShaderModule create_shader_module(str8 spirv); + +/** @brief Helper function for creating array of all extensions we want */ +cstr_darray* get_all_extensions(); + +VkImage vulkan_image_create(u32x2 dimensions, VkImageType image_type, VkFormat format, + VkImageUsageFlags usage); +void vulkan_transition_image_layout(gpu_texture* texture, VkFormat format, VkImageLayout old_layout, + VkImageLayout new_layout); + +// --- Handy macros +#define BUFFER_GET(h) (buffer_pool_get(&context.resource_pools->buffers, h)) +#define TEXTURE_GET(h) (texture_pool_get(&context.resource_pools->textures, h)) + +bool gpu_backend_init(const char* window_name, GLFWwindow* window) { + memset(&context, 0, sizeof(vulkan_context)); + context.allocator = 0; // TODO: use an allocator + context.screen_width = SCREEN_WIDTH; + context.screen_height = SCREEN_HEIGHT; + context.window = window; + context.current_img_index = 0; + context.current_frame = 0; + context.free_set_queue = VkDescriptorSet_darray_new(100); + + // Create an allocator + size_t temp_arena_size = 1024 * 1024; + context.temp_arena = arena_create(malloc(temp_arena_size), temp_arena_size); + + size_t pool_buffer_size = 1024 * 1024; + context.pool_arena = arena_create(malloc(pool_buffer_size), pool_buffer_size); + + backend_pools_init(&context.pool_arena, &context.gpu_pools); + + // Setup Vulkan instance + VkApplicationInfo app_info = { VK_STRUCTURE_TYPE_APPLICATION_INFO }; + app_info.apiVersion = VK_API_VERSION_1_2; + app_info.pApplicationName = window_name; + app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0); + app_info.pEngineName = "Celeritas Engine"; + app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0); + + VkInstanceCreateInfo create_info = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO }; + create_info.pApplicationInfo = &app_info; + + // Extensions + cstr_darray* required_extensions = cstr_darray_new(2); + // cstr_darray_push(required_extensions, VK_KHR_SURFACE_EXTENSION_NAME); + + uint32_t count; + const char** extensions = glfwGetRequiredInstanceExtensions(&count); + for (u32 i = 0; i < count; i++) { + cstr_darray_push(required_extensions, extensions[i]); + } + + cstr_darray_push(required_extensions, VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + + DEBUG("Required extensions:"); + for (u32 i = 0; i < cstr_darray_len(required_extensions); i++) { + DEBUG(" %s", required_extensions->data[i]); + } + + create_info.enabledExtensionCount = cstr_darray_len(required_extensions); + create_info.ppEnabledExtensionNames = required_extensions->data; + + // TODO: Validation layers + create_info.enabledLayerCount = 0; + create_info.ppEnabledLayerNames = NULL; + + INFO("Validation layers enabled"); + cstr_darray* desired_validation_layers = cstr_darray_new(1); + cstr_darray_push(desired_validation_layers, "VK_LAYER_KHRONOS_validation"); + + u32 n_available_layers = 0; + VK_CHECK(vkEnumerateInstanceLayerProperties(&n_available_layers, 0)); + TRACE("%d available layers", n_available_layers); + VkLayerProperties* available_layers = + arena_alloc(&context.temp_arena, n_available_layers * sizeof(VkLayerProperties)); + VK_CHECK(vkEnumerateInstanceLayerProperties(&n_available_layers, available_layers)); + + for (int i = 0; i < cstr_darray_len(desired_validation_layers); i++) { + // look through layers to make sure we can find the ones we want + bool found = false; + for (int j = 0; j < n_available_layers; j++) { + if (str8_equals(str8_cstr_view(desired_validation_layers->data[i]), + str8_cstr_view(available_layers[j].layerName))) { + found = true; + TRACE("Found layer %s", desired_validation_layers->data[i]); + break; + } + } + + if (!found) { + FATAL("Required validation is missing %s", desired_validation_layers->data[i]); + return false; + } + } + INFO("All validation layers are present"); + create_info.enabledLayerCount = cstr_darray_len(desired_validation_layers); + create_info.ppEnabledLayerNames = desired_validation_layers->data; + + VkResult result = vkCreateInstance(&create_info, NULL, &context.instance); + if (result != VK_SUCCESS) { + ERROR("vkCreateInstance failed with result: %u", result); + return false; + } + TRACE("Vulkan Instance created"); + + DEBUG("Creating Vulkan debugger"); + u32 log_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; + VkDebugUtilsMessengerCreateInfoEXT debug_create_info = { + VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT + }; + debug_create_info.messageSeverity = log_severity; + debug_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; + debug_create_info.pfnUserCallback = vk_debug_callback; + + PFN_vkCreateDebugUtilsMessengerEXT func = + (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(context.instance, + "vkCreateDebugUtilsMessengerEXT"); + assert(func); + VK_CHECK(func(context.instance, &debug_create_info, context.allocator, &context.vk_debugger)); + DEBUG("Vulkan Debugger created"); + + // Surface creation + VkSurfaceKHR surface; + VK_CHECK(glfwCreateWindowSurface(context.instance, window, NULL, &surface)); + context.surface = surface; + TRACE("Vulkan Surface created"); + + return true; +} + +void gpu_backend_shutdown() { + gpu_swapchain_destroy(context.swapchain); + + vkDestroySurfaceKHR(context.instance, context.surface, context.allocator); + vkDestroyInstance(context.instance, context.allocator); + arena_free_storage(&context.temp_arena); +} + +bool gpu_device_create(gpu_device* out_device) { + // First things first store this poitner from the renderer + context.device = out_device; + + arena_save savept = arena_savepoint(&context.temp_arena); + // Physical device + if (!select_physical_device(out_device)) { + return false; + } + TRACE("Physical device selected"); + + // Logical device & Queues + create_logical_device(out_device); + + // Create the command pool + VkCommandPoolCreateInfo pool_create_info = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO }; + pool_create_info.queueFamilyIndex = out_device->queue_family_indicies.graphics_family_index; + pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + vkCreateCommandPool(out_device->logical_device, &pool_create_info, context.allocator, + &out_device->pool); + TRACE("Command Pool created"); + + // Synchronisation objects + create_sync_objects(); + TRACE("Synchronisation primitives created"); + + arena_rewind(savept); // Free any temp data + return true; +} + +bool gpu_swapchain_create(gpu_swapchain* out_swapchain) { + context.swapchain = out_swapchain; + + out_swapchain->swapchain_arena = arena_create(malloc(1024), 1024); + + vulkan_device_query_swapchain_support(context.device->physical_device, context.surface, + &context.swapchain_support); + vulkan_swapchain_support_info swapchain_support = context.swapchain_support; + + // TODO: custom swapchain extents VkExtent2D swapchain_extent = { width, height }; + + VkSurfaceFormatKHR image_format = choose_swapchain_format(&swapchain_support); + out_swapchain->image_format = image_format; + VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR; // guaranteed to be implemented + out_swapchain->present_mode = present_mode; + + u32 image_count = swapchain_support.capabilities.minImageCount + 1; + out_swapchain->image_count = image_count; + + VkSwapchainCreateInfoKHR swapchain_create_info = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR }; + swapchain_create_info.surface = context.surface; + swapchain_create_info.minImageCount = image_count; + swapchain_create_info.imageFormat = image_format.format; + swapchain_create_info.imageColorSpace = image_format.colorSpace; + swapchain_create_info.imageExtent = swapchain_support.capabilities.currentExtent; + swapchain_create_info.imageArrayLayers = 1; + swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + swapchain_create_info.queueFamilyIndexCount = 0; + swapchain_create_info.pQueueFamilyIndices = NULL; + + swapchain_create_info.preTransform = swapchain_support.capabilities.currentTransform; + swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + swapchain_create_info.presentMode = present_mode; + swapchain_create_info.clipped = VK_TRUE; + swapchain_create_info.oldSwapchain = VK_NULL_HANDLE; + + out_swapchain->extent = swapchain_support.capabilities.currentExtent; + + VK_CHECK(vkCreateSwapchainKHR(context.device->logical_device, &swapchain_create_info, + context.allocator, &out_swapchain->handle)); + TRACE("Vulkan Swapchain created"); + + // Retrieve Images + // out_swapchain->images = + // arena_alloc(&out_swapchain->swapchain_arena, image_count * sizeof(VkImage)); + out_swapchain->images = malloc(image_count * sizeof(VkImage)); + VK_CHECK(vkGetSwapchainImagesKHR(context.device->logical_device, out_swapchain->handle, + &image_count, out_swapchain->images)); + + // Create ImageViews + // TODO: Move this to a separate function + out_swapchain->image_views = malloc(image_count * sizeof(VkImageView)); + // arena_alloc(&out_swapchain->swapchain_arena, image_count * sizeof(VkImageView)); + for (u32 i = 0; i < image_count; i++) { + VkImageViewCreateInfo view_create_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; + view_create_info.image = out_swapchain->images[i]; + view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; + view_create_info.format = image_format.format; + view_create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + view_create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + view_create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + view_create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + view_create_info.subresourceRange.baseMipLevel = 0; + view_create_info.subresourceRange.levelCount = 1; + view_create_info.subresourceRange.baseArrayLayer = 0; + view_create_info.subresourceRange.layerCount = 1; + vkCreateImageView(context.device->logical_device, &view_create_info, context.allocator, + &out_swapchain->image_views[i]); + } + + return true; +} + +void gpu_swapchain_destroy(gpu_swapchain* swapchain) { + // Destroy Framebuffers + DEBUG("Image count %d", swapchain->image_count); + for (u32 i = 0; i < swapchain->image_count; i++) { + DEBUG("Framebuffer handle %d", context.swapchain_framebuffers[i]); + vkDestroyFramebuffer(context.device->logical_device, context.swapchain_framebuffers[i], + context.allocator); + } + for (u32 i = 0; i < swapchain->image_count; i++) { + vkDestroyImageView(context.device->logical_device, swapchain->image_views[i], + context.allocator); + } + arena_free_all(&swapchain->swapchain_arena); + vkDestroySwapchainKHR(context.device->logical_device, swapchain->handle, context.allocator); + TRACE("Vulkan Swapchain destroyed"); +} + +static void recreate_swapchain(gpu_swapchain* swapchain) { + int width = 0, height = 0; + glfwGetFramebufferSize(context.window, &width, &height); + while (width == 0 || height == 0) { + glfwGetFramebufferSize(context.window, &width, &height); + glfwWaitEvents(); + } + DEBUG("Recreating swapchain..."); + vkDeviceWaitIdle(context.device->logical_device); + + gpu_swapchain_destroy(swapchain); + gpu_swapchain_create(swapchain); + create_swapchain_framebuffers(); +} + +VkFormat format_from_vertex_attr(vertex_attrib_type attr) { + switch (attr) { + case ATTR_F32: + return VK_FORMAT_R32_SFLOAT; + case ATTR_U32: + return VK_FORMAT_R32_UINT; + case ATTR_I32: + return VK_FORMAT_R32_SINT; + case ATTR_F32x2: + return VK_FORMAT_R32G32_SFLOAT; + case ATTR_U32x2: + return VK_FORMAT_R32G32_UINT; + case ATTR_I32x2: + return VK_FORMAT_R32G32_UINT; + case ATTR_F32x3: + return VK_FORMAT_R32G32B32_SFLOAT; + case ATTR_U32x3: + return VK_FORMAT_R32G32B32_UINT; + case ATTR_I32x3: + return VK_FORMAT_R32G32B32_SINT; + case ATTR_F32x4: + return VK_FORMAT_R32G32B32A32_SFLOAT; + case ATTR_U32x4: + return VK_FORMAT_R32G32B32A32_UINT; + case ATTR_I32x4: + return VK_FORMAT_R32G32B32A32_SINT; + } +} + +gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc description) { + TRACE("GPU Graphics Pipeline creation"); + // Allocate + gpu_pipeline_layout* layout = + pipeline_layout_pool_alloc(&context.gpu_pools.pipeline_layouts, NULL); + gpu_pipeline* pipeline = pipeline_pool_alloc(&context.gpu_pools.pipelines, NULL); + + // Shaders + printf("Vertex shader: %s\n", description.vs.filepath.buf); + printf("Fragment shader: %s\n", description.fs.filepath.buf); + VkShaderModule vertex_shader = create_shader_module(description.vs.code); + VkShaderModule fragment_shader = create_shader_module(description.fs.code); + + // Vertex + VkPipelineShaderStageCreateInfo vert_shader_stage_info = { + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO + }; + vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; + vert_shader_stage_info.module = vertex_shader; + vert_shader_stage_info.pName = "main"; + // Fragment + VkPipelineShaderStageCreateInfo frag_shader_stage_info = { + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO + }; + frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + frag_shader_stage_info.module = fragment_shader; + frag_shader_stage_info.pName = "main"; + + VkPipelineShaderStageCreateInfo shader_stages[2] = { vert_shader_stage_info, + frag_shader_stage_info }; + + // Attributes + u32 attr_count = description.vertex_desc.attributes_count; + printf("N attributes %d\n", attr_count); + VkVertexInputAttributeDescription attribute_descs[attr_count]; + memset(attribute_descs, 0, attr_count * sizeof(VkVertexInputAttributeDescription)); + u32 offset = 0; + for (u32 i = 0; i < description.vertex_desc.attributes_count; i++) { + attribute_descs[i].binding = 0; + attribute_descs[i].location = i; + attribute_descs[i].format = format_from_vertex_attr(description.vertex_desc.attributes[i]); + attribute_descs[i].offset = offset; + size_t this_offset = vertex_attrib_size(description.vertex_desc.attributes[i]); + printf("offset total %d this attr %ld\n", offset, this_offset); + printf("sizeof vertex %ld\n", sizeof(vertex)); + offset += this_offset; + } + + // Vertex input + // TODO: Generate this from descroiption now + VkVertexInputBindingDescription binding_desc; + binding_desc.binding = 0; + binding_desc.stride = description.vertex_desc.use_full_vertex_size + ? sizeof(vertex) + : description.vertex_desc.stride; + binding_desc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + VkPipelineVertexInputStateCreateInfo vertex_input_info = { + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO + }; + vertex_input_info.vertexBindingDescriptionCount = 1; + vertex_input_info.pVertexBindingDescriptions = &binding_desc; + vertex_input_info.vertexAttributeDescriptionCount = + attr_count; // description.vertex_desc.attributes_count; + vertex_input_info.pVertexAttributeDescriptions = attribute_descs; + + // Input Assembly + VkPipelineInputAssemblyStateCreateInfo input_assembly = { + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO + }; + input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + input_assembly.primitiveRestartEnable = VK_FALSE; + + // Viewport + VkViewport viewport = { .x = 0, + .y = 0, + .width = (f32)context.swapchain->extent.width, + .height = (f32)context.swapchain->extent.height, + .minDepth = 0.0, + .maxDepth = 1.0 }; + VkRect2D scissor = { .offset = { .x = 0, .y = 0 }, .extent = context.swapchain->extent }; + VkPipelineViewportStateCreateInfo viewport_state = { + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO + }; + viewport_state.viewportCount = 1; + // viewport_state.pViewports = &viewport; + viewport_state.scissorCount = 1; + // viewport_state.pScissors = &scissor; + + // Rasterizer + VkPipelineRasterizationStateCreateInfo rasterizer_create_info = { + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO + }; + rasterizer_create_info.depthClampEnable = VK_FALSE; + rasterizer_create_info.rasterizerDiscardEnable = VK_FALSE; + rasterizer_create_info.polygonMode = + description.wireframe ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL; + rasterizer_create_info.lineWidth = 1.0f; + rasterizer_create_info.cullMode = VK_CULL_MODE_BACK_BIT; + rasterizer_create_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + /* rasterizer_create_info.frontFace = VK_FRONT_FACE_CLOCKWISE; */ + rasterizer_create_info.depthBiasEnable = VK_FALSE; + rasterizer_create_info.depthBiasConstantFactor = 0.0; + rasterizer_create_info.depthBiasClamp = 0.0; + rasterizer_create_info.depthBiasSlopeFactor = 0.0; + + // Multisampling + VkPipelineMultisampleStateCreateInfo ms_create_info = { + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO + }; + ms_create_info.sampleShadingEnable = VK_FALSE; + ms_create_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + ms_create_info.minSampleShading = 1.0; + ms_create_info.pSampleMask = 0; + ms_create_info.alphaToCoverageEnable = VK_FALSE; + ms_create_info.alphaToOneEnable = VK_FALSE; + + // TODO: Depth and stencil testing + // VkPipelineDepthStencilStateCreateInfo depth_stencil = { + // VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO + // }; + // depth_stencil.depthTestEnable = description.depth_test ? VK_TRUE : VK_FALSE; + // depth_stencil.depthWriteEnable = description.depth_test ? VK_TRUE : VK_FALSE; + // depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS; + // depth_stencil.depthBoundsTestEnable = VK_FALSE; + // depth_stencil.stencilTestEnable = VK_FALSE; + // depth_stencil.pNext = 0; + + // Blending + VkPipelineColorBlendAttachmentState color_blend_attachment_state; + color_blend_attachment_state.blendEnable = VK_FALSE; + color_blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + color_blend_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + color_blend_attachment_state.colorBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + color_blend_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + color_blend_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | + VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + VkPipelineColorBlendStateCreateInfo color_blend = { + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO + }; + color_blend.logicOpEnable = VK_FALSE; + color_blend.logicOp = VK_LOGIC_OP_COPY; + color_blend.attachmentCount = 1; + color_blend.pAttachments = &color_blend_attachment_state; + +// Dynamic state +#define DYNAMIC_STATE_COUNT 2 + VkDynamicState dynamic_states[DYNAMIC_STATE_COUNT] = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + }; + + VkPipelineDynamicStateCreateInfo dynamic_state = { + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO + }; + dynamic_state.dynamicStateCount = DYNAMIC_STATE_COUNT; + dynamic_state.pDynamicStates = dynamic_states; + + // Descriptor Set layouts + + VkDescriptorSetLayout* desc_set_layouts = + malloc(description.data_layouts_count * sizeof(VkDescriptorSetLayout)); + pipeline->desc_set_layouts = desc_set_layouts; + pipeline->desc_set_layouts_count = description.data_layouts_count; + if (description.data_layouts_count > 0) { + pipeline->uniform_pointers = + malloc(description.data_layouts_count * sizeof(desc_set_uniform_buffer)); + } else { + pipeline->uniform_pointers = NULL; + } + + // assert(description.data_layouts_count == 1); + printf("data layouts %d\n", description.data_layouts_count); + for (u32 layout_i = 0; layout_i < description.data_layouts_count; layout_i++) { + shader_data_layout sdl = description.data_layouts[layout_i].shader_data_get_layout(NULL); + TRACE("Got shader data layout %d's bindings! . found %d", layout_i, sdl.bindings_count); + + VkDescriptorSetLayoutBinding desc_set_bindings[sdl.bindings_count]; + + // Bindings + assert(sdl.bindings_count == 2); + for (u32 binding_j = 0; binding_j < sdl.bindings_count; binding_j++) { + desc_set_bindings[binding_j].binding = binding_j; + desc_set_bindings[binding_j].descriptorCount = 1; + switch (sdl.bindings[binding_j].type) { + case SHADER_BINDING_BUFFER: + case SHADER_BINDING_BYTES: + desc_set_bindings[binding_j].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + desc_set_bindings[binding_j].stageFlags = + VK_SHADER_STAGE_VERTEX_BIT; // FIXME: dont hardcode + + u64 buffer_size = sdl.bindings[binding_j].data.bytes.size; + VkDeviceSize uniform_buf_size = buffer_size; + // TODO: Create backing buffer + + VkBuffer buffers[MAX_FRAMES_IN_FLIGHT]; + VkDeviceMemory uniform_buf_memorys[MAX_FRAMES_IN_FLIGHT]; + void* uniform_buf_mem_mappings[MAX_FRAMES_IN_FLIGHT]; + // void* s? + for (size_t frame_i = 0; frame_i < MAX_FRAMES_IN_FLIGHT; frame_i++) { + buffer_handle uniform_buf_handle = + gpu_buffer_create(buffer_size, CEL_BUFFER_UNIFORM, CEL_BUFFER_FLAG_CPU, NULL); + + gpu_buffer* created_gpu_buffer = + BUFFER_GET(uniform_buf_handle); // context.buffers[uniform_buf_handle.raw]; + buffers[frame_i] = created_gpu_buffer->handle; + uniform_buf_memorys[frame_i] = created_gpu_buffer->memory; + vkMapMemory(context.device->logical_device, uniform_buf_memorys[frame_i], 0, + uniform_buf_size, 0, &uniform_buf_mem_mappings[frame_i]); + // now we have a pointer in unifrom_buf_mem_mappings we can write to + } + + desc_set_uniform_buffer uniform_data; + memcpy(&uniform_data.buffers, &buffers, sizeof(buffers)); + memcpy(&uniform_data.uniform_buf_memorys, &uniform_buf_memorys, + sizeof(uniform_buf_memorys)); + memcpy(&uniform_data.uniform_buf_mem_mappings, &uniform_buf_mem_mappings, + sizeof(uniform_buf_mem_mappings)); + uniform_data.size = buffer_size; + + pipeline->uniform_pointers[binding_j] = uniform_data; + + break; + case SHADER_BINDING_TEXTURE: + desc_set_bindings[binding_j].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + desc_set_bindings[binding_j].stageFlags = + VK_SHADER_STAGE_FRAGMENT_BIT; // FIXME: dont hardcode + desc_set_bindings[binding_j].pImmutableSamplers = NULL; + + break; + default: + ERROR_EXIT("Unimplemented binding type!! in backend_vulkan"); + } + switch (sdl.bindings[binding_j].vis) { + case VISIBILITY_VERTEX: + desc_set_bindings[binding_j].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + break; + case VISIBILITY_FRAGMENT: + desc_set_bindings[binding_j].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + break; + case VISIBILITY_COMPUTE: + WARN("Compute is not implemented yet"); + break; + } + } + + VkDescriptorSetLayoutCreateInfo desc_set_layout_info = { + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO + }; + desc_set_layout_info.bindingCount = sdl.bindings_count; + desc_set_layout_info.pBindings = desc_set_bindings; + + VK_CHECK(vkCreateDescriptorSetLayout(context.device->logical_device, &desc_set_layout_info, + context.allocator, &desc_set_layouts[layout_i])); + } + printf("Descriptor set layouts\n"); + + // Layout + VkPipelineLayoutCreateInfo pipeline_layout_create_info = { + VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO + }; + pipeline_layout_create_info.setLayoutCount = description.data_layouts_count; + pipeline_layout_create_info.pSetLayouts = desc_set_layouts; + pipeline_layout_create_info.pushConstantRangeCount = 0; + pipeline_layout_create_info.pPushConstantRanges = NULL; + VK_CHECK(vkCreatePipelineLayout(context.device->logical_device, &pipeline_layout_create_info, + context.allocator, &layout->handle)); + pipeline->layout_handle = layout->handle; // keep a copy of the layout on the pipeline object + + VkGraphicsPipelineCreateInfo pipeline_create_info = { + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO + }; + + pipeline_create_info.stageCount = 2; + pipeline_create_info.pStages = shader_stages; + pipeline_create_info.pVertexInputState = &vertex_input_info; + pipeline_create_info.pInputAssemblyState = &input_assembly; + + pipeline_create_info.pViewportState = &viewport_state; + pipeline_create_info.pRasterizationState = &rasterizer_create_info; + pipeline_create_info.pMultisampleState = &ms_create_info; + pipeline_create_info.pDepthStencilState = NULL; // &depth_stencil; + pipeline_create_info.pColorBlendState = &color_blend; + pipeline_create_info.pDynamicState = &dynamic_state; + pipeline_create_info.pTessellationState = 0; + + pipeline_create_info.layout = layout->handle; + + pipeline_create_info.renderPass = description.renderpass->handle; + pipeline_create_info.subpass = 0; + pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE; + pipeline_create_info.basePipelineIndex = -1; + + printf("About to create graphics pipeline\n"); + + VkResult result = + vkCreateGraphicsPipelines(context.device->logical_device, VK_NULL_HANDLE, 1, + &pipeline_create_info, context.allocator, &pipeline->handle); + if (result != VK_SUCCESS) { + FATAL("graphics pipeline creation failed. its fked mate"); + ERROR_EXIT("Doomed"); + } + TRACE("Vulkan Graphics pipeline created"); + + // once the pipeline has been created we can destroy these + vkDestroyShaderModule(context.device->logical_device, vertex_shader, context.allocator); + vkDestroyShaderModule(context.device->logical_device, fragment_shader, context.allocator); + + // Framebuffers + create_swapchain_framebuffers(); + TRACE("Swapchain Framebuffers created"); + + for (u32 frame_i = 0; frame_i < MAX_FRAMES_IN_FLIGHT; frame_i++) { + context.main_cmd_bufs[frame_i] = gpu_cmd_encoder_create(); + } + TRACE("main Command Buffer created"); + + TRACE("Graphics pipeline created"); + return pipeline; +} + +void gpu_pipeline_destroy(gpu_pipeline* pipeline) { + vkDestroyPipeline(context.device->logical_device, pipeline->handle, context.allocator); + vkDestroyPipelineLayout(context.device->logical_device, pipeline->layout_handle, + context.allocator); +} + +gpu_cmd_encoder* gpu_get_default_cmd_encoder() { + return &context.main_cmd_bufs[context.current_frame]; +} + +gpu_renderpass* gpu_renderpass_create(const gpu_renderpass_desc* description) { + gpu_renderpass* renderpass = renderpass_pool_alloc(&context.gpu_pools.renderpasses, NULL); + + // attachments + u32 attachment_desc_count = 2; + VkAttachmentDescription attachment_descriptions[2]; + + // Colour attachment + VkAttachmentDescription color_attachment; + color_attachment.format = context.swapchain->image_format.format; + color_attachment.samples = VK_SAMPLE_COUNT_1_BIT; + color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + color_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + color_attachment.flags = 0; + + attachment_descriptions[0] = color_attachment; + + VkAttachmentReference color_attachment_reference; + color_attachment_reference.attachment = 0; + color_attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + // Depth attachment + u32x2 ext = { .x = context.swapchain_support.capabilities.currentExtent.width, + .y = context.swapchain_support.capabilities.currentExtent.height }; + texture_desc depth_desc = { .extents = ext, + .format = CEL_TEXTURE_FORMAT_DEPTH_DEFAULT, + .tex_type = CEL_TEXTURE_TYPE_2D }; + texture_handle depth_texture_handle = gpu_texture_create(depth_desc, true, NULL); + gpu_texture* depth = TEXTURE_GET(depth_texture_handle); + + VkAttachmentDescription depth_attachment; + depth_attachment.format = // TODO: context->device.depth_format; + depth_attachment.samples = VK_SAMPLE_COUNT_1_BIT; + depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + depth_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + depth_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + depth_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + depth_attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + depth_attachment.flags = 0; + + attachment_descriptions[1] = depth_attachment; + + VkAttachmentReference depth_attachment_reference; + depth_attachment_reference.attachment = 1; + depth_attachment_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + // main subpass + VkSubpassDescription subpass = { 0 }; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &color_attachment_reference; + + // sets everything up + // renderpass dependencies + VkSubpassDependency dependency; + dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + dependency.dstSubpass = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.srcAccessMask = 0; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.dstAccessMask = + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dependency.dependencyFlags = 0; + + // Finally, create the RenderPass + VkRenderPassCreateInfo render_pass_create_info = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO }; + render_pass_create_info.attachmentCount = 1; + render_pass_create_info.pAttachments = &color_attachment; + render_pass_create_info.subpassCount = 1; + render_pass_create_info.pSubpasses = &subpass; + render_pass_create_info.dependencyCount = 1; + render_pass_create_info.pDependencies = &dependency; + render_pass_create_info.flags = 0; + render_pass_create_info.pNext = 0; + + VK_CHECK(vkCreateRenderPass(context.device->logical_device, &render_pass_create_info, + context.allocator, &renderpass->handle)); + + // HACK + context.main_renderpass = renderpass->handle; + + return renderpass; +} + +gpu_cmd_encoder gpu_cmd_encoder_create() { + // gpu_cmd_encoder* encoder = malloc(sizeof(gpu_cmd_encoder)); // TODO: fix leaking mem + gpu_cmd_encoder encoder = { 0 }; + + VkCommandBufferAllocateInfo allocate_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; + allocate_info.commandPool = context.device->pool; + allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocate_info.commandBufferCount = 1; + allocate_info.pNext = NULL; + + VK_CHECK(vkAllocateCommandBuffers(context.device->logical_device, &allocate_info, + &encoder.cmd_buffer);); + + VkDescriptorPoolSize pool_sizes[2]; + // Uniforms pool + pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + pool_sizes[0].descriptorCount = MAX_FRAMES_IN_FLIGHT * MAX_DESCRIPTOR_SETS; + // Samplers pool + pool_sizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + pool_sizes[1].descriptorCount = MAX_FRAMES_IN_FLIGHT * MAX_DESCRIPTOR_SETS; + + VkDescriptorPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; + pool_info.poolSizeCount = 2; + pool_info.pPoolSizes = pool_sizes; + pool_info.maxSets = 100; + + VK_CHECK(vkCreateDescriptorPool(context.device->logical_device, &pool_info, context.allocator, + &encoder.descriptor_pool)); + + return encoder; +} +void gpu_cmd_encoder_destroy(gpu_cmd_encoder* encoder) { + vkFreeCommandBuffers(context.device->logical_device, context.device->pool, 1, + &encoder->cmd_buffer); +} + +void gpu_cmd_encoder_begin(gpu_cmd_encoder encoder) { + VK_CHECK(vkResetDescriptorPool(context.device->logical_device, encoder.descriptor_pool, 0)); + + VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; + VK_CHECK(vkBeginCommandBuffer(encoder.cmd_buffer, &begin_info)); +} + +void gpu_cmd_encoder_begin_render(gpu_cmd_encoder* encoder, gpu_renderpass* renderpass) { + VkRenderPassBeginInfo begin_info = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO }; + begin_info.renderPass = renderpass->handle; + /* printf("Current img: %d Current frame %d\n", context.current_img_index, context.current_frame); + */ + begin_info.framebuffer = context.swapchain_framebuffers[context.current_img_index]; + begin_info.renderArea.offset = (VkOffset2D){ 0, 0 }; + begin_info.renderArea.extent = context.swapchain->extent; + + // VkClearValue clear_values[2]; + VkClearValue clear_color = { { { 0.02f, 0.02f, 0.02f, 1.0f } } }; + // clear_values[1].depthStencil.depth = renderpass->depth; + // clear_values[1].depthStencil.stencil = renderpass->stencil; + + begin_info.clearValueCount = 1; + begin_info.pClearValues = &clear_color; + + vkCmdBeginRenderPass(encoder->cmd_buffer, &begin_info, VK_SUBPASS_CONTENTS_INLINE); + // command_buffer->state = COMMAND_BUFFER_STATE_IN_RENDER_PASS; +} + +void gpu_cmd_encoder_end_render(gpu_cmd_encoder* encoder) { + vkCmdEndRenderPass(encoder->cmd_buffer); +} + +gpu_cmd_buffer gpu_cmd_encoder_finish(gpu_cmd_encoder* encoder) { + vkEndCommandBuffer(encoder->cmd_buffer); + + // TEMP: submit + return (gpu_cmd_buffer){ .cmd_buffer = encoder->cmd_buffer }; +} + +// --- Binding +void encode_bind_pipeline(gpu_cmd_encoder* encoder, pipeline_kind kind, gpu_pipeline* pipeline) { + vkCmdBindPipeline(encoder->cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->handle); + encoder->pipeline = pipeline; +} + +void encode_bind_shader_data(gpu_cmd_encoder* encoder, u32 group, shader_data* data) { + arena tmp = arena_create(malloc(1024), 1024); + + assert(data->data != NULL); + + // Update the local buffer + desc_set_uniform_buffer ubo = encoder->pipeline->uniform_pointers[group]; + memcpy(ubo.uniform_buf_mem_mappings[context.current_frame], data->data, ubo.size); + + VkDescriptorSetAllocateInfo alloc_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; + alloc_info.descriptorPool = encoder->descriptor_pool; + alloc_info.descriptorSetCount = 1; + alloc_info.pSetLayouts = &encoder->pipeline->desc_set_layouts[group]; + + shader_data_layout sdl = data->shader_data_get_layout(data->data); + size_t binding_count = sdl.bindings_count; + assert(binding_count == 2); + + VkDescriptorSet sets[0]; + VK_CHECK(vkAllocateDescriptorSets(context.device->logical_device, &alloc_info, sets)); + // FIXME: hardcoded + VkDescriptorSet_darray_push(context.free_set_queue, sets[0]); + /* VkDescriptorSet_darray_push(context.free_set_queue, sets[1]); */ + + VkWriteDescriptorSet write_sets[binding_count]; + memset(&write_sets, 0, binding_count * sizeof(VkWriteDescriptorSet)); + + for (u32 i = 0; i < sdl.bindings_count; i++) { + shader_binding binding = sdl.bindings[i]; + + if (binding.type == SHADER_BINDING_BUFFER || binding.type == SHADER_BINDING_BYTES) { + VkDescriptorBufferInfo* buffer_info = arena_alloc(&tmp, sizeof(VkDescriptorBufferInfo)); + buffer_info->buffer = ubo.buffers[context.current_frame]; + buffer_info->offset = 0; + buffer_info->range = binding.data.bytes.size; + + write_sets[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_sets[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + write_sets[i].descriptorCount = 1; + write_sets[i].dstSet = sets[0]; + write_sets[i].dstBinding = i; + write_sets[i].dstArrayElement = 0; + write_sets[i].pBufferInfo = buffer_info; + } else if (binding.type == SHADER_BINDING_TEXTURE) { + gpu_texture* texture = TEXTURE_GET(binding.data.texture.handle); + VkDescriptorImageInfo* image_info = arena_alloc(&tmp, sizeof(VkDescriptorImageInfo)); + image_info->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + image_info->imageView = texture->view; + image_info->sampler = texture->sampler; + + write_sets[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_sets[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + write_sets[i].descriptorCount = 1; + write_sets[i].dstSet = sets[0]; + write_sets[i].dstBinding = i; + write_sets[i].dstArrayElement = 0; + write_sets[i].pImageInfo = image_info; + } else { + WARN("Unknown binding"); + } + } + + // Update + vkUpdateDescriptorSets(context.device->logical_device, binding_count, write_sets, 0, NULL); + + // Bind + vkCmdBindDescriptorSets(encoder->cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + encoder->pipeline->layout_handle, 0, 1, sets, 0, NULL); + + arena_free_storage(&tmp); +} + +void encode_set_vertex_buffer(gpu_cmd_encoder* encoder, buffer_handle buf) { + gpu_buffer* buffer = BUFFER_GET(buf); // context.buffers[buf.raw]; + VkBuffer vbs[] = { buffer->handle }; + VkDeviceSize offsets[] = { 0 }; + vkCmdBindVertexBuffers(encoder->cmd_buffer, 0, 1, vbs, offsets); +} + +void encode_set_index_buffer(gpu_cmd_encoder* encoder, buffer_handle buf) { + gpu_buffer* buffer = BUFFER_GET(buf); // context.buffers[buf.raw]; + vkCmdBindIndexBuffer(encoder->cmd_buffer, buffer->handle, 0, VK_INDEX_TYPE_UINT32); +} + +// TEMP +void encode_set_default_settings(gpu_cmd_encoder* encoder) { + VkViewport viewport = { 0 }; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = context.swapchain->extent.width; + viewport.height = context.swapchain->extent.height; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + vkCmdSetViewport(encoder->cmd_buffer, 0, 1, &viewport); + + VkRect2D scissor = { 0 }; + scissor.offset = (VkOffset2D){ 0, 0 }; + scissor.extent = context.swapchain->extent; + vkCmdSetScissor(encoder->cmd_buffer, 0, 1, &scissor); +} + +// --- Drawing + +bool gpu_backend_begin_frame() { + u32 current_frame = context.current_frame; + vkWaitForFences(context.device->logical_device, 1, &context.in_flight_fences[current_frame], + VK_TRUE, UINT64_MAX); + + u32 image_index; + VkResult result = vkAcquireNextImageKHR( + context.device->logical_device, context.swapchain->handle, UINT64_MAX, + context.image_available_semaphores[current_frame], VK_NULL_HANDLE, &image_index); + if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || context.is_resizing) { + ERROR("Acquire next image failure. recreate swapchain"); + context.is_resizing = false; + recreate_swapchain(context.swapchain); + return false; + } else if (result != VK_SUCCESS) { + ERROR_EXIT("failed to acquire swapchain image"); + } + + vkResetFences(context.device->logical_device, 1, &context.in_flight_fences[current_frame]); + + context.current_img_index = image_index; + VK_CHECK(vkResetCommandBuffer(context.main_cmd_bufs[current_frame].cmd_buffer, 0)); + return true; +} + +void gpu_temp_draw(size_t n_indices) { + gpu_cmd_encoder* encoder = gpu_get_default_cmd_encoder(); // &context.main_cmd_buf; + /* vkCmdDraw(encoder->cmd_buffer, n_verts, 1, 0, 0); */ + vkCmdDrawIndexed(encoder->cmd_buffer, n_indices, 1, 0, 0, 0); +} + +void gpu_backend_end_frame() { + VkPresentInfoKHR present_info = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR }; + present_info.waitSemaphoreCount = 1; + present_info.pWaitSemaphores = &context.render_finished_semaphores[context.current_frame]; + + VkSwapchainKHR swapchains[] = { context.swapchain->handle }; + present_info.swapchainCount = 1; + present_info.pSwapchains = swapchains; + present_info.pImageIndices = &context.current_img_index; + + VkResult result = vkQueuePresentKHR(context.device->present_queue, &present_info); + if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { + ERROR("Queue present error. recreate swapchain"); + recreate_swapchain(context.swapchain); + return; + } else if (result != VK_SUCCESS) { + ERROR_EXIT("failed to present swapchain image"); + } + context.current_frame = (context.current_frame + 1) % MAX_FRAMES_IN_FLIGHT; + + /* vkDeviceWaitIdle(context.device->logical_device); */ +} + +// TODO: Move into better order in file +void gpu_queue_submit(gpu_cmd_buffer* buffer) { + VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; + + // Specify semaphore to wait on + VkSemaphore wait_semaphores[] = { context.image_available_semaphores[context.current_frame] }; + VkPipelineStageFlags wait_stages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; + + submit_info.waitSemaphoreCount = 1; + submit_info.pWaitSemaphores = wait_semaphores; + submit_info.pWaitDstStageMask = wait_stages; + + // Specify semaphore to signal when finished executing buffer + VkSemaphore signal_semaphores[] = { context.render_finished_semaphores[context.current_frame] }; + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = signal_semaphores; + + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &buffer->cmd_buffer; + + VK_CHECK(vkQueueSubmit(context.device->graphics_queue, 1, &submit_info, + context.in_flight_fences[context.current_frame])); +} + +inline void encode_draw_indexed(gpu_cmd_encoder* encoder, u64 index_count) { + vkCmdDrawIndexed(encoder->cmd_buffer, index_count, 1, 0, 0, 0); +} + +bool select_physical_device(gpu_device* out_device) { + u32 physical_device_count = 0; + VK_CHECK(vkEnumeratePhysicalDevices(context.instance, &physical_device_count, 0)); + if (physical_device_count == 0) { + FATAL("No devices that support vulkan were found"); + return false; + } + TRACE("Number of devices found %d", physical_device_count); + + VkPhysicalDevice* physical_devices = + arena_alloc(&context.temp_arena, physical_device_count * sizeof(VkPhysicalDevice)); + VK_CHECK(vkEnumeratePhysicalDevices(context.instance, &physical_device_count, physical_devices)); + + bool found = false; + for (u32 device_i = 0; device_i < physical_device_count; device_i++) { + if (is_physical_device_suitable(physical_devices[device_i])) { + out_device->physical_device = physical_devices[device_i]; + found = true; + break; + } + } + + if (!found) { + FATAL("Couldn't find a suitable physical device"); + return false; + } + + vkGetPhysicalDeviceProperties(out_device->physical_device, &out_device->properties); + vkGetPhysicalDeviceFeatures(out_device->physical_device, &out_device->features); + vkGetPhysicalDeviceMemoryProperties(out_device->physical_device, &out_device->memory); + + return true; +} + +bool is_physical_device_suitable(VkPhysicalDevice device) { + VkPhysicalDeviceProperties properties; + vkGetPhysicalDeviceProperties(device, &properties); + + VkPhysicalDeviceFeatures features; + vkGetPhysicalDeviceFeatures(device, &features); + + VkPhysicalDeviceMemoryProperties memory; + vkGetPhysicalDeviceMemoryProperties(device, &memory); + + // TODO: Check against these device properties + + queue_family_indices indices = find_queue_families(device); + + vulkan_device_query_swapchain_support(device, context.surface, &context.swapchain_support); + + return indices.has_graphics && indices.has_present && context.swapchain_support.mode_count > 0 && + context.swapchain_support.format_count > 0; +} + +queue_family_indices find_queue_families(VkPhysicalDevice device) { + queue_family_indices indices = { 0 }; + + u32 queue_family_count = 0; + vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, 0); + + VkQueueFamilyProperties* queue_families = + arena_alloc(&context.temp_arena, queue_family_count * sizeof(VkQueueFamilyProperties)); + vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, queue_families); + + for (u32 q_fam_i = 0; q_fam_i < queue_family_count; q_fam_i++) { + // Graphics queue + if (queue_families[q_fam_i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { + indices.graphics_family_index = q_fam_i; + indices.has_graphics = true; + } + + VkBool32 present_support = false; + vkGetPhysicalDeviceSurfaceSupportKHR(device, q_fam_i, context.surface, &present_support); + if (present_support && !indices.has_present) { + indices.present_family_index = q_fam_i; + indices.has_present = true; + } + } + + return indices; +} + +bool create_logical_device(gpu_device* out_device) { + queue_family_indices indices = find_queue_families(out_device->physical_device); + INFO(" %s | %s | %s | %s | %s", bool_str(indices.has_graphics), bool_str(indices.has_present), + bool_str(indices.has_compute), bool_str(indices.has_transfer), + out_device->properties.deviceName); + TRACE("Graphics Family queue index: %d", indices.graphics_family_index); + TRACE("Present Family queue index: %d", indices.present_family_index); + TRACE("Compute Family queue index: %d", indices.compute_family_index); + TRACE("Transfer Family queue index: %d", indices.transfer_family_index); + + // Queues + f32 prio_one = 1.0; + VkDeviceQueueCreateInfo queue_create_infos[1] = { 0 }; + queue_create_infos[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queue_create_infos[0].queueFamilyIndex = indices.graphics_family_index; + queue_create_infos[0].queueCount = 1; + queue_create_infos[0].pQueuePriorities = &prio_one; + queue_create_infos[0].flags = 0; + queue_create_infos[0].pNext = 0; + + // queue_create_infos[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + // queue_create_infos[1].queueFamilyIndex = indices.present_family_index; + // queue_create_infos[1].queueCount = 1; + // queue_create_infos[1].pQueuePriorities = &prio_one; + // queue_create_infos[1].flags = 0; + // queue_create_infos[1].pNext = 0; + + // Features + VkPhysicalDeviceFeatures device_features = { 0 }; + device_features.samplerAnisotropy = VK_TRUE; // request anistrophy + + // Device itself + VkDeviceCreateInfo device_create_info = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; + device_create_info.queueCreateInfoCount = 1; + device_create_info.pQueueCreateInfos = queue_create_infos; + device_create_info.pEnabledFeatures = &device_features; + device_create_info.enabledExtensionCount = 1; + const char* extension_names = VK_KHR_SWAPCHAIN_EXTENSION_NAME; + device_create_info.ppEnabledExtensionNames = &extension_names; + + // deprecated + device_create_info.enabledLayerCount = 0; + device_create_info.ppEnabledLayerNames = 0; + + VkResult result = vkCreateDevice(context.device->physical_device, &device_create_info, + context.allocator, &context.device->logical_device); + if (result != VK_SUCCESS) { + printf("error creating logical device with status %u\n", result); + ERROR_EXIT("Unable to create vulkan logical device. Exiting.."); + } + TRACE("Logical device created"); + + context.device->queue_family_indicies = indices; + + // Retrieve queue handles + vkGetDeviceQueue(context.device->logical_device, indices.graphics_family_index, 0, + &context.device->graphics_queue); + vkGetDeviceQueue(context.device->logical_device, indices.present_family_index, 0, + &context.device->present_queue); + + return true; +} + +VkShaderModule create_shader_module(str8 spirv) { + VkShaderModuleCreateInfo create_info = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO }; + create_info.codeSize = spirv.len; + create_info.pCode = (uint32_t*)spirv.buf; + + VkShaderModule shader_module; + VK_CHECK(vkCreateShaderModule(context.device->logical_device, &create_info, context.allocator, + &shader_module)); + + return shader_module; +} + +void create_descriptor_pools() {} + +void create_swapchain_framebuffers() { + WARN("Recreating framebuffers..."); + u32 image_count = context.swapchain->image_count; + context.swapchain_framebuffers = + arena_alloc(&context.swapchain->swapchain_arena, image_count * sizeof(VkFramebuffer)); + for (u32 i = 0; i < image_count; i++) { + VkImageView attachments[1] = { context.swapchain->image_views[i] }; + + VkFramebufferCreateInfo framebuffer_create_info = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO }; + framebuffer_create_info.attachmentCount = 1; + framebuffer_create_info.pAttachments = attachments; + + framebuffer_create_info.renderPass = + context.main_renderpass; // TODO: description.renderpass->handle; + framebuffer_create_info.width = context.swapchain->extent.width; + framebuffer_create_info.height = context.swapchain->extent.height; + framebuffer_create_info.layers = 1; + + VK_CHECK(vkCreateFramebuffer(context.device->logical_device, &framebuffer_create_info, + context.allocator, &context.swapchain_framebuffers[i])); + } +} + +void create_sync_objects() { + VkSemaphoreCreateInfo semaphore_info = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO }; + VkFenceCreateInfo fence_info = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO }; + fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; + + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + VK_CHECK(vkCreateSemaphore(context.device->logical_device, &semaphore_info, context.allocator, + &context.image_available_semaphores[i]);); + VK_CHECK(vkCreateSemaphore(context.device->logical_device, &semaphore_info, context.allocator, + &context.render_finished_semaphores[i]);); + + VK_CHECK(vkCreateFence(context.device->logical_device, &fence_info, context.allocator, + &context.in_flight_fences[i])); + } +} + +static i32 find_memory_index(u32 type_filter, u32 property_flags) { + VkPhysicalDeviceMemoryProperties memory_properties; + vkGetPhysicalDeviceMemoryProperties(context.device->physical_device, &memory_properties); + + for (u32 i = 0; i < memory_properties.memoryTypeCount; ++i) { + // Check each memory type to see if its bit is set to 1. + if (type_filter & (1 << i) && + (memory_properties.memoryTypes[i].propertyFlags & property_flags) == property_flags) { + return i; + } + } + + WARN("Unable to find suitable memory type!"); + return -1; +} + +buffer_handle gpu_buffer_create(u64 size, gpu_buffer_type buf_type, gpu_buffer_flags flags, + const void* data) { + VkBufferCreateInfo buffer_info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; + buffer_info.size = size; + buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + + switch (buf_type) { + case CEL_BUFFER_DEFAULT: + buffer_info.usage |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + break; + case CEL_BUFFER_VERTEX: + buffer_info.usage |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + break; + case CEL_BUFFER_INDEX: + buffer_info.usage |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT; + break; + case CEL_BUFFER_UNIFORM: + buffer_info.usage |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + break; + case CEL_BUFFER_COUNT: + WARN("Incorrect gpu_buffer_type provided. using default"); + break; + } + + buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + // "allocating" the cpu-side buffer struct + /* gpu_buffer buffer; */ + /* buffer.size = size; */ + buffer_handle handle; + gpu_buffer* buffer = buffer_pool_alloc(&context.resource_pools->buffers, &handle); + buffer->size = size; + + VK_CHECK(vkCreateBuffer(context.device->logical_device, &buffer_info, context.allocator, + &buffer->handle)); + + VkMemoryRequirements requirements; + vkGetBufferMemoryRequirements(context.device->logical_device, buffer->handle, &requirements); + + // Just make them always need all of them for now + i32 memory_index = + find_memory_index(requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + + // Allocate the actual VRAM + VkMemoryAllocateInfo allocate_info = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + allocate_info.allocationSize = requirements.size; + allocate_info.memoryTypeIndex = (u32)memory_index; + + vkAllocateMemory(context.device->logical_device, &allocate_info, context.allocator, + &buffer->memory); + vkBindBufferMemory(context.device->logical_device, buffer->handle, buffer->memory, 0); + + /* Now there are two options: + * 1. create CPU-accessible memory -> map memory -> memcpy -> unmap + * 2. use a staging buffer thats CPU-accessible and copy its contents to a + * GPU-only buffer + */ + + /* context.buffers[context.buffer_count] = buffer; */ + /* context.buffer_count++; */ + + if (data) { + TRACE("Upload data as part of buffer creation"); + if (flags & CEL_BUFFER_FLAG_CPU) { + // map memory -> copy data in -> unmap memory + buffer_upload_bytes(handle, (bytebuffer){ .buf = (u8*)data, .size = size }, 0, size); + } else if (flags & CEL_BUFFER_FLAG_GPU) { + TRACE("Uploading data to buffer using staging buffer"); + // Create a staging buffer + buffer_handle staging = gpu_buffer_create(size, buf_type, CEL_BUFFER_FLAG_CPU, NULL); + + // Copy data into it + buffer_upload_bytes(staging, (bytebuffer){ .buf = (u8*)data, .size = size }, 0, size); + + // Enqueue a copy from the staging buffer into the DEVICE_LOCAL buffer + gpu_cmd_encoder temp_encoder = gpu_cmd_encoder_create(); + gpu_cmd_encoder_begin(temp_encoder); + encode_buffer_copy(&temp_encoder, staging, 0, handle, 0, size); + gpu_cmd_buffer copy_cmd_buffer = gpu_cmd_encoder_finish(&temp_encoder); + + VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &temp_encoder.cmd_buffer; + vkQueueSubmit(context.device->graphics_queue, 1, &submit_info, VK_NULL_HANDLE); + + // Cleanup + vkQueueWaitIdle(context.device->graphics_queue); + gpu_cmd_encoder_destroy(&temp_encoder); + gpu_buffer_destroy(staging); + } + } + + return handle; +} + +void gpu_buffer_destroy(buffer_handle buffer) { + gpu_buffer* b = buffer_pool_get(&context.resource_pools->buffers, buffer); + vkDestroyBuffer(context.device->logical_device, b->handle, context.allocator); + vkFreeMemory(context.device->logical_device, b->memory, context.allocator); + buffer_pool_dealloc(&context.resource_pools->buffers, buffer); +} + +// Upload data to a +void buffer_upload_bytes(buffer_handle gpu_buf, bytebuffer cpu_buf, u64 offset, u64 size) { + gpu_buffer* buffer = buffer_pool_get(&context.resource_pools->buffers, gpu_buf); + void* data_ptr; + vkMapMemory(context.device->logical_device, buffer->memory, 0, size, 0, &data_ptr); + DEBUG("Uploading %d bytes to buffer", size); + memcpy(data_ptr, cpu_buf.buf, size); + vkUnmapMemory(context.device->logical_device, buffer->memory); +} + +void encode_buffer_copy(gpu_cmd_encoder* encoder, buffer_handle src, u64 src_offset, + buffer_handle dst, u64 dst_offset, u64 copy_size) { + VkBufferCopy copy_region; + copy_region.srcOffset = src_offset; + copy_region.dstOffset = dst_offset; + copy_region.size = copy_size; + + gpu_buffer* src_buf = buffer_pool_get(&context.resource_pools->buffers, src); + gpu_buffer* dst_buf = buffer_pool_get(&context.resource_pools->buffers, dst); + vkCmdCopyBuffer(encoder->cmd_buffer, src_buf->handle, dst_buf->handle, 1, ©_region); +} + +// one-shot command buffers +VkCommandBuffer vulkan_command_buffer_create_oneshot() { + VkCommandBufferAllocateInfo alloc_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; + alloc_info.commandPool = context.device->pool; + alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + alloc_info.commandBufferCount = 1; + alloc_info.pNext = 0; + + VkCommandBuffer cmd_buffer; + vkAllocateCommandBuffers(context.device->logical_device, &alloc_info, &cmd_buffer); + + VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; + begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + vkBeginCommandBuffer(cmd_buffer, &begin_info); + + return cmd_buffer; +} + +void vulkan_command_buffer_finish_oneshot(VkCommandBuffer cmd_buffer) { + VK_CHECK(vkEndCommandBuffer(cmd_buffer)); + + // submit to queue + VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &cmd_buffer; + VK_CHECK(vkQueueSubmit(context.device->graphics_queue, 1, &submit_info, 0)); + VK_CHECK(vkQueueWaitIdle(context.device->graphics_queue)); + + vkFreeCommandBuffers(context.device->logical_device, context.device->pool, 1, &cmd_buffer); +} + +void copy_buffer_to_buffer_oneshot(buffer_handle src, u64 src_offset, buffer_handle dst, + u64 dst_offset, u64 copy_size) { + VkBufferCopy copy_region; + copy_region.srcOffset = src_offset; + copy_region.dstOffset = dst_offset; + copy_region.size = copy_size; + + gpu_buffer* src_buf = buffer_pool_get(&context.resource_pools->buffers, src); + gpu_buffer* dst_buf = buffer_pool_get(&context.resource_pools->buffers, dst); + VkCommandBuffer temp_cmd_buffer = vulkan_command_buffer_create_oneshot(); + vkCmdCopyBuffer(temp_cmd_buffer, src_buf->handle, dst_buf->handle, 1, ©_region); + vulkan_command_buffer_finish_oneshot(temp_cmd_buffer); +} + +void copy_buffer_to_image_oneshot(buffer_handle src, texture_handle dst) { + gpu_buffer* src_buf = buffer_pool_get(&context.resource_pools->buffers, src); + gpu_texture* dst_tex = texture_pool_get(&context.resource_pools->textures, dst); + + VkCommandBuffer temp_cmd_buffer = vulkan_command_buffer_create_oneshot(); + + VkBufferImageCopy region; + region.bufferOffset = 0; + region.bufferRowLength = 0; + region.bufferImageHeight = 0; + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.mipLevel = 0; + region.imageSubresource.baseArrayLayer = 0; + region.imageSubresource.layerCount = 1; + printf("Image details width: %d height %d\n", dst_tex->desc.extents.x, dst_tex->desc.extents.y); + region.imageOffset.x = 0; + region.imageOffset.y = 0; + region.imageOffset.z = 0; + region.imageExtent.width = dst_tex->desc.extents.x; + region.imageExtent.height = dst_tex->desc.extents.y; + region.imageExtent.depth = 1; + + vkCmdCopyBufferToImage(temp_cmd_buffer, src_buf->handle, dst_tex->handle, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + vulkan_command_buffer_finish_oneshot(temp_cmd_buffer); +} + +VkImage vulkan_image_create(u32x2 dimensions, VkImageType image_type, VkFormat format, + VkImageUsageFlags usage) { + VkImage image; + + VkImageCreateInfo image_create_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; + image_create_info.imageType = VK_IMAGE_TYPE_2D; + image_create_info.extent.width = dimensions.x; + image_create_info.extent.height = dimensions.y; + image_create_info.extent.depth = 1; + image_create_info.mipLevels = 1; + image_create_info.arrayLayers = 1; + image_create_info.format = format; + image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; + image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + image_create_info.usage = usage; // VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; + + VK_CHECK( + vkCreateImage(context.device->logical_device, &image_create_info, context.allocator, &image)); + + return image; +} + +texture_handle gpu_texture_create(texture_desc desc, bool create_view, const void* data) { + VkDeviceSize image_size = desc.extents.x * desc.extents.y * 4; + // FIXME: handle this properly + VkFormat format = desc.format == CEL_TEXTURE_FORMAT_8_8_8_8_RGBA_UNORM ? VK_FORMAT_R8G8B8A8_SRGB + : VK_FORMAT_D32_SFLOAT; + + VkImage image; // vulkan_image_create(desc.extents, VK_IMAGE_TYPE_2D, format, + // VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); + VkDeviceMemory image_memory; + + VkImageCreateInfo image_create_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; + image_create_info.imageType = VK_IMAGE_TYPE_2D; + image_create_info.extent.width = desc.extents.x; + image_create_info.extent.height = desc.extents.y; + image_create_info.extent.depth = 1; + image_create_info.mipLevels = 1; + image_create_info.arrayLayers = 1; + image_create_info.format = format; + image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; + image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + if (format == VK_FORMAT_D32_SFLOAT) { + image_create_info.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + } + image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; + + VK_CHECK( + vkCreateImage(context.device->logical_device, &image_create_info, context.allocator, &image)); + + VkMemoryRequirements memory_reqs; + vkGetImageMemoryRequirements(context.device->logical_device, image, &memory_reqs); + + VkMemoryAllocateInfo alloc_info = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + alloc_info.allocationSize = memory_reqs.size; + alloc_info.memoryTypeIndex = + find_memory_index(memory_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + vkAllocateMemory(context.device->logical_device, &alloc_info, context.allocator, &image_memory); + + vkBindImageMemory(context.device->logical_device, image, image_memory, 0); + + texture_handle handle; + gpu_texture* texture = texture_pool_alloc(&context.resource_pools->textures, &handle); + DEBUG("Allocated texture with handle %d", handle.raw); + texture->handle = image; + texture->debug_label = "Test Texture"; + texture->desc = desc; + texture->memory = image_memory; + texture->size = image_size; + + if (data) { + TRACE("Uploading pixel data to texture using staging buffer"); + // Create a staging buffer + buffer_handle staging = + gpu_buffer_create(image_size, CEL_BUFFER_DEFAULT, CEL_BUFFER_FLAG_CPU, NULL); + // Copy data into it + vulkan_transition_image_layout(texture, format, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + buffer_upload_bytes(staging, (bytebuffer){ .buf = (u8*)data, .size = image_size }, 0, + image_size); + copy_buffer_to_image_oneshot(staging, handle); + vulkan_transition_image_layout(texture, format, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + gpu_buffer_destroy(staging); + } + + // Texture View + if (create_view) { + VkImageViewCreateInfo view_create_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; + view_create_info.image = image; + view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; + view_create_info.format = format; + view_create_info.subresourceRange.aspectMask = + format == VK_FORMAT_D32_SFLOAT ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; + + view_create_info.subresourceRange.baseMipLevel = 0; + view_create_info.subresourceRange.levelCount = 1; + view_create_info.subresourceRange.baseArrayLayer = 0; + view_create_info.subresourceRange.layerCount = 1; + + VK_CHECK(vkCreateImageView(context.device->logical_device, &view_create_info, context.allocator, + &texture->view)); + } + + // Sampler + VkSamplerCreateInfo sampler_info = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; + sampler_info.magFilter = VK_FILTER_LINEAR; + sampler_info.minFilter = VK_FILTER_LINEAR; + sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + sampler_info.anisotropyEnable = VK_TRUE; + sampler_info.maxAnisotropy = 16; + sampler_info.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; + sampler_info.unnormalizedCoordinates = VK_FALSE; + sampler_info.compareEnable = VK_FALSE; + sampler_info.compareOp = VK_COMPARE_OP_ALWAYS; + sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + sampler_info.mipLodBias = 0.0; + sampler_info.minLod = 0.0; + sampler_info.maxLod = 0.0; + + VkResult res = vkCreateSampler(context.device->logical_device, &sampler_info, context.allocator, + &texture->sampler); + if (res != VK_SUCCESS) { + ERROR("Error creating texture sampler for image %s", texture->debug_label); + exit(1); + } + + return handle; +} + +void vulkan_transition_image_layout(gpu_texture* texture, VkFormat format, VkImageLayout old_layout, + VkImageLayout new_layout) { + VkCommandBuffer temp_cmd_buffer = vulkan_command_buffer_create_oneshot(); + + VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; + barrier.oldLayout = old_layout; + barrier.newLayout = new_layout; + barrier.srcQueueFamilyIndex = context.device->queue_family_indicies.graphics_family_index; + barrier.dstQueueFamilyIndex = context.device->queue_family_indicies.graphics_family_index; + barrier.image = texture->handle; + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.subresourceRange.baseMipLevel = 0; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = 1; + barrier.srcAccessMask = 0; // TODO + barrier.dstAccessMask = 0; // TODO + + VkPipelineStageFlags source_stage; + VkPipelineStageFlags dest_stage; + + if (old_layout == VK_IMAGE_LAYOUT_UNDEFINED && + new_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { + barrier.srcAccessMask = 0; + barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + + source_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + dest_stage = VK_PIPELINE_STAGE_TRANSFER_BIT; + + } else if (old_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && + new_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + source_stage = VK_PIPELINE_STAGE_TRANSFER_BIT; + dest_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + } else { + FATAL("Unsupported image layout transition"); + return; + } + + vkCmdPipelineBarrier(temp_cmd_buffer, source_stage, dest_stage, 0, 0, 0, 0, 0, 1, &barrier); + + vulkan_command_buffer_finish_oneshot(temp_cmd_buffer); +} + +/* TYPED_POOL(gpu_buffer, buffer); */ +/* TYPED_POOL(gpu_texture, texture); */ + +/* void resource_pools_init(arena* a, struct resource_pools* res_pools) { */ +/* buffer_pool buf_pool = buffer_pool_create(a, MAX_BUFFERS, sizeof(gpu_buffer)); */ +/* res_pools->buffers = buf_pool; */ +/* texture_pool tex_pool = texture_pool_create(a, MAX_TEXTURES, sizeof(gpu_texture)); */ +/* res_pools->textures = tex_pool; */ + +/* context.resource_pools = res_pools; */ +/* } */ + +#endif diff --git a/src/archive/src/render/archive/backends/vulkan/backend_vulkan.h b/src/archive/src/render/archive/backends/vulkan/backend_vulkan.h new file mode 100644 index 0000000..6ca0bb5 --- /dev/null +++ b/src/archive/src/render/archive/backends/vulkan/backend_vulkan.h @@ -0,0 +1,118 @@ +#pragma once +#include "defines.h" +#if defined(CEL_REND_BACKEND_VULKAN) +#include +#include +#include + +#include "mem.h" +#include "ral.h" +#include "ral_types.h" + +#define MAX_FRAMES_IN_FLIGHT 2 +#define GPU_SWAPCHAIN_IMG_COUNT 2 + +/* +Conventions: + - Place the 'handle' as the first field of a struct + - Vulkan specific data goes at the top, followed by our internal data +*/ + +typedef struct queue_family_indices { + u32 graphics_family_index; + u32 present_family_index; + u32 compute_family_index; + u32 transfer_family_index; + bool has_graphics; + bool has_present; + bool has_compute; + bool has_transfer; +} queue_family_indices; + +// typedef struct vulkan_framebuffer { +// } vulkan_framebuffer; + +typedef struct gpu_swapchain { + VkSwapchainKHR handle; + arena swapchain_arena; + VkExtent2D extent; + u32x2 dimensions; + VkSurfaceFormatKHR image_format; + VkPresentModeKHR present_mode; + u32 image_count; + VkImage* images; + VkImageView* image_views; +} gpu_swapchain; + +typedef struct gpu_device { + // In Vulkan we store both physical and logical device here + VkPhysicalDevice physical_device; + VkDevice logical_device; + VkPhysicalDeviceProperties properties; + VkPhysicalDeviceFeatures features; + VkPhysicalDeviceMemoryProperties memory; + queue_family_indices queue_family_indicies; + VkQueue graphics_queue; + VkQueue present_queue; + VkQueue compute_queue; + VkQueue transfer_queue; + VkCommandPool pool; +} gpu_device; + +typedef struct gpu_pipeline_layout { + VkPipelineLayout handle; +} gpu_pipeline_layout; + +typedef struct desc_set_uniform_buffer { + VkBuffer buffers[MAX_FRAMES_IN_FLIGHT]; + VkDeviceMemory uniform_buf_memorys[MAX_FRAMES_IN_FLIGHT]; + void* uniform_buf_mem_mappings[MAX_FRAMES_IN_FLIGHT]; + size_t size; +} desc_set_uniform_buffer; + +typedef struct gpu_pipeline { + VkPipeline handle; + VkPipelineLayout layout_handle; + + // Descriptor gubbins + shader_data data_layouts[MAX_SHADER_DATA_LAYOUTS]; + u32 data_layouts_count; + + VkDescriptorSetLayout* desc_set_layouts; + // Based on group, we know which data to load + desc_set_uniform_buffer* uniform_pointers; + u32 desc_set_layouts_count; + +} gpu_pipeline; + +typedef struct gpu_renderpass { + VkRenderPass handle; + // TODO: Where to store framebuffers? VkFramebuffer framebuffers[GPU_SWAPCHAIN_IMG_COUNT]; +} gpu_renderpass; + +typedef struct gpu_cmd_encoder { + VkCommandBuffer cmd_buffer; + VkDescriptorPool descriptor_pool; + gpu_pipeline* pipeline; +} gpu_cmd_encoder; + +typedef struct gpu_cmd_buffer { + VkCommandBuffer cmd_buffer; +} gpu_cmd_buffer; + +typedef struct gpu_buffer { + VkBuffer handle; + VkDeviceMemory memory; + u64 size; +} gpu_buffer; + +typedef struct gpu_texture { + VkImage handle; + VkDeviceMemory memory; + u64 size; + texture_desc desc; + VkImageView view; + VkSampler sampler; + char* debug_label; +} gpu_texture; +#endif \ No newline at end of file diff --git a/src/archive/src/render/immdraw.c b/src/archive/src/render/immdraw.c new file mode 100644 index 0000000..8a10c65 --- /dev/null +++ b/src/archive/src/render/immdraw.c @@ -0,0 +1,176 @@ +#include "immdraw.h" +#include "core.h" +#include "file.h" +#include "log.h" +#include "maths.h" +#include "maths_types.h" +#include "primitives.h" +#include "ral_common.h" +#include "ral_impl.h" +#include "ral_types.h" +#include "render.h" +#include "render_types.h" +#include "shader_layouts.h" + +void Immdraw_Init(Immdraw_Storage* storage) { + INFO("Immediate drawing initialisation"); + + // Meshes + Geometry sphere_geo = Geo_CreateUVsphere(1.0, 16, 16); + storage->sphere = Mesh_Create(&sphere_geo, true); + + Geometry cube_geo = Geo_CreateCuboid(f32x3(1.0, 1.0, 1.0)); + storage->cube = Mesh_Create(&cube_geo, true); + + Geometry plane_geo = Geo_CreatePlane(f32x2(1.0, 1.0), 1, 1); + storage->plane = Mesh_Create(&plane_geo, true); + + Geometry cone_geo = Geo_CreateCone(1.0, 1.0, 8); + storage->cone = Mesh_Create(&cone_geo, true); + + Geometry cyl_geo = Geo_CreateCylinder(1.0, 2.0, 8); + storage->cylinder = Mesh_Create(&cyl_geo, true); + + storage->bbox = GenBboxMesh(); + + // Pipeline / material + VertexDescription vertex_desc = { + .debug_label = "Immdraw Vertex", + .use_full_vertex_size = true, + }; + VertexDesc_AddAttr(&vertex_desc, "position", ATTR_F32x3); + VertexDesc_AddAttr(&vertex_desc, "normal", ATTR_F32x3); + + const char* vert_path = "assets/shaders/immdraw.vert"; + const char* frag_path = "assets/shaders/immdraw.frag"; + const char* vert_shader = string_from_file(vert_path); + const char* frag_shader = string_from_file(frag_path); + + ShaderDataLayout camera_data = Binding_Camera_GetLayout(NULL); + ShaderDataLayout imm_uniform_data = ImmediateUniforms_GetLayout(NULL); + + GraphicsPipelineDesc pipeline_desc = { + .debug_name = "Immediate Draw Pipeline", + .vertex_desc = static_3d_vertex_description(), + .data_layouts = { camera_data, imm_uniform_data }, + .data_layouts_count = 2, + .vs = { .debug_name = "Immdraw Vertex Shader", .filepath = vert_path, .code = vert_shader }, + .fs = { .debug_name = "Immdraw Fragment Shader", .filepath = frag_path, .code = frag_shader }, + .depth_test = true, + .wireframe = true, + }; + GPU_Renderpass* rpass = + GPU_Renderpass_Create((GPU_RenderpassDesc){ .default_framebuffer = true }); + storage->colour_pipeline = GPU_GraphicsPipeline_Create(pipeline_desc, rpass); +} + +void Immdraw_Shutdown(Immdraw_Storage* storage) { + GraphicsPipeline_Destroy(storage->colour_pipeline); +} + +void Immdraw_Sphere(Transform tf, Vec4 colour, bool wireframe) { + TRACE("Draw sphere"); + Immdraw_Storage* imm = Render_GetImmdrawStorage(); + Immdraw_Primitive(tf, CEL_TRI, 1.0, colour, wireframe, imm->sphere); +} +void Immdraw_Cuboid(Transform tf, Vec4 colour, bool wireframe) { + TRACE("Draw cube"); + Immdraw_Storage* imm = Render_GetImmdrawStorage(); + Immdraw_Primitive(tf, CEL_TRI, 1.0, colour, wireframe, imm->cube); +} +void Immdraw_Plane(Transform tf, Vec4 colour, bool wireframe) { + TRACE("Draw plane"); + Immdraw_Storage* imm = Render_GetImmdrawStorage(); + Immdraw_Primitive(tf, CEL_TRI, 1.0, colour, wireframe, imm->plane); +} + +void Immdraw_Bbox(Transform tf, Vec4 colour, bool wireframe) { + TRACE("Draw bbox"); + Immdraw_Storage* imm = Render_GetImmdrawStorage(); + Immdraw_Primitive(tf, CEL_LINE, 1.0, colour, wireframe, imm->bbox); +} + +void Immdraw_Cylinder(Transform tf, Vec4 colour, bool wireframe) { + TRACE("Draw cylinder"); + Immdraw_Storage* imm = Render_GetImmdrawStorage(); + Immdraw_Primitive(tf, CEL_TRI, 1.0, colour, wireframe, imm->cylinder); +} + +void Immdraw_Cone(Transform tf, Vec4 colour, bool wireframe) { + TRACE("Draw cone"); + Immdraw_Storage* imm = Render_GetImmdrawStorage(); + Immdraw_Primitive(tf, CEL_TRI, 1.0, colour, wireframe, imm->cone); +} + +void Immdraw_Primitive(Transform tf, PrimitiveTopology topology, f32 size, Vec4 colour, + bool wireframe, Mesh mesh) { + Immdraw_Storage* imm = Render_GetImmdrawStorage(); + GPU_CmdEncoder* enc = GPU_GetDefaultEncoder(); + + // begin renderpass + GPU_CmdEncoder_BeginRender(enc, imm->colour_pipeline->renderpass); + // bind pipeline + GPU_EncodeBindPipeline(enc, imm->colour_pipeline); + + // TODO: implement wireframe in other apis +#if defined(CEL_REND_BACKEND_OPENGL) +#include + if (wireframe) { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + } else { + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } +#endif + + // update uniforms + ImmediateUniforms uniforms = { + .model = transform_to_mat(&tf), + .colour = colour, + }; + Mat4 view, proj; + u32x2 dimensions = GPU_Swapchain_GetDimensions(); + RenderScene* scene = Render_GetScene(); + Camera_ViewProj(&scene->camera, (f32)dimensions.x, (f32)dimensions.y, &view, &proj); + Binding_Camera camera_data = { .view = view, + .projection = proj, + .viewPos = vec4(scene->camera.position.x, scene->camera.position.y, + scene->camera.position.z, 1.0) }; + GPU_EncodeBindShaderData(enc, 0, Binding_Camera_GetLayout(&camera_data)); + GPU_EncodeBindShaderData(enc, 1, ImmediateUniforms_GetLayout(&uniforms)); + + // draw call + GPU_EncodeSetVertexBuffer(enc, mesh.vertex_buffer); + GPU_EncodeSetIndexBuffer(enc, mesh.index_buffer); + GPU_EncodeDrawIndexed(enc, topology, mesh.geometry.index_count); + + // end renderpass + GPU_CmdEncoder_EndRender(enc); +} + +Mesh GenBboxMesh() { + Vertex_darray* vertices = Vertex_darray_new(8); + u32_darray* indices = u32_darray_new(24); + + // normals & uvs dont matter + VERT_3D(vertices, FRONT_BOT_LEFT, VEC3_NEG_Z, vec2(0, 0)); + VERT_3D(vertices, FRONT_BOT_RIGHT, VEC3_NEG_Z, vec2(0, 0)); + VERT_3D(vertices, BACK_BOT_LEFT, VEC3_NEG_Z, vec2(0, 0)); + VERT_3D(vertices, BACK_BOT_RIGHT, VEC3_NEG_Z, vec2(0, 0)); + VERT_3D(vertices, FRONT_TOP_LEFT, VEC3_NEG_Z, vec2(0, 0)); + VERT_3D(vertices, FRONT_TOP_RIGHT, VEC3_NEG_Z, vec2(0, 0)); + VERT_3D(vertices, BACK_TOP_LEFT, VEC3_NEG_Z, vec2(0, 0)); + VERT_3D(vertices, BACK_TOP_RIGHT, VEC3_NEG_Z, vec2(0, 0)); + + u32 line_indices[24] = { 0, 1, 2, 3, 0, 2, 1, 3, 4, 5, 6, 7, 4, 6, 5, 7, 0, 4, 1, 5, 2, 6, 3, 7 }; + for (u32 i = 0; i < 24; i++) { + u32_darray_push(indices, line_indices[i]); + } + + Geometry geo = { .format = VERTEX_STATIC_3D, + .has_indices = true, + .index_count = indices->len, + .vertices = vertices, + .indices = indices }; + + return Mesh_Create(&geo, true); +} diff --git a/src/archive/src/render/immdraw.h b/src/archive/src/render/immdraw.h new file mode 100644 index 0000000..2911350 --- /dev/null +++ b/src/archive/src/render/immdraw.h @@ -0,0 +1,63 @@ +/** + * @brief Immediate-mode drawing APIs + */ + +#pragma once +#include "defines.h" +#include "maths_types.h" +#include "ral_impl.h" +#include "ral_types.h" +#include "render_types.h" + +typedef struct Immdraw_Storage { + Mesh plane; + Mesh cube; + Mesh sphere; + Mesh cylinder; + Mesh cone; + Mesh bbox; + GPU_Pipeline* colour_pipeline; /** @brief Pipeline for drawing geometry that has vertex colours */ +} Immdraw_Storage; + +typedef struct ImmediateUniforms { + Mat4 model; + Vec4 colour; +} ImmediateUniforms; + +// --- Public API + +PUB void Immdraw_Init(Immdraw_Storage* storage); +PUB void Immdraw_Shutdown(Immdraw_Storage* storage); + +// These functions cause a pipeline switch and so aren't optimised for performance +PUB void Immdraw_Plane(Transform tf, Vec4 colour, bool wireframe); +PUB void Immdraw_Cuboid(Transform tf, Vec4 colour, bool wireframe); +PUB void Immdraw_Cylinder(Transform tf, Vec4 colour, bool wireframe); +PUB void Immdraw_Cone(Transform tf, Vec4 colour, bool wireframe); +PUB void Immdraw_Sphere(Transform tf, Vec4 colour, bool wireframe); +PUB void Immdraw_Bbox(Transform tf, Vec4 colour, bool wireframe); + +PUB void Immdraw_TransformGizmo(Transform tf, f32 size); + +// --- Internal + +void Immdraw_Primitive(Transform tf, PrimitiveTopology topology, f32 size, Vec4 colour, + bool wireframe, Mesh mesh); + +Mesh GenBboxMesh(); + +static ShaderDataLayout ImmediateUniforms_GetLayout(void* data) { + ImmediateUniforms* d = (ImmediateUniforms*)data; + bool has_data = data != NULL; + + ShaderBinding b1 = { .label = "ImmUniforms", + .kind = BINDING_BYTES, + // .vis = VISIBILITY_VERTEX, + .data.bytes.size = sizeof(ImmediateUniforms) }; + + if (has_data) { + b1.data.bytes.data = d; + } + + return (ShaderDataLayout){ .bindings = { b1 }, .binding_count = 1 }; +} diff --git a/src/archive/src/render/pbr.c b/src/archive/src/render/pbr.c new file mode 100644 index 0000000..4bad528 --- /dev/null +++ b/src/archive/src/render/pbr.c @@ -0,0 +1,266 @@ +#include "pbr.h" +#include "animation.h" +#include "camera.h" +#include "core.h" +#include "file.h" +#include "log.h" +#include "maths.h" +#include "mem.h" +#include "ral_common.h" +#include "ral_impl.h" +#include "ral_types.h" +#include "render.h" +#include "render_types.h" +#include "shader_layouts.h" + +void PBR_Init(PBR_Storage* storage) { + INFO("PBR shaders init"); + storage->pbr_pass = PBR_RPassCreate(); + PBR_PipelinesCreate(storage, storage->pbr_pass); +} + +GPU_Renderpass* PBR_RPassCreate() { + GPU_RenderpassDesc desc = { .default_framebuffer = true }; + return GPU_Renderpass_Create(desc); +} + +void PBR_PipelinesCreate(PBR_Storage* storage, GPU_Renderpass* rpass) { + // Common shader bindings + ShaderDataLayout camera_data = Binding_Camera_GetLayout(NULL); + ShaderDataLayout model_data = Binding_Model_GetLayout(NULL); + ShaderDataLayout material_data = PBRMaterial_GetLayout(NULL); + ShaderDataLayout lights_data = Binding_Lights_GetLayout(NULL); + + // Static + { + const char* vert_path = "assets/shaders/static_geometry.vert"; + const char* frag_path = "assets/shaders/pbr_textured.frag"; + char* vert_shader = string_from_file(vert_path); + char* frag_shader = string_from_file(frag_path); + + GraphicsPipelineDesc desc = { + .debug_name = "PBR (Static) Pipeline", + .vertex_desc = static_3d_vertex_description(), + .data_layouts = { camera_data, model_data, material_data, lights_data }, + .data_layouts_count = 4, + .vs = { .debug_name = "PBR (textured) Vertex Shader", + .filepath = str8(vert_path), + .code = vert_shader }, + .fs = { .debug_name = "PBR (textured) Fragment Shader", + .filepath = str8(frag_path), + .code = frag_shader }, + .depth_test = true, + .wireframe = true, + }; + storage->pbr_static_pipeline = GPU_GraphicsPipeline_Create(desc, rpass); + } + + // Skinned + { + const char* vert_path = "assets/shaders/skinned_geometry.vert"; + const char* frag_path = "assets/shaders/pbr_textured.frag"; + char* vert_shader = string_from_file(vert_path); + char* frag_shader = string_from_file(frag_path); + + ShaderDataLayout anim_uniform = AnimData_GetLayout(NULL); + + VertexDescription vertex_desc = { .debug_label = "Skinned vertices", + .use_full_vertex_size = true }; + VertexDesc_AddAttr(&vertex_desc, "inPosition", ATTR_F32x3); + VertexDesc_AddAttr(&vertex_desc, "inNormal", ATTR_F32x3); + VertexDesc_AddAttr(&vertex_desc, "inTexCoords", ATTR_F32x2); + VertexDesc_AddAttr(&vertex_desc, "inBoneIndices", ATTR_I32x4); + VertexDesc_AddAttr(&vertex_desc, "inWeights", ATTR_F32x4); + + GraphicsPipelineDesc desc = { + .debug_name = "PBR (Skinned) Pipeline", + .vertex_desc = vertex_desc, + .data_layouts = { camera_data, model_data, material_data, lights_data, anim_uniform }, + .data_layouts_count = 5, + .vs = { .debug_name = "PBR (textured) Vertex Shader", + .filepath = str8(vert_path), + .code = vert_shader }, + .fs = { .debug_name = "PBR (textured) Fragment Shader", + .filepath = str8(frag_path), + .code = frag_shader }, + .depth_test = true, + .wireframe = true, + }; + storage->pbr_skinned_pipeline = GPU_GraphicsPipeline_Create(desc, rpass); + } +} + +void PBR_Execute(PBR_Storage* storage, Camera camera, TextureHandle shadowmap_tex, + RenderEnt* entities, size_t entity_count) { + // 1. set up our pipeline + // 2. upload constant data (camera, lights) + // 3. draw each entity + // - upload material data -> in the future we will sort & batch by material + // - upload model transform + // - emit draw call + + GPU_CmdEncoder* enc = GPU_GetDefaultEncoder(); + GPU_CmdEncoder_BeginRender(enc, storage->pbr_pass); + + // TEMP: only do skinned + GPU_EncodeBindPipeline(enc, storage->pbr_skinned_pipeline); + + // Feed shader data + Mat4 view, proj; + u32x2 dimensions = GPU_Swapchain_GetDimensions(); + Camera_ViewProj(&camera, (f32)dimensions.x, (f32)dimensions.y, &view, &proj); + Binding_Camera camera_data = { .view = view, + .projection = proj, + .viewPos = vec4(camera.position.x, camera.position.y, + camera.position.z, 1.0) }; + GPU_EncodeBindShaderData(enc, 0, Binding_Camera_GetLayout(&camera_data)); + + Vec3 light_color = vec3(300.0, 300.0, 300.0); + Binding_Lights + lights_data = { .pointLights = { + // FIXME: add lights to our RenderScene structure. for now these are + // hardcoded + (pbr_point_light){ .pos = vec3(0.0, 6.0, 6.0), .color = light_color }, + (pbr_point_light){ .pos = vec3(-10, 10, 10), .color = light_color }, + (pbr_point_light){ .pos = vec3(10, -10, 10), .color = light_color }, + (pbr_point_light){ .pos = vec3(-10, -10, 10), .color = light_color }, + } }; + GPU_EncodeBindShaderData(enc, 3, Binding_Lights_GetLayout(&lights_data)); + + // TODO: Add shadowmap texture to uniforms + Mesh_pool* mesh_pool = Render_GetMeshPool(); + Material_pool* material_pool = Render_GetMaterialPool(); + + for (size_t ent_i = 0; ent_i < entity_count; ent_i++) { + RenderEnt renderable = entities[ent_i]; + Mesh* mesh = Mesh_pool_get(mesh_pool, renderable.mesh); + Material* mat = Material_pool_get(material_pool, renderable.material); + + // upload material data + PBRMaterialUniforms material_data = { .mat = *mat }; + GPU_EncodeBindShaderData(enc, 2, PBRMaterial_GetLayout(&material_data)); + + // upload model transform + Binding_Model model_data = { .model = renderable.affine }; + GPU_EncodeBindShaderData(enc, 1, Binding_Model_GetLayout(&model_data)); + + // Skinning matrices + + // 1. calculate matrices + AnimDataUniform anim_data = { 0 }; + CASSERT(renderable.armature); + Armature* skeleton = renderable.armature; + // Skip the first one as we assume its root for this test + for (int j_i = 1; j_i < skeleton->joints->len; j_i++) { + Joint* j = &skeleton->joints->data[j_i]; + j->local_transform = transform_to_mat(&j->transform_components); + Mat4 m = mat4_mult(j->local_transform, j->inverse_bind_matrix); + Joint* p = &skeleton->joints->data[j->parent]; + j->local_transform = mat4_mult(j->local_transform, p->local_transform); + printf("Quat %f \n", j->transform_components.rotation.z); + } + + // 2. bind and upload + for (int j_i = 1; j_i < skeleton->joints->len; j_i++) { + anim_data.bone_matrices[j_i] = skeleton->joints->data[j_i].local_transform; + } + GPU_EncodeBindShaderData(enc, 3, AnimData_GetLayout(&anim_data)); + + // set buffers + GPU_EncodeSetVertexBuffer(enc, mesh->vertex_buffer); + GPU_EncodeSetIndexBuffer(enc, mesh->index_buffer); + // draw + GPU_EncodeDrawIndexedTris(enc, mesh->geometry.index_count); + } + + GPU_CmdEncoder_EndRender(enc); +} + +void PBRMaterial_BindData(ShaderDataLayout* layout, const void* data) { + PBRMaterialUniforms* d = (PBRMaterialUniforms*)data; + CASSERT(data); + CASSERT(layout->binding_count == 5); + + TextureHandle white1x1 = Render_GetWhiteTexture(); + if (d->mat.albedo_map.raw != INVALID_TEX_HANDLE.raw) { + layout->bindings[0].data.texture.handle = d->mat.albedo_map; + } else { + layout->bindings[0].data.texture.handle = white1x1; + } + // TODO .. the rest +} + +ShaderDataLayout PBRMaterial_GetLayout(void* data) { + PBRMaterialUniforms* d = (PBRMaterialUniforms*)data; + bool has_data = data != NULL; + + ShaderBinding b1 = { + .label = "albedoMap", + .kind = BINDING_TEXTURE, + }; + ShaderBinding b2 = { + .label = "metallicRoughnessMap", + .kind = BINDING_TEXTURE, + }; + ShaderBinding b3 = { + .label = "aoMap", + .kind = BINDING_TEXTURE, + }; + ShaderBinding b4 = { + .label = "normalMap", + .kind = BINDING_TEXTURE, + }; + ShaderBinding b5 = { .label = "PBR_Params", + .kind = BINDING_BYTES, + .data.bytes.size = sizeof(PBR_Params) }; + + if (has_data) { + TextureHandle white1x1 = Render_GetWhiteTexture(); + if (d->mat.albedo_map.raw != INVALID_TEX_HANDLE.raw) { + b1.data.texture.handle = d->mat.albedo_map; + } else { + b1.data.texture.handle = white1x1; + } + + if (d->mat.metallic_roughness_map.raw != INVALID_TEX_HANDLE.raw) { + b2.data.texture.handle = d->mat.metallic_roughness_map; + } else { + b2.data.texture.handle = white1x1; + } + + if (d->mat.ambient_occlusion_map.raw != INVALID_TEX_HANDLE.raw) { + b3.data.texture.handle = d->mat.ambient_occlusion_map; + } else { + b3.data.texture.handle = white1x1; + } + + if (d->mat.normal_map.raw != INVALID_TEX_HANDLE.raw) { + b4.data.texture.handle = d->mat.normal_map; + } else { + b4.data.texture.handle = white1x1; + } + + arena* frame = Render_GetFrameArena(); + PBR_Params* params = arena_alloc(frame, sizeof(PBR_Params)); + params->albedo = d->mat.base_colour; + params->metallic = d->mat.metallic; + params->roughness = d->mat.roughness; + params->ambient_occlusion = d->mat.ambient_occlusion; + b5.data.bytes.data = params; + } + + return (ShaderDataLayout){ .bindings = { b1, b2, b3, b4, b5 }, .binding_count = 5 }; +} + +Material PBRMaterialDefault() { + return (Material){ .name = "Standard Material", + .kind = MAT_PBR, + .base_colour = vec3(1.0, 1.0, 1.0), + .metallic = 0.0, + .roughness = 0.5, + .ambient_occlusion = 0.0, + .albedo_map = INVALID_TEX_HANDLE, + .metallic_roughness_map = INVALID_TEX_HANDLE, + .normal_map = INVALID_TEX_HANDLE, + .ambient_occlusion_map = INVALID_TEX_HANDLE }; +} diff --git a/src/archive/src/render/pbr.h b/src/archive/src/render/pbr.h new file mode 100644 index 0000000..5a21533 --- /dev/null +++ b/src/archive/src/render/pbr.h @@ -0,0 +1,70 @@ +/** + * @file pbr.h + * @brief PBR render pass and uniforms + */ + +#pragma once +#include "backend_opengl.h" +#include "camera.h" +#include "defines.h" +#include "maths_types.h" +#include "ral_types.h" +#include "render_types.h" + +// --- Public API + +/** @brief Holds data for the PBR pipeline */ +typedef struct PBR_Storage { + GPU_Renderpass* pbr_pass; + GPU_Pipeline* pbr_static_pipeline; + GPU_Pipeline* pbr_skinned_pipeline; +} PBR_Storage; + +typedef struct PBRMaterialUniforms { + Material mat; +} PBRMaterialUniforms; + +/** @brief */ +PUB void PBR_Init(PBR_Storage* storage); + +// NOTE: For simplicity's sake we will render this pass directly to the default framebuffer +// internally this defers to `PBR_Execute()` +PUB void PBR_Run(PBR_Storage* storage + // light data + // camera + // geometry + // materials +); + +/** @brief Parameters that get passed as a uniform block to the PBR shader */ +typedef struct PBR_Params { + Vec3 albedo; + f32 metallic; + f32 roughness; + f32 ambient_occlusion; +} PBR_Params; + +/** @brief Textures that will get passed into the PBR shader if they're not `INVALID_TEX_HANDLE` */ +typedef struct PBR_Textures { + TextureHandle albedo_map; + TextureHandle normal_map; + bool metal_roughness_combined; + TextureHandle metallic_map; + TextureHandle roughness_map; + TextureHandle ao_map; +} PBR_Textures; + +/** @brief Returns a default white matte material */ +PUB Material PBRMaterialDefault(); + +PUB ShaderDataLayout PBRMaterial_GetLayout(void* data); + +// --- Internal + +GPU_Renderpass* PBR_RPassCreate(); /** @brief Create the PBR Renderpass */ + +void PBR_PipelinesCreate(PBR_Storage* storage, + GPU_Renderpass* rpass); /** @brief Create PBR Pipelines */ + +void PBR_Execute(PBR_Storage* storage, Camera camera, TextureHandle shadowmap_tex, + RenderEnt* entities, size_t entity_count); diff --git a/src/archive/src/render/render.c b/src/archive/src/render/render.c new file mode 100644 index 0000000..af636a8 --- /dev/null +++ b/src/archive/src/render/render.c @@ -0,0 +1,359 @@ +/** + * @brief + */ + +#include "render.h" +#include +#include +#include +#include "camera.h" +#include "core.h" +#include "grid.h" +#include "immdraw.h" +#include "log.h" +#include "maths.h" +#include "maths_types.h" +#include "mem.h" +#include "pbr.h" +#include "ral_common.h" +#include "ral_impl.h" +#include "ral_types.h" +#include "render_types.h" +#include "shadows.h" +#include "terrain.h" + +#define STB_IMAGE_IMPLEMENTATION +#include + +#define FRAME_ARENA_SIZE MB(1) +#define POOL_SIZE_BYTES \ + MB(10) // we will reserve 10 megabytes up front to store resource, mesh, and material pools +#define MAX_MESHES 1024 +#define MAX_MATERIALS 256 + +extern Core g_core; + +struct Renderer { + struct GLFWwindow* window; + RendererConfig config; + GPU_Device device; + GPU_Swapchain swapchain; + GPU_Renderpass* default_renderpass; + bool frame_aborted; + RenderMode render_mode; + RenderScene scene; + PBR_Storage* pbr; + Shadow_Storage* shadows; + Terrain_Storage* terrain; + Grid_Storage* grid; + Immdraw_Storage* immediate; + // Text_Storage* text; + ResourcePools* resource_pools; + Mesh_pool mesh_pool; + Material_pool material_pool; + arena frame_arena; + TextureHandle white_1x1; + TextureHandle black_1x1; +}; + +Renderer* get_renderer() { return g_core.renderer; } + +bool Renderer_Init(RendererConfig config, Renderer* ren, GLFWwindow** out_window, + GLFWwindow* optional_window) { + INFO("Renderer init"); + ren->render_mode = RENDER_MODE_DEFAULT; + + ren->frame_arena = arena_create(malloc(FRAME_ARENA_SIZE), FRAME_ARENA_SIZE); + + // init resource pools + DEBUG("Initialise GPU resource pools"); + arena pool_arena = arena_create(malloc(POOL_SIZE_BYTES), POOL_SIZE_BYTES); + ren->resource_pools = arena_alloc(&pool_arena, sizeof(struct ResourcePools)); + ResourcePools_Init(&pool_arena, ren->resource_pools); + ren->mesh_pool = Mesh_pool_create(&pool_arena, MAX_MESHES, sizeof(Mesh)); + ren->material_pool = Material_pool_create(&pool_arena, MAX_MATERIALS, sizeof(Material)); + + // GLFW window creation + GLFWwindow* window; + if (optional_window != NULL) { + INFO("GLFWwindow pointer was provided!!!! Skipping generic glfw init.."); + window = optional_window; + } else { + INFO("No GLFWwindow provided - creating one"); + // NOTE: all platforms use GLFW at the moment but thats subject to change + glfwInit(); + +#if defined(CEL_REND_BACKEND_OPENGL) + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); +#elif defined(CEL_REND_BACKEND_VULKAN) + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); +#endif + + window = glfwCreateWindow(config.scr_width, config.scr_height, config.window_name, NULL, NULL); + INFO("Window created"); + if (window == NULL) { + ERROR("Failed to create GLFW window\n"); + glfwTerminate(); + return false; + } + } + + ren->window = window; + *out_window = window; + + glfwMakeContextCurrent(ren->window); + + DEBUG("Set up GLFW window callbacks"); + glfwSetWindowSizeCallback(window, Render_WindowSizeChanged); + + // set the RAL backend up + if (!GPU_Backend_Init(config.window_name, window, ren->resource_pools)) { + return false; + } + + GPU_Device_Create(&ren->device); + GPU_Swapchain_Create(&ren->swapchain); + + // set up default scene + Camera default_cam = + Camera_Create(vec3(0.0, 2.0, 4.0), vec3_normalise(vec3(0.0, -2.0, -4.0)), VEC3_Y, 45.0); + SetCamera(default_cam); + DirectionalLight default_light = { /* TODO */ }; + SetMainLight(default_light); + + // create our renderpasses + ren->shadows = malloc(sizeof(Shadow_Storage)); + Shadow_Init(ren->shadows, 1024, 1024); + + ren->pbr = calloc(1, sizeof(PBR_Storage)); + PBR_Init(ren->pbr); + + ren->terrain = calloc(1, sizeof(Terrain_Storage)); + Terrain_Init(ren->terrain); + + // FIXME + // ren->grid = calloc(1, sizeof(Grid_Storage)); + // Grid_Init(ren->grid); + + ren->immediate = calloc(1, sizeof(Immdraw_Storage)); + Immdraw_Init(ren->immediate); + + // load default textures + ren->white_1x1 = TextureLoadFromFile("assets/textures/white1x1.png"); + ren->black_1x1 = TextureLoadFromFile("assets/textures/black1x1.png"); + + return true; +} + +void Renderer_Shutdown(Renderer* ren) { + free(ren->shadows); + DEBUG("Freed Shadows storage"); + free(ren->pbr); + DEBUG("Freed PBR storage"); + free(ren->terrain); + DEBUG("Freed Terrain storage"); + free(ren->immediate); + DEBUG("Freed Immdraw storage"); + arena_free_storage(&ren->frame_arena); + DEBUG("Freed frame allocator buffer"); +} +size_t Renderer_GetMemReqs() { return sizeof(Renderer); } + +void Render_WindowSizeChanged(GLFWwindow* window, i32 new_width, i32 new_height) { + (void)window; + INFO("Window size changed callback"); + // Renderer* ren = Core_GetRenderer(&g_core); + GPU_Swapchain_Resize(new_width, new_height); +} + +void Render_FrameBegin(Renderer* ren) { + arena_free_all(&ren->frame_arena); + ren->frame_aborted = false; + if (!GPU_Backend_BeginFrame()) { + ren->frame_aborted = true; + WARN("Frame aborted"); + return; + } +} +void Render_FrameEnd(Renderer* ren) { + if (ren->frame_aborted) { + return; + } + + GPU_CmdEncoder* enc = GPU_GetDefaultEncoder(); + + GPU_Backend_EndFrame(); +} +void Render_RenderEntities(RenderEnt* entities, size_t entity_count) { + Renderer* ren = get_renderer(); + RenderScene scene = ren->scene; + + // FUTURE: Depth pre-pass + + Shadow_Storage* shadow_storage = Render_GetShadowStorage(); + shadow_storage->enabled = false; + TextureHandle sun_shadowmap = + shadow_storage->enabled ? Shadow_GetShadowMapTexture(shadow_storage) : INVALID_TEX_HANDLE; + + PBR_Execute(ren->pbr, scene.camera, sun_shadowmap, entities, entity_count); +} + +TextureData TextureDataLoad(const char* path, bool invert_y) { + TRACE("Load texture %s", path); + + // load the file data + int width, height, num_channels; + stbi_set_flip_vertically_on_load(invert_y); + +#pragma GCC diagnostic ignored "-Wpointer-sign" + char* data = stbi_load(path, &width, &height, &num_channels, 0); + if (data) { + DEBUG("loaded texture: %s", path); + } else { + WARN("failed to load texture"); + } + + // printf("width: %d height: %d num channels: %d\n", width, height, num_channels); + + unsigned int channel_type; + GPU_TextureFormat format; + if (num_channels == 4) { + channel_type = GL_RGBA; + format = TEXTURE_FORMAT_8_8_8_8_RGBA_UNORM; + } else { + channel_type = GL_RGB; + format = TEXTURE_FORMAT_8_8_8_RGB_UNORM; + } + TextureDesc desc = { + .extents = { width, height }, + .format = format, + .num_channels = num_channels, + .tex_type = TEXTURE_TYPE_2D, + }; + + return (TextureData){ .description = desc, .image_data = data }; +} + +TextureHandle TextureLoadFromFile(const char* path) { + TextureData tex_data = TextureDataLoad(path, false); + TextureHandle h = GPU_TextureCreate(tex_data.description, true, tex_data.image_data); + return h; +} + +Mesh Mesh_Create(Geometry* geometry, bool free_on_upload) { + Mesh m = { 0 }; + + // Create and upload vertex buffer + size_t vert_bytes = geometry->vertices->len * sizeof(Vertex); + INFO("Creating vertex buffer with size %d (%d x %d)", vert_bytes, geometry->vertices->len, + sizeof(Vertex)); + m.vertex_buffer = + GPU_BufferCreate(vert_bytes, BUFFER_VERTEX, BUFFER_FLAG_GPU, geometry->vertices->data); + + // Create and upload index buffer + if (geometry->has_indices) { + size_t index_bytes = geometry->indices->len * sizeof(u32); + INFO("Creating index buffer with size %d (len: %d)", index_bytes, geometry->indices->len); + m.index_buffer = + GPU_BufferCreate(index_bytes, BUFFER_INDEX, BUFFER_FLAG_GPU, geometry->indices->data); + } + + m.is_uploaded = true; + m.geometry = *geometry; // clone geometry data and store on Mesh struct + if (free_on_upload) { + Geometry_Destroy(geometry); + } + return m; +} + +void Geometry_Destroy(Geometry* geometry) { + if (geometry->indices) { + u32_darray_free(geometry->indices); + } + if (geometry->vertices) { + Vertex_darray_free(geometry->vertices); + } +} +PUB MeshHandle Mesh_Insert(Mesh* mesh) { return Mesh_pool_insert(Render_GetMeshPool(), mesh); } +PUB MaterialHandle Material_Insert(Material* material) { + return Material_pool_insert(Render_GetMaterialPool(), material); +} +Mesh* Mesh_Get(MeshHandle handle) { return Mesh_pool_get(Render_GetMeshPool(), handle); } + +void Mesh_DebugPrint(Mesh* mesh) { + printf("Mesh %d vertices %d indices %d joints \n", mesh->geometry.vertices->len, + mesh->geometry.indices->len); +} + +size_t ModelExtractRenderEnts(RenderEnt_darray* entities, ModelHandle model_handle, Mat4 affine, + RenderEntityFlags flags) { + Model* model = MODEL_GET(model_handle); + for (u32 i = 0; i < model->mesh_count; i++) { + Mesh* m = Mesh_pool_get(Render_GetMeshPool(), model->meshes[i]); + RenderEnt data = { .mesh = model->meshes[i], + .material = m->material, + .affine = affine, + // .bounding_box + .flags = flags }; + RenderEnt_darray_push(entities, data); + } + return model->mesh_count; // how many RenderEnts we pushed +} + +void SetCamera(Camera camera) { g_core.renderer->scene.camera = camera; } +void SetMainLight(DirectionalLight light) { g_core.renderer->scene.sun = light; } + +arena* GetRenderFrameArena(Renderer* r) { return &r->frame_arena; } + +RenderScene* Render_GetScene() { + Renderer* ren = Core_GetRenderer(&g_core); + return &ren->scene; +} + +Shadow_Storage* Render_GetShadowStorage() { + Renderer* ren = Core_GetRenderer(&g_core); + return ren->shadows; +} + +Terrain_Storage* Render_GetTerrainStorage() { + Renderer* ren = Core_GetRenderer(&g_core); + return ren->terrain; +} + +Grid_Storage* Render_GetGridStorage() { + Renderer* ren = Core_GetRenderer(&g_core); + return ren->grid; +} + +Immdraw_Storage* Render_GetImmdrawStorage() { + Renderer* ren = Core_GetRenderer(&g_core); + return ren->immediate; +} + +TextureHandle Render_GetWhiteTexture() { + Renderer* ren = Core_GetRenderer(&g_core); + return ren->white_1x1; +} + +/** @return an arena allocator that gets cleared at the beginning of every render frame */ +arena* Render_GetFrameArena() { + Renderer* ren = Core_GetRenderer(&g_core); + return &ren->frame_arena; +} + +Mesh_pool* Render_GetMeshPool() { + Renderer* ren = Core_GetRenderer(&g_core); + return &ren->mesh_pool; +} +Material_pool* Render_GetMaterialPool() { + Renderer* ren = Core_GetRenderer(&g_core); + return &ren->material_pool; +} + +void Render_SetRenderMode(RenderMode mode) { + Renderer* ren = Core_GetRenderer(&g_core); + ren->render_mode = mode; +} diff --git a/src/archive/src/render/render.h b/src/archive/src/render/render.h new file mode 100644 index 0000000..d752f8b --- /dev/null +++ b/src/archive/src/render/render.h @@ -0,0 +1,151 @@ +/** + * @brief + */ + +#pragma once +#include "camera.h" +#include "defines.h" +#include "grid.h" +#include "immdraw.h" +#include "maths_types.h" +#include "ral_types.h" +#include "render_types.h" +#include "shadows.h" + +typedef struct Renderer Renderer; +typedef struct GLFWwindow GLFWwindow; +typedef struct RendererConfig { + const char* window_name; + u32 scr_width, scr_height; + Vec3 clear_colour; +} RendererConfig; + +typedef struct RenderFlags { + bool wireframe; +} RenderFlags; + +typedef struct RenderCtx { + Mat4 view; + Mat4 projection; +} RenderCtx; + +/** @brief Holds globally bound data for rendering a scene. Typically held by the renderer. + * Whenever you call draw functions you can think of this as an implicit parameter. */ +typedef struct RenderScene { + Camera camera; + DirectionalLight sun; +} RenderScene; + +PUB void SetCamera(Camera camera); +PUB void SetMainLight(DirectionalLight light); + +// #define MESH_GET(h) (Mesh_pool_get(g_core.renderer->meshes, h)) +// #define MATERIAL_GET(h) (Material_pool_get(g_core.renderer->material, h)) + +// --- Lifecycle + +PUB bool Renderer_Init(RendererConfig config, Renderer* renderer, GLFWwindow** out_window, + GLFWwindow* optional_window); +PUB void Renderer_Shutdown(Renderer* renderer); +PUB size_t Renderer_GetMemReqs(); +void Render_WindowSizeChanged(GLFWwindow* window, i32 new_width, i32 new_height); + +// internal init functions +void DefaultPipelinesInit(Renderer* renderer); + +// NOTE: All of these functions grab the Renderer instance off the global Core +PUB void Render_FrameBegin(Renderer* renderer); +PUB void Render_FrameEnd(Renderer* renderer); + +/** @brief */ +PUB void Render_RenderEntities(RenderEnt* entities, size_t entity_count); + +// TODO: Render_FrameDraw(); - this will + +// --- Resources + +PUB TextureData TextureDataLoad(const char* path, bool invert_y); +PUB void TextureUpload(TextureHandle handle, size_t n_bytes, const void* data); +PUB TextureHandle TextureLoadFromFile(const char* path); +PUB ModelHandle ModelLoad(const char* debug_name, const char* filepath); + +// --- Rendering Data + +PUB Mesh Mesh_Create(Geometry* geometry, bool free_on_upload); +PUB void Mesh_Delete(Mesh* mesh); +Mesh* Mesh_Get(MeshHandle handle); +void Geometry_Destroy(Geometry* geometry); +MeshHandle Mesh_Insert(Mesh* mesh); +void Mesh_DebugPrint(Mesh* mesh); +MaterialHandle Material_Insert(Material* material); + +/** @brief gets render entities from a model and pushes them into a dynamic array for rendering */ +size_t ModelExtractRenderEnts(RenderEnt_darray* entities, ModelHandle model_handle, Mat4 affine, + RenderEntityFlags flags); + +// --- Drawing + +// NOTE: These functions use the globally bound camera in RenderScene +PUB void DrawMesh(Mesh* mesh, Material* material, Mat4 model); + +/** @brief the renderer does some internal bookkeeping for terrain so we use the terrain + stored on the Renderer rather than accept it as a parameter */ +PUB void Render_DrawTerrain(); + +// --- Getters (not in love with this but I'm finding keeping Renderer internals private to be okay) +arena* GetRenderFrameArena(Renderer* r); + +typedef struct RenderScene RenderScene; +typedef struct Shadow_Storage Shadow_Storage; +typedef struct Terrain_Storage Terrain_Storage; + +RenderScene* Render_GetScene(); +Shadow_Storage* Render_GetShadowStorage(); +Terrain_Storage* Render_GetTerrainStorage(); +Grid_Storage* Render_GetGridStorage(); +Immdraw_Storage* Render_GetImmdrawStorage(); +TextureHandle Render_GetWhiteTexture(); +arena* Render_GetFrameArena(); +Mesh_pool* Render_GetMeshPool(); +Material_pool* Render_GetMaterialPool(); + +// --- Setters +void Render_SetRenderMode(RenderMode mode); + +// ------------------------------------------------- + +// Frame lifecycle on CPU + +// 1. extract +// 2. culling +// 3. render +// 4. dispatch (combined with render for now) + +// typedef struct Cull_Result { +// u64 n_visible_objects; +// u64 n_culled_objects; +// u32* visible_ent_indices; // allocated on frame arena +// size_t index_count; +// } Cull_Result; + +// // everything that can be in the world, knows how to extract rendering data +// typedef void (*ExtractRenderData)(void* world_data); + +// typedef struct Renderer Renderer; + +// /** @brief Produces a smaller set of only those meshes visible in the camera frustum on the CPU +// */ Cull_Result Frame_Cull(Renderer* ren, RenderEnt* entities, size_t entity_count, Camera* +// camera); + +// Cull_Result Frame_Cull(Renderer* ren, RenderEnt* entities, size_t entity_count, Camera* camera) { +// // TODO: u32 chunk_count = Tpool_GetNumWorkers(); + +// arena* frame_arena = GetRenderFrameArena(ren); + +// Cull_Result result = { 0 }; +// result.visible_ent_indices = arena_alloc( +// frame_arena, sizeof(u32) * entity_count); // make space for if all ents are visible + +// assert((result.n_visible_objects + result.n_culled_objects == entity_count)); +// return result; +// } diff --git a/src/archive/src/render/render_types.h b/src/archive/src/render/render_types.h new file mode 100644 index 0000000..bdf9849 --- /dev/null +++ b/src/archive/src/render/render_types.h @@ -0,0 +1,138 @@ +/** + * @brief + */ + +#pragma once +#include "animation.h" +#include "defines.h" +#include "maths_types.h" +#include "mem.h" +#include "ral_types.h" + +// --- Handles + +#define INVALID_MODEL_HANDLE ((ModelHandle){ .raw = 9999991 }) +#define INVALID_MATERIAL_HANDLE ((MaterialHandle){ .raw = 9999992 }) +#define INVALID_MESH_HANDLE ((MeshHandle){ .raw = 9999993 }) + +typedef enum RenderMode { + RENDER_MODE_DEFAULT, + RENDER_MODE_WIREFRAME, + RENDER_MODE_WIREFRAME_ON_LIT, + RENDER_MODE_COUNT +} RenderMode; + +typedef struct u32_opt { + u32 value; + bool has_value; +} u32_opt; + +typedef struct Mesh { + BufferHandle vertex_buffer; + BufferHandle index_buffer; + Geometry geometry; // NULL means it has been freed CPU-side + MaterialHandle material; + bool is_skinned; // false = its static + Armature armature; + bool is_uploaded; // has the data been uploaded to the GPU +} Mesh; +#ifndef TYPED_MESH_CONTAINERS +KITC_DECL_TYPED_ARRAY(Mesh) +TYPED_POOL(Mesh, Mesh) +#define TYPED_MESH_CONTAINERS +#endif + +typedef struct TextureData { + TextureDesc description; + void* image_data; +} TextureData; + +// --- Supported materials +typedef enum MaterialKind { + MAT_BLINN_PHONG, // NOTE: we're dropping support for this + MAT_PBR, // uses textures for PBR properties + MAT_PBR_PARAMS, // uses float values to represent a surface uniformly + MAT_COUNT +} MaterialKind; +static const char* material_kind_names[] = { "Blinn Phong", "PBR (Textures)", "PBR (Params)", + "Count (This should be an error)" }; + +/** + * @brief + * @note based on https://google.github.io/filament/Filament.html#materialsystem/standardmodel + */ +typedef struct Material { + char name[64]; + MaterialKind kind; // at the moment all materials are PBR materials + Vec3 base_colour; // linear RGB {0,0,0} to {1,1,1} + f32 metallic; + f32 roughness; + f32 ambient_occlusion; + TextureHandle albedo_map; + TextureHandle normal_map; + TextureHandle metallic_roughness_map; + TextureHandle ambient_occlusion_map; +} Material; + +#ifndef TYPED_MATERIAL_CONTAINERS +KITC_DECL_TYPED_ARRAY(Material) +TYPED_POOL(Material, Material) +#define TYPED_MATERIAL_CONTAINERS +#endif + +/** @brief Convenient wrapper around a number of meshes each with a material */ +typedef struct Model { + Str8 name; + MeshHandle* meshes; + size_t mesh_count; + MaterialHandle* materials; + size_t material_count; + arena anim_arena; + AnimationClip_darray* animations; +} Model; +#ifndef TYPED_MODEL_ARRAY +KITC_DECL_TYPED_ARRAY(Model) +#define TYPED_MODEL_ARRAY +#endif + +// TODO: function to create a model from a single mesh (like when using primitives) + +// --- Lights +typedef struct PointLight { + Vec3 position; + f32 constant, linear, quadratic; + Vec3 ambient; + Vec3 diffuse; + Vec3 specular; +} PointLight; + +typedef struct DirectionalLight { + Vec3 direction; + Vec3 ambient; + Vec3 diffuse; + Vec3 specular; +} DirectionalLight; + +// --- + +typedef enum RenderEntityFlag { + REND_ENT_CASTS_SHADOWS = 1 << 0, + REND_ENT_VISIBLE = 1 << 1, +} RenderEntityFlag; +typedef u32 RenderEntityFlags; + +/** @brief A renderable 'thing' */ +typedef struct RenderEnt { + MeshHandle mesh; + MaterialHandle material; + /** If NULL, no armature and the mesh is static geometry, else it is to be skinned */ + Armature* armature; + Mat4 affine; // In the future this should be updated by the transform graph + Bbox_3D bounding_box; + RenderEntityFlags flags; +} RenderEnt; + +#ifndef TYPED_RENDERENT_ARRAY +KITC_DECL_TYPED_ARRAY(RenderEnt) +#define TYPED_RENDERENT_ARRAY +#endif diff --git a/src/archive/src/render/shader_layouts.h b/src/archive/src/render/shader_layouts.h new file mode 100644 index 0000000..ef94c89 --- /dev/null +++ b/src/archive/src/render/shader_layouts.h @@ -0,0 +1,70 @@ +#pragma once +#include "maths_types.h" +#include "ral_types.h" + +/** @brief shader layout for camera matrices */ +typedef struct Binding_Camera { + Mat4 view; + Mat4 projection; + Vec4 viewPos; +} Binding_Camera; + +typedef struct Binding_Model { + Mat4 model; +} Binding_Model; + +/** @brief data that is handy to have in any shader */ +typedef struct Binding_Globals { +} Binding_Globals; + +typedef struct pbr_point_light { + Vec3 pos; + f32 pad; + Vec3 color; + f32 pad2; +} pbr_point_light; + +typedef struct Binding_Lights { + pbr_point_light pointLights[4]; +} Binding_Lights; + +static ShaderDataLayout Binding_Camera_GetLayout(void* data) { + Binding_Camera* d = data; + bool has_data = data != NULL; + + ShaderBinding b1 = { .label = "Camera", + .kind = BINDING_BYTES, + .data.bytes = { .size = sizeof(Binding_Camera) } }; + if (has_data) { + b1.data.bytes.data = d; + } + return (ShaderDataLayout){ .bindings = { b1 }, .binding_count = 1 }; +} + +static ShaderDataLayout Binding_Model_GetLayout(void* data) { + Binding_Model* d = data; + bool has_data = data != NULL; + + ShaderBinding b1 = { .label = "Model", + .kind = BINDING_BYTES, + .vis = VISIBILITY_VERTEX, + .data.bytes = { .size = sizeof(Binding_Model) } }; + if (has_data) { + b1.data.bytes.data = d; + } + return (ShaderDataLayout){ .bindings = { b1 }, .binding_count = 1 }; +} + +static ShaderDataLayout Binding_Lights_GetLayout(void* data) { + Binding_Lights* d = data; + bool has_data = data != NULL; + + ShaderBinding b1 = { .label = "Lights", + .kind = BINDING_BYTES, + .vis = VISIBILITY_FRAGMENT, + .data.bytes = { .size = sizeof(Binding_Lights) } }; + if (has_data) { + b1.data.bytes.data = d; + } + return (ShaderDataLayout){ .bindings = { b1 }, .binding_count = 1 }; +} diff --git a/src/archive/src/render/shadows.c b/src/archive/src/render/shadows.c new file mode 100644 index 0000000..029eefb --- /dev/null +++ b/src/archive/src/render/shadows.c @@ -0,0 +1,211 @@ +#include "shadows.h" +#include +#include "file.h" +#include "glad/glad.h" +#include "log.h" +#include "maths.h" +#include "maths_types.h" +#include "primitives.h" +#include "ral_common.h" +#include "ral_impl.h" +#include "ral_types.h" +#include "render.h" +#include "render_types.h" +#include "str.h" + +ShaderDataLayout ShadowUniforms_GetLayout(void* data) { + ShadowUniforms* d = (ShadowUniforms*)data; + bool has_data = data != NULL; + + ShaderBinding b1 = { + .label = "ShadowUniforms", + .kind = BINDING_BYTES, + .vis = VISIBILITY_VERTEX, + .data = { .bytes = { .size = sizeof(ShadowUniforms) } } + // TODO: split this into two bindings so we can update model matrix independently + }; + + if (has_data) { + b1.data.bytes.data = data; + } + + return (ShaderDataLayout){ .binding_count = 1, .bindings = { b1 } }; +} + +ShaderDataLayout ShadowDebugQuad_GetLayout(void* data) { + TextureHandle* handle = data; + bool has_data = data != NULL; + + ShaderBinding b1 = { + .label = "depthMap", + .kind = BINDING_TEXTURE, + .vis = VISIBILITY_FRAGMENT, + }; + + if (has_data) { + b1.data.texture.handle = *handle; + } + + return (ShaderDataLayout){ .binding_count = 1, .bindings = { b1 } }; +} + +void Shadow_Init(Shadow_Storage* storage, u32 shadowmap_width, u32 shadowmap_height) { + memset(storage, 0, sizeof(Shadow_Storage)); + arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024); + + TextureDesc depthmap_desc = { .extents = u32x2(shadowmap_width, shadowmap_height), + .format = TEXTURE_FORMAT_DEPTH_DEFAULT, + .tex_type = TEXTURE_TYPE_2D }; + DEBUG("Creating depth map texture for shadows"); + TextureHandle depthmap = GPU_TextureCreate(depthmap_desc, false, NULL); + storage->depth_texture = depthmap; + + // -- shadowmap drawing pass + GPU_RenderpassDesc rpass_desc = { .default_framebuffer = false, + .has_color_target = false, + .has_depth_stencil = true, + .depth_stencil = depthmap }; + + storage->shadowmap_pass = GPU_Renderpass_Create(rpass_desc); + + WARN("About to laod shaders"); + WARN("Shader paths: %s %s", "assets/shaders/shadows.vert", "assets/shaders/shadows.frag"); + Str8 vert_path = str8("assets/shaders/shadows.vert"); + Str8 frag_path = str8("assets/shaders/shadows.frag"); + str8_opt vertex_shader = str8_from_file(&scratch, vert_path); + str8_opt fragment_shader = str8_from_file(&scratch, frag_path); + if (!vertex_shader.has_value || !fragment_shader.has_value) { + ERROR_EXIT("Failed to load shaders from disk"); + } + + ShaderDataLayout uniforms = ShadowUniforms_GetLayout(NULL); + + GraphicsPipelineDesc pipeline_desc = { + .debug_name = "Shadows Pipeline", + .vertex_desc = static_3d_vertex_description(), + .data_layouts = { uniforms }, + .data_layouts_count = 1, + .vs = { .debug_name = "Shadows Vert shader", + .filepath = vert_path, + .code = vertex_shader.contents, + .is_spirv = false }, + .fs = { .debug_name = "Shadows Frag shader", + .filepath = frag_path, + .code = fragment_shader.contents, + .is_spirv = false }, + }; + storage->shadowmap_pipeline = GPU_GraphicsPipeline_Create(pipeline_desc, storage->shadowmap_pass); + + // -- debug quad pipeline + GPU_RenderpassDesc debug_pass_desc = { .default_framebuffer = true }; + storage->debugquad_pass = GPU_Renderpass_Create(debug_pass_desc); + + vert_path = str8("assets/shaders/debug_quad.vert"); + frag_path = str8("assets/shaders/debug_quad.frag"); + vertex_shader = str8_from_file(&scratch, vert_path); + fragment_shader = str8_from_file(&scratch, frag_path); + if (!vertex_shader.has_value || !fragment_shader.has_value) { + ERROR_EXIT("Failed to load shaders from disk"); + } + + ShaderDataLayout debugquad_uniforms = ShadowDebugQuad_GetLayout(NULL); + + GraphicsPipelineDesc debugquad_pipeline_desc = { + .debug_name = "Shadows debug quad Pipeline", + .vertex_desc = static_3d_vertex_description(), + .data_layouts = { debugquad_uniforms }, + .data_layouts_count = 1, + .vs = { .debug_name = "depth debug quad vert shader", + .filepath = vert_path, + .code = vertex_shader.contents, + .is_spirv = false }, + .fs = { .debug_name = "depth debug quad frag shader", + .filepath = frag_path, + .code = fragment_shader.contents, + .is_spirv = false }, + }; + storage->debugquad_pipeline = + GPU_GraphicsPipeline_Create(debugquad_pipeline_desc, storage->debugquad_pass); + + Geometry quad_geo = Geo_CreatePlane(f32x2(1, 1), 1, 1); + // HACK: Swap vertices to make it face us + Vertex top0 = quad_geo.vertices->data[0]; + quad_geo.vertices->data[0] = quad_geo.vertices->data[2]; + quad_geo.vertices->data[2] = top0; + Vertex top1 = quad_geo.vertices->data[1]; + quad_geo.vertices->data[1] = quad_geo.vertices->data[3]; + quad_geo.vertices->data[3] = top1; + storage->quad = Mesh_Create(&quad_geo, false); + + arena_free_storage(&scratch); +} + +void Shadow_Run(RenderEnt* entities, size_t entity_count) { + Shadow_Storage* shadow_storage = Render_GetShadowStorage(); + + // calculations + RenderScene* render_scene = Render_GetScene(); + f32 near_plane = 1.0, far_plane = 10.0; + // -- Not sure about how we want to handle lights + Vec3 light_position = { 1, 4, -1 }; + // -- + Mat4 light_projection = mat4_orthographic(-10.0, 10.0, -10.0, 10.0, near_plane, far_plane); + Mat4 light_view = mat4_look_at(light_position, VEC3_ZERO, VEC3_Y); + Mat4 light_space_matrix = mat4_mult(light_view, light_projection); + + Shadow_ShadowmapExecute(shadow_storage, light_space_matrix, entities, entity_count); +} + +void Shadow_DrawDebugQuad() { + Shadow_Storage* shadow_storage = Render_GetShadowStorage(); + + GPU_CmdEncoder* enc = GPU_GetDefaultEncoder(); + GPU_CmdEncoder_BeginRender(enc, shadow_storage->debugquad_pass); + + GPU_EncodeBindPipeline(enc, shadow_storage->debugquad_pipeline); + ShaderDataLayout quad_data = ShadowDebugQuad_GetLayout(&shadow_storage->depth_texture); + GPU_EncodeBindShaderData(enc, 0, quad_data); + GPU_EncodeSetVertexBuffer(enc, shadow_storage->quad.vertex_buffer); + GPU_EncodeSetIndexBuffer(enc, shadow_storage->quad.index_buffer); + GPU_EncodeDrawIndexedTris(enc, shadow_storage->quad.geometry.indices->len); + + GPU_CmdEncoder_EndRender(enc); +} + +void Shadow_ShadowmapExecute(Shadow_Storage* storage, Mat4 light_space_transform, + RenderEnt* entities, size_t entity_count) { + GPU_CmdEncoder shadow_encoder = GPU_CmdEncoder_Create(); + + GPU_CmdEncoder_BeginRender(&shadow_encoder, storage->shadowmap_pass); + // DEBUG("Begin shadowmap renderpass"); + + // FIXME: shouldnt be gl specific + glClear(GL_DEPTH_BUFFER_BIT); + + GPU_EncodeBindPipeline(&shadow_encoder, storage->shadowmap_pipeline); + + ShadowUniforms uniforms = { + .light_space = light_space_transform, + .model = mat4_ident() // this will be overwritten for each Model + }; + ShaderDataLayout shader_data = ShadowUniforms_GetLayout(&uniforms); + + for (size_t ent_i = 0; ent_i < entity_count; ent_i++) { + RenderEnt renderable = entities[ent_i]; + if (renderable.flags && REND_ENT_CASTS_SHADOWS) { + // Model* model = MODEL_GET(renderable.model); + + uniforms.model = renderable.affine; // update the model transform + + Mesh* mesh = Mesh_pool_get(Render_GetMeshPool(), renderable.mesh); + GPU_EncodeBindShaderData(&shadow_encoder, 0, shader_data); + GPU_EncodeSetVertexBuffer(&shadow_encoder, mesh->vertex_buffer); + GPU_EncodeSetIndexBuffer(&shadow_encoder, mesh->index_buffer); + GPU_EncodeDrawIndexedTris(&shadow_encoder, mesh->geometry.indices->len); + } + } + + GPU_CmdEncoder_EndRender(&shadow_encoder); // end renderpass +} + +TextureHandle Shadow_GetShadowMapTexture(Shadow_Storage* storage) { return storage->depth_texture; } diff --git a/src/archive/src/render/shadows.h b/src/archive/src/render/shadows.h new file mode 100644 index 0000000..0482d10 --- /dev/null +++ b/src/archive/src/render/shadows.h @@ -0,0 +1,48 @@ +/** + * @brief Functions for adding shadows to scene rendering. + */ + +#pragma once +#include "defines.h" +#include "ral_impl.h" +#include "ral_types.h" +#include "render_types.h" + +typedef struct Shadow_Storage { + bool enabled; + GPU_Renderpass* shadowmap_pass; + GPU_Pipeline* shadowmap_pipeline; + TextureHandle depth_texture; + bool debug_quad_enabled; + Mesh quad; + GPU_Renderpass* debugquad_pass; + GPU_Pipeline* debugquad_pipeline; + // TODO: Some statistics tracking +} Shadow_Storage; + +typedef struct ShadowUniforms { + Mat4 light_space; + Mat4 model; +} ShadowUniforms; + +typedef struct Camera Camera; +typedef struct Mat4 Mat4; + +// --- Public API +PUB void Shadow_Init(Shadow_Storage* storage, u32 shadowmap_width, u32 shadowmap_height); + +/** @brief Run shadow map generation for given entities, and store in a texture. + * @note Uses active directional light for now */ +PUB void Shadow_Run(RenderEnt* entities, size_t entity_count); + +PUB void Shadow_DrawDebugQuad(); + +/** @brief Get the shadow texture generated from shadowmap pass */ +PUB TextureHandle Shadow_GetShadowMapTexture(Shadow_Storage* storage); + +// --- Internal +GPU_Renderpass* Shadow_RPassCreate(); // Creates the render pass +GPU_Pipeline* Shadow_PipelineCreate(GPU_Renderpass* rpass); // Creates the pipeline +void Shadow_ShadowmapExecute(Shadow_Storage* storage, Mat4 light_space_transform, + RenderEnt* entities, size_t entity_count); +void Shadow_RenderDebugQuad(); diff --git a/src/archive/src/render/skybox.c b/src/archive/src/render/skybox.c new file mode 100644 index 0000000..b4e1e42 --- /dev/null +++ b/src/archive/src/render/skybox.c @@ -0,0 +1,161 @@ +#include "skybox.h" +#include +#include "file.h" +#include "glad/glad.h" +#include "log.h" +#include "maths.h" +#include "primitives.h" +#include "ral_common.h" +#include "ral_impl.h" +#include "ral_types.h" +#include "render.h" +#include "render_types.h" +#include "shader_layouts.h" + +float skyboxVertices[] = { + // positions + -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, + 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, + + -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, + -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, + + 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, + + -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, + + -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, + + -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, + 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f +}; + +static const char* faces[6] = { "assets/demo/skybox/right.jpg", "assets/demo/skybox/left.jpg", + "assets/demo/skybox/top.jpg", "assets/demo/skybox/bottom.jpg", + "assets/demo/skybox/front.jpg", "assets/demo/skybox/back.jpg" }; + +Skybox Skybox_Create(const char** face_paths, int n) { + INFO("Creating a skybox"); + CASSERT_MSG( + n == 6, + "We only support full cubemaps for now"); // ! we're only supporting a full cubemap for now + + // -- cube verts + Geometry geom = { .format = VERTEX_POS_ONLY, // doesnt matter + .has_indices = false, + .indices = NULL, + .vertices = Vertex_darray_new(36) }; + for (u32 i = 0; i < (36 * 3); i += 3) { + Vertex_darray_push( + geom.vertices, + (Vertex){ .pos_only = { .position = vec3(skyboxVertices[i], skyboxVertices[i + 1], + skyboxVertices[i + 2]) } }); + } + Mesh cube = Mesh_Create(&geom, false); + + // -- cubemap texture + TextureHandle handle; + GPU_Texture* tex = GPU_TextureAlloc(&handle); + glBindTexture(GL_TEXTURE_CUBE_MAP, tex->id); + + for (unsigned int i = 0; i < n; i++) { + TextureData data = TextureDataLoad(face_paths[i], false); + assert(data.description.format == TEXTURE_FORMAT_8_8_8_RGB_UNORM); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, data.description.extents.x, + data.description.extents.y, 0, GL_RGB, GL_UNSIGNED_BYTE, data.image_data); + } + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + // shader pipeline + GPU_RenderpassDesc rpass_desc = { + .default_framebuffer = true, + }; + GPU_Renderpass* pass = GPU_Renderpass_Create(rpass_desc); + + arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024); + + Str8 vert_path = str8("assets/shaders/skybox.vert"); + Str8 frag_path = str8("assets/shaders/skybox.frag"); + str8_opt vertex_shader = str8_from_file(&scratch, vert_path); + str8_opt fragment_shader = str8_from_file(&scratch, frag_path); + if (!vertex_shader.has_value || !fragment_shader.has_value) { + ERROR_EXIT("Failed to load shaders from disk") + } + + ShaderDataLayout camera_data = Binding_Camera_GetLayout(NULL); + ShaderDataLayout shader_data = Skybox_GetLayout(NULL); + + VertexDescription builder = { .debug_label = "pos only" }; + VertexDesc_AddAttr(&builder, "inPosition", ATTR_F32x3); + builder.use_full_vertex_size = true; + + GraphicsPipelineDesc pipeline_desc = { + .debug_name = "Skybox pipeline", + .vertex_desc = builder, + .data_layouts = { shader_data, camera_data }, + .data_layouts_count = 2, + .vs = { .debug_name = "Skybox Vertex Shader", + .filepath = vert_path, + .code = vertex_shader.contents }, + .fs = { .debug_name = "Skybox Fragment Shader", + .filepath = frag_path, + .code = fragment_shader.contents }, + .wireframe = false, + .depth_test = true, + }; + + GPU_Pipeline* pipeline = GPU_GraphicsPipeline_Create(pipeline_desc, pass); + + return (Skybox){ .cube = cube, .texture = handle, .pipeline = pipeline }; +} + +Skybox Skybox_Default() { return Skybox_Create(faces, 6); } + +void Skybox_Draw(Skybox* skybox, Camera camera) { + GPU_CmdEncoder* enc = GPU_GetDefaultEncoder(); + glDepthFunc(GL_LEQUAL); + GPU_CmdEncoder_BeginRender(enc, skybox->pipeline->renderpass); + GPU_EncodeBindPipeline(enc, skybox->pipeline); + GPU_EncodeSetDefaults(enc); + + // Shader data + + Mat4 view, proj; + u32x2 dimensions = GPU_Swapchain_GetDimensions(); + Camera_ViewProj(&camera, dimensions.x, dimensions.y, &view, &proj); + Mat4 new = mat4_ident(); + new.data[0] = view.data[0]; + new.data[1] = view.data[1]; + new.data[2] = view.data[2]; + new.data[4] = view.data[4]; + new.data[5] = view.data[5]; + new.data[6] = view.data[6]; + new.data[8] = view.data[8]; + new.data[9] = view.data[9]; + new.data[10] = view.data[10]; + + Binding_Camera camera_data = { .view = new, + .projection = proj, + .viewPos = vec4(camera.position.x, camera.position.y, + camera.position.z, 1.0) }; + GPU_EncodeBindShaderData(enc, 0, Binding_Camera_GetLayout(&camera_data)); + + SkyboxUniforms uniforms = { .cubemap = skybox->texture }; + ShaderDataLayout skybox_data = Skybox_GetLayout(&uniforms); + GPU_EncodeBindShaderData(enc, 0, skybox_data); + + GPU_EncodeSetVertexBuffer(enc, skybox->cube.vertex_buffer); + GPU_EncodeSetIndexBuffer(enc, skybox->cube.index_buffer); + + GPU_EncodeDrawTris(enc, 36); + + GPU_CmdEncoder_EndRender(enc); + glDepthFunc(GL_LESS); +} diff --git a/src/archive/src/render/skybox.h b/src/archive/src/render/skybox.h new file mode 100644 index 0000000..c2ef3a2 --- /dev/null +++ b/src/archive/src/render/skybox.h @@ -0,0 +1,41 @@ +/** + * @brief + */ + +#pragma once +#include "camera.h" +#include "defines.h" +#include "ral_impl.h" +#include "render_types.h" + +typedef struct Skybox { + Mesh cube; + TextureHandle texture; + GPU_Pipeline* pipeline; // "shader" +} Skybox; + +PUB Skybox Skybox_Create(const char** face_paths, int n); // should always pass n = 6 for now + +PUB void Skybox_Draw(Skybox* skybox, Camera camera); + +typedef struct SkyboxUniforms { + TextureHandle cubemap; +} SkyboxUniforms; + +static ShaderDataLayout Skybox_GetLayout(void* data) { + SkyboxUniforms* d = (SkyboxUniforms*)data; // cold cast + bool has_data = data != NULL; + + ShaderBinding b1 = { + .label = "cubeMap", + .vis = VISIBILITY_FRAGMENT, + .kind = BINDING_TEXTURE, + }; + + if (has_data) { + b1.data.texture.handle = d->cubemap; + } + return (ShaderDataLayout){ .bindings = { b1 }, .binding_count = 1 }; +} + +Skybox Skybox_Default(); \ No newline at end of file diff --git a/src/archive/src/resources/gltf.c b/src/archive/src/resources/gltf.c new file mode 100644 index 0000000..66ae1b6 --- /dev/null +++ b/src/archive/src/resources/gltf.c @@ -0,0 +1,596 @@ +#include +#include +#include +#include "animation.h" +#include "colours.h" +#include "core.h" +#include "defines.h" +#include "file.h" +#include "loaders.h" +#include "log.h" +#include "maths.h" +#include "maths_types.h" +#include "mem.h" +#include "pbr.h" +#include "platform.h" +#include "ral_types.h" +#include "render.h" +#include "render_types.h" +#include "str.h" + +#define CGLTF_IMPLEMENTATION +#include + +extern Core g_core; + +/* GLTF Loading Pipeline + ===================== */ + +struct face { + cgltf_uint indices[3]; +}; +typedef struct face face; + +KITC_DECL_TYPED_ARRAY(Vec3) +KITC_DECL_TYPED_ARRAY(Vec2) +KITC_DECL_TYPED_ARRAY(Vec4u) +KITC_DECL_TYPED_ARRAY(Vec4i) +KITC_DECL_TYPED_ARRAY(Vec4) +KITC_DECL_TYPED_ARRAY(face) +KITC_DECL_TYPED_ARRAY(i32) + +size_t GLTF_LoadMaterials(cgltf_data* data, Str8 relative_path, Material_darray* out_materials); + +ModelHandle ModelLoad_gltf(const char* path, bool invert_texture_y) { + size_t arena_size = MB(1); + arena scratch = arena_create(malloc(arena_size), arena_size); + + TRACE("Loading model at Path %s\n", path); + path_opt relative_path = path_parent(&scratch, path); + if (!relative_path.has_value) { + WARN("Couldnt get a relative path for the path to use for loading materials & textures later"); + } + const char* file_string = string_from_file(path); + + ModelHandle handle; + Model* model = Model_pool_alloc(&g_core.models, &handle); + model->name = Str8_cstr_view(path); + + bool success = + model_load_gltf_str(file_string, path, relative_path.path, model, invert_texture_y); + + if (!success) { + FATAL("Couldnt load GLTF file at path %s", path); + ERROR_EXIT("Load fails are considered crash-worthy right now. This will change later.\n"); + } + + arena_free_all(&scratch); + arena_free_storage(&scratch); + return handle; +} + +void assert_path_type_matches_component_type(cgltf_animation_path_type target_path, + cgltf_accessor* output) { + if (target_path == cgltf_animation_path_type_rotation) { + assert(output->component_type == cgltf_component_type_r_32f); + assert(output->type == cgltf_type_vec4); + } +} + +// TODO: Brainstorm how I can make this simpler and break it up into more testable pieces + +void load_position_components(Vec3_darray* positions, cgltf_accessor* accessor) { + TRACE("Loading %d vec3 position components", accessor->count); + CASSERT_MSG(accessor->component_type == cgltf_component_type_r_32f, + "Positions components are floats"); + CASSERT_MSG(accessor->type == cgltf_type_vec3, "Vertex positions should be a vec3"); + + for (cgltf_size v = 0; v < accessor->count; ++v) { + Vec3 pos; + cgltf_accessor_read_float(accessor, v, &pos.x, 3); + Vec3_darray_push(positions, pos); + } +} + +void load_normal_components(Vec3_darray* normals, cgltf_accessor* accessor) { + TRACE("Loading %d vec3 normal components", accessor->count); + CASSERT_MSG(accessor->component_type == cgltf_component_type_r_32f, + "Normal vector components are floats"); + CASSERT_MSG(accessor->type == cgltf_type_vec3, "Vertex normals should be a vec3"); + + for (cgltf_size v = 0; v < accessor->count; ++v) { + Vec3 pos; + cgltf_accessor_read_float(accessor, v, &pos.x, 3); + Vec3_darray_push(normals, pos); + } +} + +void load_texcoord_components(Vec2_darray* texcoords, cgltf_accessor* accessor) { + TRACE("Load texture coordinates from accessor"); + CASSERT(accessor->component_type == cgltf_component_type_r_32f); + CASSERT_MSG(accessor->type == cgltf_type_vec2, "Texture coordinates should be a vec2"); + + for (cgltf_size v = 0; v < accessor->count; ++v) { + Vec2 tex; + bool success = cgltf_accessor_read_float(accessor, v, &tex.x, 2); + if (!success) { + ERROR("Error loading tex coord"); + } + Vec2_darray_push(texcoords, tex); + } +} + +void load_joint_index_components(Vec4i_darray* joint_indices, cgltf_accessor* accessor) { + TRACE("Load joint indices from accessor"); + CASSERT(accessor->component_type == cgltf_component_type_r_16u); + CASSERT_MSG(accessor->type == cgltf_type_vec4, "Joint indices should be a vec4"); + Vec4i tmp_joint_index; + Vec4 joints_as_floats; + for (cgltf_size v = 0; v < accessor->count; ++v) { + cgltf_accessor_read_float(accessor, v, &joints_as_floats.x, 4); + tmp_joint_index.x = (u32)joints_as_floats.x; + tmp_joint_index.y = (u32)joints_as_floats.y; + tmp_joint_index.z = (u32)joints_as_floats.z; + tmp_joint_index.w = (u32)joints_as_floats.w; + printf("Joints affecting vertex %d : %d %d %d %d\n", v, tmp_joint_index.x, tmp_joint_index.y, + tmp_joint_index.z, tmp_joint_index.w); + Vec4i_darray_push(joint_indices, tmp_joint_index); + } +} + +bool model_load_gltf_str(const char* file_string, const char* filepath, Str8 relative_path, + Model* out_model, bool invert_textures_y) { + TRACE("Load GLTF from string"); + + // Setup temps + Vec3_darray* tmp_positions = Vec3_darray_new(1000); + Vec3_darray* tmp_normals = Vec3_darray_new(1000); + Vec2_darray* tmp_uvs = Vec2_darray_new(1000); + Vec4i_darray* tmp_joint_indices = Vec4i_darray_new(1000); + Vec4_darray* tmp_weights = Vec4_darray_new(1000); + Material_darray* tmp_materials = Material_darray_new(1); + Mesh_darray* tmp_meshes = Mesh_darray_new(1); + i32_darray* tmp_material_indexes = i32_darray_new(1); + + Joint_darray* joints = Joint_darray_new(256); + + cgltf_options options = { 0 }; + cgltf_data* data = NULL; + cgltf_result result = cgltf_parse_file(&options, filepath, &data); + if (result != cgltf_result_success) { + WARN("gltf load failed"); + // TODO: cleanup arrays(allocate all from arena ?) + return false; + } + + cgltf_load_buffers(&options, data, filepath); + DEBUG("loaded buffers"); + + // --- Skin + size_t num_skins = data->skins_count; + bool is_skinned = false; + Armature main_skeleton = { 0 }; + if (num_skins == 1) { + is_skinned = true; + } else if (num_skins > 1) { + WARN("GLTF files with more than 1 skin are not supported"); + return false; + } + + if (is_skinned) { + cgltf_skin* gltf_skin = data->skins; + DEBUG("loading skin %s", gltf_skin->name); + size_t num_joints = gltf_skin->joints_count; + DEBUG("# Joints %d", num_joints); + + // Create our data that will be placed onto the model + Armature armature = { .label = "test_skin" }; + printf("Skin %s\n", gltf_skin->name); + // armature.label = Clone_cstr(&armature.arena, gltf_skin->name); + armature.joints = joints; // ! Make sure not to free this + + cgltf_accessor* gltf_inverse_bind_matrices = gltf_skin->inverse_bind_matrices; + + // --- Joints + // for each one we'll spit out a joint + for (size_t i = 0; i < num_joints; i++) { + // Get the joint and assign its node index for later referencing + cgltf_node* joint_node = gltf_skin->joints[i]; + TRACE("Joint %d (node index %d)", i, cgltf_node_index(data, joint_node)); + Joint joint_i = { .debug_label = "test_joint", + .node_idx = cgltf_node_index(data, joint_node), + .inverse_bind_matrix = mat4_ident() }; + + if (joint_node->children_count > 0 && !joint_node->has_translation && + !joint_node->has_rotation) { + WARN("Joint node with index %d is the root node", i); + joint_i.transform_components = TRANSFORM_DEFAULT; + joint_i.parent = -1; + for (u32 c_i = 0; c_i < joint_node->children_count; c_i++) { + joint_i.children[c_i] = cgltf_node_index(data, joint_node->children[c_i]); + joint_i.children_count++; + } + } else { + TRACE("Storing joint transform"); + joint_i.transform_components = TRANSFORM_DEFAULT; + if (joint_node->has_translation) { + memcpy(&joint_i.transform_components.position, &joint_node->translation, 3 * sizeof(f32)); + } + if (joint_node->has_rotation) { + memcpy(&joint_i.transform_components.rotation, &joint_node->rotation, 4 * sizeof(f32)); + } + if (joint_node->has_scale) { + memcpy(&joint_i.transform_components.scale, &joint_node->scale, 3 * sizeof(f32)); + } + joint_i.parent = cgltf_node_index(data, joint_node->parent); + } + // Calculate and store the starting transform of the joint + joint_i.local_transform = transform_to_mat(&joint_i.transform_components); + // Read in the inverse bind matrix + cgltf_accessor_read_float(gltf_inverse_bind_matrices, i, &joint_i.inverse_bind_matrix.data[0], + 16); + Joint_darray_push(armature.joints, joint_i); + } + main_skeleton = armature; + // out_model->armature = armature; + // out_model->has_joints = true; + } + + // --- Materials + size_t num_materials = GLTF_LoadMaterials(data, relative_path, tmp_materials); + + // --- Meshes + size_t num_meshes = data->meshes_count; + TRACE("Num meshes %d", num_meshes); + for (size_t m = 0; m < num_meshes; m++) { + printf("Primitive count %d\n", data->meshes[m].primitives_count); + for (size_t prim_i = 0; prim_i < data->meshes[m].primitives_count; prim_i++) { + DEBUG("Primitive %d\n", prim_i); + + cgltf_primitive primitive = data->meshes[m].primitives[prim_i]; + DEBUG("Found %d attributes", primitive.attributes_count); + + for (cgltf_size a = 0; a < primitive.attributes_count; a++) { + cgltf_attribute attribute = primitive.attributes[a]; + if (attribute.type == cgltf_attribute_type_position) { + cgltf_accessor* accessor = attribute.data; + load_position_components(tmp_positions, accessor); + } else if (attribute.type == cgltf_attribute_type_normal) { + cgltf_accessor* accessor = attribute.data; + load_normal_components(tmp_normals, accessor); + } else if (attribute.type == cgltf_attribute_type_texcoord) { + cgltf_accessor* accessor = attribute.data; + load_texcoord_components(tmp_uvs, accessor); + } else if (attribute.type == cgltf_attribute_type_joints) { + TRACE("Load joint indices from accessor"); + cgltf_accessor* accessor = attribute.data; + load_joint_index_components(tmp_joint_indices, accessor); + } else if (attribute.type == cgltf_attribute_type_weights) { + TRACE("Load joint weights from accessor"); + cgltf_accessor* accessor = attribute.data; + CASSERT(accessor->component_type == cgltf_component_type_r_32f); + CASSERT(accessor->type == cgltf_type_vec4); + + for (cgltf_size v = 0; v < accessor->count; ++v) { + Vec4 weights; + cgltf_accessor_read_float(accessor, v, &weights.x, 4); + printf("Weights affecting vertex %d : %f %f %f %f\n", v, weights.x, weights.y, + weights.z, weights.w); + Vec4_darray_push(tmp_weights, weights); + } + } else { + WARN("Unhandled cgltf_attribute_type: %s. skipping..", attribute.name); + } + } + // mesh.vertex_bone_data = vertex_bone_data_darray_new(1); + i32 mat_idx = -1; + if (primitive.material != NULL) { + DEBUG("Primitive Material %s", primitive.material->name); + // FIXME! + for (u32 i = 0; i < Material_darray_len(tmp_materials); i++) { + printf("%s vs %s \n", primitive.material->name, tmp_materials->data[i].name); + if (strcmp(primitive.material->name, tmp_materials->data[i].name) == 0) { + INFO("Found material"); + mat_idx = i; + i32_darray_push(tmp_material_indexes, mat_idx); + break; + } + } + } else { + i32_darray_push(tmp_material_indexes, -1); + } + + TRACE("Vertex data has been loaded"); + + Vertex_darray* geo_vertices = Vertex_darray_new(3); + u32_darray* geo_indices = u32_darray_new(0); + + // Store vertices + printf("Positions %d Normals %d UVs %d\n", tmp_positions->len, tmp_normals->len, + tmp_uvs->len); + // assert(tmp_positions->len == tmp_normals->len); + // assert(tmp_normals->len == tmp_uvs->len); + bool has_normals = tmp_normals->len > 0; + bool has_uvs = tmp_uvs->len > 0; + for (u32 v_i = 0; v_i < tmp_positions->len; v_i++) { + Vertex v = { 0 }; + if (is_skinned) { + v.skinned_3d.position = tmp_positions->data[v_i]; + v.skinned_3d.normal = has_normals ? tmp_normals->data[v_i] : VEC3_ZERO, + v.skinned_3d.tex_coords = has_uvs ? tmp_uvs->data[v_i] : vec2_create(0., 0.); + v.skinned_3d.bone_ids = tmp_joint_indices->data[v_i]; + v.skinned_3d.bone_weights = tmp_weights->data[v_i]; + } else { + v.static_3d.position = tmp_positions->data[v_i]; + v.static_3d.normal = has_normals ? tmp_normals->data[v_i] : VEC3_ZERO, + v.static_3d.tex_coords = has_uvs ? tmp_uvs->data[v_i] : vec2_create(0., 0.); + } + Vertex_darray_push(geo_vertices, v); + }; + + // Store indices + cgltf_accessor* indices = primitive.indices; + if (primitive.indices > 0) { + WARN("indices! %d", indices->count); + + // store indices + for (cgltf_size i = 0; i < indices->count; ++i) { + cgltf_uint ei; + cgltf_accessor_read_uint(indices, i, &ei, 1); + u32_darray_push(geo_indices, ei); + } + + Geometry* geometry = malloc(sizeof(Geometry)); + geometry->format = is_skinned ? VERTEX_SKINNED : VERTEX_STATIC_3D; + geometry->has_indices = true; + geometry->vertices = geo_vertices; + geometry->indices = geo_indices; + geometry->index_count = geo_indices->len; + + Mesh m = Mesh_Create(geometry, false); + if (is_skinned) { + m.is_skinned = true; + m.armature = main_skeleton; + } + Mesh_darray_push(tmp_meshes, m); + + Vec3_darray_clear(tmp_positions); + Vec3_darray_clear(tmp_normals); + Vec2_darray_clear(tmp_uvs); + Vec4i_darray_clear(tmp_joint_indices); + Vec4_darray_clear(tmp_weights); + } else { + WARN("No indices found. Ignoring mesh..."); + } + } + + // --- Animations + size_t num_animations = data->animations_count; + TRACE("Num animations %d", num_animations); + + if (num_animations > 0) { + if (!out_model->animations) { + out_model->animations = AnimationClip_darray_new(num_animations); + } + out_model->anim_arena = arena_create(malloc(MB(1)), MB(1)); + arena* arena = &out_model->anim_arena; + + // Iterate over each animation in the GLTF + for (int anim_idx = 0; anim_idx < data->animations_count; anim_idx++) { + cgltf_animation animation = data->animations[anim_idx]; + AnimationClip clip = { 0 }; + clip.clip_name = "test anim clip"; + clip.channels = AnimationSampler_darray_new(1); + + // for each animation, loop through all the channels + for (size_t c = 0; c < animation.channels_count; c++) { + cgltf_animation_channel channel = animation.channels[c]; + + AnimationSampler sampler = { 0 }; + + KeyframeKind data_type; + + switch (channel.target_path) { + case cgltf_animation_path_type_rotation: + data_type = KEYFRAME_ROTATION; + break; + case cgltf_animation_path_type_translation: + data_type = KEYFRAME_TRANSLATION; + break; + case cgltf_animation_path_type_scale: + data_type = KEYFRAME_SCALE; + break; + case cgltf_animation_path_type_weights: + data_type = KEYFRAME_WEIGHTS; + WARN("Morph target weights arent supported yet"); + return false; + default: + WARN("unsupported animation type"); + return false; + } + + sampler.current_index = 0; + sampler.animation.interpolation = INTERPOLATION_LINEAR; // NOTE: hardcoded for now + + // Keyframe times + size_t n_frames = channel.sampler->input->count; + CASSERT_MSG(channel.sampler->input->component_type == cgltf_component_type_r_32f, + "Expected animation sampler input component to be type f32"); + f32* times = arena_alloc(arena, n_frames * sizeof(f32)); + sampler.animation.n_timestamps = n_frames; + sampler.animation.timestamps = times; + cgltf_accessor_unpack_floats(channel.sampler->input, times, n_frames); + + // Keyframe values + size_t n_values = channel.sampler->output->count; + CASSERT_MSG(n_frames == n_values, "keyframe times = keyframe values"); + + Keyframes keyframes = { 0 }; + keyframes.kind = data_type; + keyframes.count = n_values; + keyframes.values = arena_alloc(arena, n_values * sizeof(Keyframe)); + for (cgltf_size v = 0; v < channel.sampler->output->count; ++v) { + switch (data_type) { + case KEYFRAME_ROTATION: { + Quat rot; + cgltf_accessor_read_float(channel.sampler->output, v, &rot.x, 4); + // printf("Quat %f %f %f %f\n", rot.x, rot.y, rot.z, rot.w); + keyframes.values[v].rotation = rot; + break; + } + case KEYFRAME_TRANSLATION: { + Vec3 trans; + cgltf_accessor_read_float(channel.sampler->output, v, &trans.x, 3); + keyframes.values[v].translation = trans; + break; + } + case KEYFRAME_SCALE: { + Vec3 scale; + cgltf_accessor_read_float(channel.sampler->output, v, &scale.x, 3); + keyframes.values[v].scale = scale; + break; + } + case KEYFRAME_WEIGHTS: { + // TODO: morph weights + break; + } + } + } + sampler.animation.values = keyframes; + sampler.min = channel.sampler->input->min[0]; + sampler.max = channel.sampler->input->max[0]; + + // *target_property = sampler; + printf("%d timestamps between %f and %f\n", sampler.animation.n_timestamps, sampler.min, + sampler.max); + + // TODO: get target + size_t target_index = cgltf_node_index(data, channel.target_node); + size_t joint_index = 0; + bool found = false; + for (u32 ji = 0; ji < main_skeleton.joints->len; ji++) { + if (main_skeleton.joints->data[ji].node_idx == target_index) { + joint_index = ji; + found = true; + break; + } + } + if (!found) { + WARN("Coulndnt find joint index"); + } + sampler.target_joint_idx = + joint_index; // NOTE: this assuming the target is a joint at the moment + AnimationSampler_darray_push(clip.channels, sampler); + } + + AnimationClip_darray_push(out_model->animations, clip); + } + } + + // exit(0); + } + + num_meshes = tmp_meshes->len; + + // we now have an array of meshes, materials, and the material which each mesh should get + out_model->meshes = malloc(num_meshes * sizeof(MeshHandle)); + out_model->mesh_count = num_meshes; + out_model->materials = malloc(num_materials * sizeof(MaterialHandle)); + out_model->material_count = num_materials; + + MaterialHandle* mat_handles = calloc(num_materials, sizeof(MaterialHandle)); + for (u32 mat_i = 0; mat_i < num_materials; mat_i++) { + mat_handles[mat_i] = + Material_pool_insert(Render_GetMaterialPool(), &tmp_materials->data[mat_i]); + } + memcpy(out_model->materials, mat_handles, num_materials * sizeof(MaterialHandle)); + + for (u32 mesh_i = 0; mesh_i < num_meshes; mesh_i++) { + i32 mat_idx = tmp_material_indexes->data[mesh_i]; + if (mat_idx > 0) { + tmp_meshes->data[mesh_i].material = mat_handles[mat_idx]; + + } else { + Material default_mat = PBRMaterialDefault(); + tmp_meshes->data[mesh_i].material = + Material_pool_insert(Render_GetMaterialPool(), &default_mat); + } + MeshHandle mesh = Mesh_pool_insert(Render_GetMeshPool(), &tmp_meshes->data[mesh_i]); + out_model->meshes[mesh_i] = mesh; + } + + free(mat_handles); + + return true; +} + +const char* bool_yes_no(bool pred) { return pred ? "Yes" : "No"; } + +// Loads all materials +size_t GLTF_LoadMaterials(cgltf_data* data, Str8 relative_path, Material_darray* out_materials) { + size_t num_materials = data->materials_count; + TRACE("Num materials %d", num_materials); + for (size_t m = 0; m < num_materials; m++) { + cgltf_material gltf_material = data->materials[m]; + TRACE("Loading material '%s'", gltf_material.name); + cgltf_pbr_metallic_roughness pbr = gltf_material.pbr_metallic_roughness; + + Material our_material = PBRMaterialDefault(); // focusing on PBR materials for now + + our_material.base_colour = + vec3(pbr.base_color_factor[0], pbr.base_color_factor[1], pbr.base_color_factor[2]); + our_material.metallic = pbr.metallic_factor; + our_material.roughness = pbr.roughness_factor; + + // -- albedo / base colour + cgltf_texture_view albedo_tex_view = pbr.base_color_texture; + bool has_albedo_texture = albedo_tex_view.texture != NULL; + TRACE("Has PBR base colour texture? %s", bool_yes_no(has_albedo_texture)); + printf("Base colour factor: %f %f %f\n", pbr.base_color_factor[0], pbr.base_color_factor[1], + pbr.base_color_factor[2]); + if (has_albedo_texture) { + char albedo_map_path[1024]; + snprintf(albedo_map_path, sizeof(albedo_map_path), "%s/%s", relative_path.buf, + albedo_tex_view.texture->image->uri); + our_material.albedo_map = TextureLoadFromFile(albedo_map_path); + } else { + our_material.albedo_map = Render_GetWhiteTexture(); + WARN("GLTF model has no albedo map"); + our_material.base_colour = + vec3_create(pbr.base_color_factor[0], pbr.base_color_factor[1], pbr.base_color_factor[2]); + } + + // -- metallic + cgltf_texture_view metal_rough_tex_view = pbr.metallic_roughness_texture; + printf("Metal factor: %f\n", pbr.metallic_factor); + printf("Roughness factor: %f\n", pbr.roughness_factor); + if (metal_rough_tex_view.texture != NULL) { + char metal_rough_map_path[1024]; + snprintf(metal_rough_map_path, sizeof(metal_rough_map_path), "%s/%s", relative_path.buf, + metal_rough_tex_view.texture->image->uri); + our_material.metallic_roughness_map = TextureLoadFromFile(metal_rough_map_path); + } else { + WARN("GLTF model has no metal/roughness map"); + our_material.metallic = pbr.metallic_factor; + our_material.roughness = pbr.roughness_factor; + } + + cgltf_texture_view normal_tex_view = gltf_material.normal_texture; + if (normal_tex_view.texture != NULL) { + char normal_map_path[1024]; + snprintf(normal_map_path, sizeof(normal_map_path), "%s/%s", relative_path.buf, + normal_tex_view.texture->image->uri); + our_material.normal_map = TextureLoadFromFile(normal_map_path); + } else { + WARN("GLTF model has no normal map"); + } + + u32 string_length = strlen(gltf_material.name) + 1; + assert(string_length < 64); + strcpy(our_material.name, gltf_material.name); + + Material_darray_push(out_materials, our_material); + } + + return out_materials->len; +} diff --git a/src/archive/src/resources/loaders.h b/src/archive/src/resources/loaders.h new file mode 100644 index 0000000..ea1f9a2 --- /dev/null +++ b/src/archive/src/resources/loaders.h @@ -0,0 +1,17 @@ +#pragma once + +#include "defines.h" +#include "render_types.h" +#include "str.h" + +// --- Public API +PUB ModelHandle ModelLoad_obj(const char* path, bool invert_texture_y); +PUB ModelHandle ModelLoad_gltf(const char* path, bool invert_texture_y); + +typedef struct GLTF_LoadStats { + u32 mesh_count, material_count, vertex_count, index_count, animation_count, joint_count; +} GLTF_LoadStats; + +// --- Internal +bool model_load_gltf_str(const char* file_string, const char* filepath, Str8 relative_path, + Model* out_model, bool invert_textures_y); diff --git a/src/archive/src/resources/obj.c b/src/archive/src/resources/obj.c new file mode 100644 index 0000000..a5e9b18 --- /dev/null +++ b/src/archive/src/resources/obj.c @@ -0,0 +1,398 @@ +/** + * @file obj.c + * @brief Wavefront OBJ loader. + * @copyright Copyright (c) 2024 + */ +#include +#include +#include +#include +#include +#include + +#include "core.h" +#include "darray.h" +#include "file.h" +#include "log.h" +#include "maths.h" +#include "mem.h" +#include "platform.h" +#include "render.h" +#include "render_types.h" +#include "str.h" + +extern Core g_core; + +struct face { + u32 vertex_indices[3]; + u32 normal_indices[3]; + u32 uv_indices[3]; +}; +typedef struct face face; + +KITC_DECL_TYPED_ARRAY(Vec3) +KITC_DECL_TYPED_ARRAY(Vec2) +KITC_DECL_TYPED_ARRAY(face) + +// Forward declarations +// void create_submesh(mesh_darray *meshes, Vec3_darray *tmp_positions, Vec3_darray *tmp_normals, +// Vec2_darray *tmp_uvs, face_darray *tmp_faces, material_darray *materials, +// bool material_loaded, char current_material_name[256]); +// bool load_material_lib(const char *path, str8 relative_path, material_darray *materials); +// bool model_load_obj_str(const char *file_string, str8 relative_path, Model *out_model, +// bool invert_textures_y); + +ModelHandle model_load_obj(Core* core, const char* path, bool invert_textures_y) { + size_t arena_size = 1024; + arena scratch = arena_create(malloc(arena_size), arena_size); + + TRACE("Loading model at Path %s\n", path); + path_opt relative_path = path_parent(&scratch, path); + if (!relative_path.has_value) { + WARN("Couldnt get a relative path for the path to use for loading materials & textures later"); + } + const char* file_string = string_from_file(path); + + ModelHandle handle; + // model *model = model_pool_alloc(&g_core.models, &handle); + // model->name = str8_cstr_view(path); + // model->meshes = mesh_darray_new(1); + + // bool success = model_load_obj_str(file_string, relative_path.path, &model, invert_textures_y); + + // if (!success) { + // FATAL("Couldnt load OBJ file at path %s", path); + // ERROR_EXIT("Load fails are considered crash-worthy right now. This will change later.\n"); + // } + + // arena_free_all(&scratch); + // arena_free_storage(&scratch); + return handle; +} + +bool model_load_obj_str(const char* file_string, Str8 relative_path, Model* out_model, + bool invert_textures_y) { + TRACE("Load OBJ from string"); + + // // Setup temps + // vec3_darray *tmp_positions = vec3_darray_new(1000); + // vec3_darray *tmp_normals = vec3_darray_new(1000); + // vec2_darray *tmp_uvs = vec2_darray_new(1000); + // face_darray *tmp_faces = face_darray_new(1000); + // // TODO: In the future I'd like these temporary arrays to be allocated from an arena provided + // // by the function one level up, model_load_obj. That way we can just `return false;` anywhere + // in + // // this code to indicate an error, and be sure that all that memory will be cleaned up without + // // having to call vec3_darray_free in every single error case before returning. + + // // Other state + // bool object_set = false; + // bool material_loaded = false; + // char current_material_name[64]; + + // char *pch; + // char *rest = file_string; + // pch = strtok_r((char *)file_string, "\n", &rest); + + // int line_num = 0; + // char last_char_type = 'a'; + + // while (pch != NULL) { + // line_num++; + // char line_header[128]; + // int offset = 0; + + // // skip whitespace + // char *p = pch; + + // skip_space(pch); + + // if (*p == '\0') { + // /* the string is empty */ + // } else { + // // read the first word of the line + // int res = sscanf(pch, "%s %n", line_header, &offset); + // /* printf("header: %s, offset : %d res: %d\n",line_header, offset, res); */ + // if (res != 1) { + // break; + // } + + // if (strcmp(line_header, "o") == 0 || strcmp(line_header, "g") == 0) { + // // if we're currently parsing one + // if (!object_set) { + // object_set = true; + // } else { + // create_submesh(out_model->meshes, tmp_positions, tmp_normals, tmp_uvs, tmp_faces, + // NULL, // out_model->materials, + // material_loaded, current_material_name); + // object_set = false; + // } + // } else if (strcmp(line_header, "v") == 0) { + // // special logic: if we went from faces back to vertices trigger a mesh output. + // // PS: I hate OBJ + // if (last_char_type == 'f') { + // create_submesh(out_model->meshes, tmp_positions, tmp_normals, tmp_uvs, tmp_faces, + // NULL, // FIXME: out_model->materials, + // material_loaded, current_material_name); + // object_set = false; + // } + + // last_char_type = 'v'; + // vec3 vertex; + // sscanf(pch + offset, "%f %f %f", &vertex.x, &vertex.y, &vertex.z); + + // vec3_darray_push(tmp_positions, vertex); + // } else if (strcmp(line_header, "vt") == 0) { + // last_char_type = 't'; + // vec2 uv; + // char copy[1024]; + // memcpy(copy, pch + offset, strlen(pch + offset) + 1); + // char *p = pch + offset; + // while (isspace((unsigned char)*p)) ++p; + + // // I can't remember what is going on here + // memset(copy, 0, 1024); + // memcpy(copy, pch + offset, strlen(pch + offset) + 1); + // int res = sscanf(copy, "%f %f", &uv.x, &uv.y); + // memset(copy, 0, 1024); + // memcpy(copy, pch + offset, strlen(pch + offset) + 1); + // if (res != 1) { + // // da frick? some .obj files have 3 uvs instead of 2 + // f32 dummy; + // int res2 = sscanf(copy, "%f %f %f", &uv.x, &uv.y, &dummy); + // } + + // if (invert_textures_y) { + // uv.y = -uv.y; // flip Y axis to be consistent with how other PNGs are being handled + // // `texture_load` will flip it again + // } + // vec2_darray_push(tmp_uvs, uv); + // } else if (strcmp(line_header, "vn") == 0) { + // last_char_type = 'n'; + // vec3 normal; + // sscanf(pch + offset, "%f %f %f", &normal.x, &normal.y, &normal.z); + // vec3_darray_push(tmp_normals, normal); + // } else if (strcmp(line_header, "f") == 0) { + // last_char_type = 'f'; + // struct face f; + // sscanf(pch + offset, "%d/%d/%d %d/%d/%d %d/%d/%d", &f.vertex_indices[0], + // &f.uv_indices[0], + // &f.normal_indices[0], &f.vertex_indices[1], &f.uv_indices[1], + // &f.normal_indices[1], &f.vertex_indices[2], &f.uv_indices[2], + // &f.normal_indices[2]); + // // printf("f %d/%d/%d %d/%d/%d %d/%d/%d\n", f.vertex_indices[0], f.uv_indices[0], + // // f.normal_indices[0], + // // f.vertex_indices[1], f.uv_indices[1], f.normal_indices[1], + // // f.vertex_indices[2], f.uv_indices[2], f.normal_indices[2]); + // face_darray_push(tmp_faces, f); + // } else if (strcmp(line_header, "mtllib") == 0) { + // char filename[1024]; + // sscanf(pch + offset, "%s", filename); + // char mtllib_path[1024]; + // snprintf(mtllib_path, sizeof(mtllib_path), "%s/%s", relative_path.buf, filename); + // if (!load_material_lib(mtllib_path, relative_path, out_model->materials)) { + // ERROR("couldnt load material lib"); + // return false; + // } + // } else if (strcmp(line_header, "usemtl") == 0) { + // material_loaded = true; + // sscanf(pch + offset, "%s", current_material_name); + // } + // } + + // pch = strtok_r(NULL, "\n", &rest); + // } + + // // last mesh or if one wasnt created with 'o' directive + // if (face_darray_len(tmp_faces) > 0) { + // TRACE("Last leftover mesh"); + // create_submesh(out_model->meshes, tmp_positions, tmp_normals, tmp_uvs, tmp_faces, + // NULL, // TODO: out_model->materials, + // material_loaded, current_material_name); + // } + + // // Free data + // free((char *)file_string); + // vec3_darray_free(tmp_positions); + // vec3_darray_free(tmp_normals); + // vec2_darray_free(tmp_uvs); + // face_darray_free(tmp_faces); + // TRACE("Freed temporary OBJ loading data"); + + // if (mesh_darray_len(out_model->meshes) > 256) { + // printf("num meshes: %ld\n", mesh_darray_len(out_model->meshes)); + // } + + // // TODO: bounding box calculation for each mesh + // // TODO: bounding box calculation for model + + // TODO: copy from mesh_darray to malloc'd mesh* array + + return true; +} + +// /** +// * @brief Takes the current positions, normals, uvs arrays and constructs the vertex array +// * from those indices. +// */ +// void create_submesh(mesh_darray *meshes, vec3_darray *tmp_positions, vec3_darray *tmp_normals, +// vec2_darray *tmp_uvs, face_darray *tmp_faces, material_darray *materials, +// bool material_loaded, char current_material_name[256]) { +// // size_t num_verts = face_darray_len(tmp_faces) * 3; +// // vertex_darray *out_vertices = vertex_darray_new(num_verts); + +// // face_darray_iter face_iter = face_darray_iter_new(tmp_faces); +// // struct face *f; + +// // while ((f = face_darray_iter_next(&face_iter))) { +// // for (int j = 0; j < 3; j++) { +// // vertex vert = { 0 }; +// // vert.position = tmp_positions->data[f->vertex_indices[j] - 1]; +// // if (vec3_darray_len(tmp_normals) == 0) { +// // vert.normal = vec3_create(0.0, 0.0, 0.0); +// // } else { +// // vert.normal = tmp_normals->data[f->normal_indices[j] - 1]; +// // } +// // vert.uv = tmp_uvs->data[f->uv_indices[j] - 1]; +// // vertex_darray_push(out_vertices, vert); +// // } +// // } + +// // DEBUG("Loaded submesh\n vertices: %zu\n uvs: %zu\n normals: %zu\n faces: %zu", +// // vec3_darray_len(tmp_positions), vec2_darray_len(tmp_uvs), +// vec3_darray_len(tmp_normals), +// // face_darray_len(tmp_faces)); + +// // // Clear current object faces +// // face_darray_clear(tmp_faces); + +// // mesh m = { .vertices = out_vertices }; +// // if (material_loaded) { +// // // linear scan to find material +// // bool found = false; +// // DEBUG("Num of materials : %ld", material_darray_len(materials)); +// // material_darray_iter mat_iter = material_darray_iter_new(materials); +// // blinn_phong_material *cur_material; +// // while ((cur_material = material_darray_iter_next(&mat_iter))) { +// // if (strcmp(cur_material->name, current_material_name) == 0) { +// // DEBUG("Found match"); +// // m.material_index = mat_iter.current_idx - 1; +// // found = true; +// // break; +// // } +// // } + +// // if (!found) { +// // // TODO: default material +// // m.material_index = 0; +// // DEBUG("Set default material"); +// // } +// // } +// // mesh_darray_push(meshes, m); +// } + +// bool load_material_lib(const char *path, str8 relative_path, material_darray *materials) { +// TRACE("BEGIN load material lib at %s", path); + +// // const char *file_string = string_from_file(path); +// // if (file_string == NULL) { +// // ERROR("couldnt load %s", path); +// // return false; +// // } + +// // char *pch; +// // char *saveptr; +// // pch = strtok_r((char *)file_string, "\n", &saveptr); + +// // material current_material = DEFAULT_MATERIAL; + +// // bool material_set = false; + +// // while (pch != NULL) { +// // char line_header[128]; +// // int offset = 0; +// // // read the first word of the line +// // int res = sscanf(pch, "%s %n", line_header, &offset); +// // if (res != 1) { +// // break; +// // } + +// // // When we see "newmtl", start a new material, or flush the previous one +// // if (strcmp(line_header, "newmtl") == 0) { +// // if (material_set) { +// // // a material was being parsed, so flush that one and start a new one +// // material_darray_push(materials, current_material); +// // DEBUG("pushed material with name %s", current_material.name); +// // WARN("Reset current material"); +// // current_material = DEFAULT_MATERIAL; +// // } else { +// // material_set = true; +// // } +// // // scan the new material name +// // char material_name[64]; +// // sscanf(pch + offset, "%s", current_material.name); +// // DEBUG("material name %s\n", current_material.name); +// // // current_material.name = material_name; +// // } else if (strcmp(line_header, "Ka") == 0) { +// // // ambient +// // sscanf(pch + offset, "%f %f %f", ¤t_material.ambient_colour.x, +// // ¤t_material.ambient_colour.y, ¤t_material.ambient_colour.z); +// // } else if (strcmp(line_header, "Kd") == 0) { +// // // diffuse +// // sscanf(pch + offset, "%f %f %f", ¤t_material.diffuse.x, +// ¤t_material.diffuse.y, +// // ¤t_material.diffuse.z); +// // } else if (strcmp(line_header, "Ks") == 0) { +// // // specular +// // sscanf(pch + offset, "%f %f %f", ¤t_material.specular.x, +// // ¤t_material.specular.y, +// // ¤t_material.specular.z); +// // } else if (strcmp(line_header, "Ns") == 0) { +// // // specular exponent +// // sscanf(pch + offset, "%f", ¤t_material.spec_exponent); +// // } else if (strcmp(line_header, "map_Kd") == 0) { +// // char diffuse_map_filename[1024]; +// // sscanf(pch + offset, "%s", diffuse_map_filename); +// // char diffuse_map_path[1024]; +// // snprintf(diffuse_map_path, sizeof(diffuse_map_path), "%s/%s", relative_path.buf, +// // diffuse_map_filename); +// // printf("load from %s\n", diffuse_map_path); + +// // // -------------- +// // texture diffuse_texture = texture_data_load(diffuse_map_path, true); +// // current_material.diffuse_texture = diffuse_texture; +// // strcpy(current_material.diffuse_tex_path, diffuse_map_path); +// // texture_data_upload(¤t_material.diffuse_texture); +// // // -------------- +// // } else if (strcmp(line_header, "map_Ks") == 0) { +// // // char specular_map_path[1024] = "assets/"; +// // // sscanf(pch + offset, "%s", specular_map_path + 7); +// // char specular_map_filename[1024]; +// // sscanf(pch + offset, "%s", specular_map_filename); +// // char specular_map_path[1024]; +// // snprintf(specular_map_path, sizeof(specular_map_path), "%s/%s", relative_path.buf, +// // specular_map_filename); +// // printf("load from %s\n", specular_map_path); +// // // -------------- +// // texture specular_texture = texture_data_load(specular_map_path, true); +// // current_material.specular_texture = specular_texture; +// // strcpy(current_material.specular_tex_path, specular_map_path); +// // texture_data_upload(¤t_material.specular_texture); +// // // -------------- +// // } else if (strcmp(line_header, "map_Bump") == 0) { +// // // TODO +// // } + +// // pch = strtok_r(NULL, "\n", &saveptr); +// // } + +// // TRACE("end load material lib"); + +// // // last mesh or if one wasnt created with 'o' directive +// // // TRACE("Last leftover material"); +// // material_darray_push(materials, current_material); + +// // INFO("Loaded %ld materials", material_darray_len(materials)); +// TRACE("END load material lib"); +// return true; +// } diff --git a/src/archive/src/std/buf.h b/src/archive/src/std/buf.h new file mode 100644 index 0000000..77fc7b9 --- /dev/null +++ b/src/archive/src/std/buf.h @@ -0,0 +1,11 @@ +/** + * @file buf.h + * @brief + */ +#pragma once +#include "defines.h" + +typedef struct bytebuffer { + u8* buf; + size_t size; +} bytebuffer; diff --git a/src/archive/src/std/containers/container_utils.h b/src/archive/src/std/containers/container_utils.h new file mode 100644 index 0000000..e1d164c --- /dev/null +++ b/src/archive/src/std/containers/container_utils.h @@ -0,0 +1,17 @@ +/** + * @file container_utils.h + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-06-19 + * + * @copyright Copyright (c) 2024 + * + */ + +#pragma once + +typedef struct generic_iterator { +} generic_iterator; + +typedef void* (*iterator_next_item)(void* iterator); \ No newline at end of file diff --git a/src/archive/src/std/containers/darray.h b/src/archive/src/std/containers/darray.h new file mode 100644 index 0000000..080afb4 --- /dev/null +++ b/src/archive/src/std/containers/darray.h @@ -0,0 +1,151 @@ +/** + * @file darray.h + * @brief Typed dynamic array + * @copyright Copyright (c) 2023 + */ +// COPIED FROM KITC WITH SOME MINOR ADJUSTMENTS + +/* TODO: + - a 'find' function that takes a predicate (maybe wrap with a macro so we dont have to define a + new function?) +*/ + +#ifndef KITC_TYPED_ARRAY_H +#define KITC_TYPED_ARRAY_H + +#include +#include +#include +#include + +#define DARRAY_DEFAULT_CAPACITY 64 +#define DARRAY_RESIZE_FACTOR 3 + +/** @brief create a new darray type and functions with type `N` */ +#define typed_array(T) \ + struct { \ + /* @brief current number of items in the array */ \ + size_t len; \ + size_t capacity; \ + T* data; \ + } + +#define typed_array_iterator(T) \ + struct { \ + T##_darray* array; \ + size_t current_idx; \ + } + +#define PREFIX static + +#define KITC_DECL_TYPED_ARRAY(T) DECL_TYPED_ARRAY(T, T) + +#define DECL_TYPED_ARRAY(T, Type) \ + typedef typed_array(T) Type##_darray; \ + typedef typed_array_iterator(Type) Type##_darray_iter; \ + \ + /* Create a new one growable array */ \ + PREFIX Type##_darray* Type##_darray_new(size_t starting_capacity) { \ + Type##_darray* d; \ + T* data; \ + d = malloc(sizeof(Type##_darray)); \ + data = malloc(starting_capacity * sizeof(T)); \ + \ + d->len = 0; \ + d->capacity = starting_capacity; \ + d->data = data; \ + \ + return d; \ + } \ + \ + PREFIX void Type##_darray_free(Type##_darray* d) { \ + if (d != NULL) { \ + free(d->data); \ + free(d); \ + } \ + } \ + \ + PREFIX T* Type##_darray_resize(Type##_darray* d, size_t capacity) { \ + /* resize the internal data block */ \ + T* new_data = realloc(d->data, sizeof(T) * capacity); \ + /* TODO: handle OOM error */ \ + \ + d->capacity = capacity; \ + d->data = new_data; \ + return new_data; \ + } \ + \ + PREFIX void Type##_darray_push(Type##_darray* d, T value) { \ + if (d->len >= d->capacity) { \ + size_t new_capacity = \ + d->capacity > 0 ? d->capacity * DARRAY_RESIZE_FACTOR : DARRAY_DEFAULT_CAPACITY; \ + T* resized = Type##_darray_resize(d, new_capacity); \ + (void)resized; \ + } \ + \ + d->data[d->len] = value; \ + d->len += 1; \ + } \ + \ + PREFIX void Type##_darray_push_copy(Type##_darray* d, const T* value) { \ + if (d->len >= d->capacity) { \ + size_t new_capacity = \ + d->capacity > 0 ? d->capacity * DARRAY_RESIZE_FACTOR : DARRAY_DEFAULT_CAPACITY; \ + T* resized = Type##_darray_resize(d, new_capacity); \ + (void)resized; \ + } \ + \ + T* place = d->data + d->len; \ + d->len += 1; \ + memcpy(place, value, sizeof(T)); \ + } \ + \ + PREFIX void Type##_darray_pop(Type##_darray* d, T* dest) { \ + T* item = d->data + (d->len - 1); \ + d->len -= 1; \ + memcpy(dest, item, sizeof(T)); \ + } \ + \ + PREFIX void Type##_darray_ins(Type##_darray* d, const T* value, size_t index) { \ + /* check if requires resize */ \ + if (d->len + 1 > d->capacity) { \ + size_t new_capacity = \ + d->capacity > 0 ? d->capacity * DARRAY_RESIZE_FACTOR : DARRAY_DEFAULT_CAPACITY; \ + T* resized = Type##_darray_resize(d, new_capacity); \ + (void)resized; \ + } \ + \ + /* shift existing data after index */ \ + T* insert_dest = d->data + index; \ + T* shift_dest = insert_dest + 1; \ + \ + int num_items = d->len - index; \ + \ + d->len += 1; \ + memcpy(shift_dest, insert_dest, num_items * sizeof(T)); \ + memcpy(insert_dest, value, sizeof(T)); \ + } \ + \ + PREFIX void Type##_darray_clear(Type##_darray* d) { \ + d->len = 0; \ + memset(d->data, 0, d->capacity * sizeof(T)); \ + } \ + \ + PREFIX size_t Type##_darray_len(Type##_darray* d) { return d->len; } \ + \ + PREFIX Type##_darray_iter Type##_darray_iter_new(Type##_darray* d) { \ + Type##_darray_iter iterator; \ + iterator.array = d; \ + iterator.current_idx = 0; \ + return iterator; \ + } \ + \ + PREFIX void* Type##_darray_iter_next(Type##_darray_iter* iterator) { \ + if (iterator->current_idx < iterator->array->len) { \ + return &iterator->array->data[iterator->current_idx++]; \ + } else { \ + return NULL; \ + } \ + } + +#endif // KITC_TYPED_ARRAY_H diff --git a/src/archive/src/std/containers/graphs.h b/src/archive/src/std/containers/graphs.h new file mode 100644 index 0000000..5dbec97 --- /dev/null +++ b/src/archive/src/std/containers/graphs.h @@ -0,0 +1,14 @@ +/** + * @file graphs.h + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-04-27 + * + * @copyright Copyright (c) 2024 + * + */ + +// Adjacency list backed graphs + +// Matrix backed graphs (not as useful) \ No newline at end of file diff --git a/src/archive/src/std/containers/hashmap.h b/src/archive/src/std/containers/hashmap.h new file mode 100644 index 0000000..95c1c6b --- /dev/null +++ b/src/archive/src/std/containers/hashmap.h @@ -0,0 +1,27 @@ +/** + * @file hashmap.h + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-04-27 + * + * @copyright Copyright (c) 2024 + * + */ + +typedef struct hashmap hashmap; + +/* +Example usage +------------- +init hashmap +insert (string, material) +get (string) -> material_opt or material* ? + +*/ + +void hashmap_init(hashmap* map); + +// ... + +void hashmap_free(hashmap* map); \ No newline at end of file diff --git a/src/archive/src/std/containers/hashset.h b/src/archive/src/std/containers/hashset.h new file mode 100644 index 0000000..7f87213 --- /dev/null +++ b/src/archive/src/std/containers/hashset.h @@ -0,0 +1,29 @@ +/** + * @file hashset.h + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-04-27 + * + * @copyright Copyright (c) 2024 + * + */ + +#include "defines.h" + +typedef struct hashset hashset; + +/** @brief Describes a function that will take a pointer to a datatype (e.g. a u64 or a struct) + and return a hashed key. */ +typedef uint64_t (*hash_item)(void* item); + +void hashset_init(hashset* set, hash_item hash_func, size_t initial_capacity); +// TODO: void hashset_from_iterator(); +bool hashset_insert(hashset* set, void* item, uint64_t* out_key); +void hashset_batch_insert(hashset* set, void* items, u64 item_count); +bool hashset_contains(hashset* set, void* item); +bool hashset_remove_item(hashset* set, void* item); +bool hashset_remove_key(hashset* set, uint64_t key); +void hashset_merge(hashset* set_a, hashset* set_b); +hashset* hashset_merge_cloned(hashset* set_a, hashset* set_b); +void hashset_free(hashset* set); \ No newline at end of file diff --git a/src/archive/src/std/containers/ring_queue.c b/src/archive/src/std/containers/ring_queue.c new file mode 100644 index 0000000..8bfc10b --- /dev/null +++ b/src/archive/src/std/containers/ring_queue.c @@ -0,0 +1,68 @@ +#include "ring_queue.h" + +#include +#include +#include "defines.h" + +ring_queue* ring_queue_new(size_t type_size, size_t capacity, void* memory) { + ring_queue* q = malloc(sizeof(ring_queue)); + q->len = 0; + q->capacity = capacity; + q->type_size = type_size; + q->head = 0; + q->tail = -1; + + if (memory) { + // caller owns the memory + q->owns_memory = false; + q->data = memory; + } else { + // ring queue should own the memory + q->owns_memory = true; + q->data = malloc(capacity * type_size); + } + + return q; +} + +void ring_queue_free(ring_queue* queue) { + if (queue) { + if (queue->owns_memory) { + free(queue->data); + } + free(queue); + } +} + +bool ring_queue_enqueue(ring_queue* queue, const void* value) { + if (queue->len == queue->capacity) { + return false; + } + + queue->tail = (queue->tail + 1) % queue->capacity; + memcpy(queue->data + (queue->tail * queue->type_size), value, queue->type_size); + queue->len++; + return true; +} + +bool ring_queue_dequeue(ring_queue* queue, void* out_value) { + if (queue->len == 0) { + // queue is empty + return false; + } + + memcpy(out_value, queue->data + (queue->head * queue->type_size), queue->type_size); + queue->head = (queue->head + 1) % queue->capacity; + queue->len--; + return true; +} + +bool ring_queue_peek(const ring_queue* queue, void* out_value) { + if (queue->len == 0) { + // queue is empty + return false; + } + + memcpy(out_value, queue->data + (queue->head * queue->type_size), queue->type_size); + return true; +} \ No newline at end of file diff --git a/src/archive/src/std/containers/ring_queue.h b/src/archive/src/std/containers/ring_queue.h new file mode 100644 index 0000000..15d5da4 --- /dev/null +++ b/src/archive/src/std/containers/ring_queue.h @@ -0,0 +1,35 @@ +/** + * @file ring_queue.h + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-02-24 + * + * @copyright Copyright (c) 2024 + * + */ +#pragma once +#include "defines.h" + +/** + * @brief a fixed-size ring queue + */ +typedef struct ring_queue { + size_t len; + size_t capacity; + size_t type_size; + void* data; + bool owns_memory; + int32_t head; + int32_t tail; +} ring_queue; + +ring_queue* ring_queue_new(size_t type_size, size_t capacity, void* memory_block); + +void ring_queue_free(ring_queue* queue); + +bool ring_queue_enqueue(ring_queue* queue, const void* value); + +bool ring_queue_dequeue(ring_queue* queue, void* out_value); + +bool ring_queue_peek(const ring_queue* queue, void* out_value); \ No newline at end of file diff --git a/src/archive/src/std/containers/stack_array.h b/src/archive/src/std/containers/stack_array.h new file mode 100644 index 0000000..d2b6bdd --- /dev/null +++ b/src/archive/src/std/containers/stack_array.h @@ -0,0 +1,19 @@ +#pragma once +#include + +// Defines "_sarray" types + +#define TYPED_STACK_ARRAY(T, Name, Len) \ + typedef struct Name##_sarray { \ + T items[ Len ]; \ + size_t len; \ + } Name##_sarray; \ + Name##_sarray Name##_sarray_create() { \ + Name##_sarray arr = { .len = 0 }; \ + return arr; \ + } \ + bool Name##_sarray_push(Name##_sarray* arr, T item) { \ + if (arr->len == Len) { return false; }\ + arr->items[arr->len++] = item;\ + return true;\ + } diff --git a/src/archive/src/std/mem.c b/src/archive/src/std/mem.c new file mode 100644 index 0000000..1f9078b --- /dev/null +++ b/src/archive/src/std/mem.c @@ -0,0 +1,135 @@ +#include +#include +#include +#include + +#include "log.h" +#include "mem.h" + +#ifndef DEFAULT_ALIGNMENT +#define DEFAULT_ALIGNMENT (2 * sizeof(void*)) +#endif + +// --- Arena + +void* arena_alloc_align(arena* a, size_t size, size_t align) { + ptrdiff_t padding = -(uintptr_t)a->curr & (align - 1); + ptrdiff_t available = a->end - a->curr - padding; + // TRACE("Padding %td available %td", padding, available); + if (available < 0 || (ptrdiff_t)size > available) { + ERROR_EXIT("Arena ran out of memory\n"); + } + void* p = a->curr + padding; + a->curr += padding + size; + return memset(p, 0, size); +} +void* arena_alloc(arena* a, size_t size) { return arena_alloc_align(a, size, DEFAULT_ALIGNMENT); } + +arena arena_create(void* backing_buffer, size_t capacity) { + return (arena){ .begin = backing_buffer, + .curr = backing_buffer, + .end = backing_buffer + (ptrdiff_t)capacity }; +} + +void arena_free_all(arena* a) { + a->curr = a->begin; // pop everything at once and reset to the start. +} + +void arena_free_storage(arena* a) { free(a->begin); } + +arena_save arena_savepoint(arena* a) { + arena_save savept = { .arena = a, .savepoint = a->curr }; + return savept; +} + +void arena_rewind(arena_save savepoint) { savepoint.arena->curr = savepoint.savepoint; } + +// --- Pool + +void_pool void_pool_create(arena* a, const char* debug_label, u64 capacity, u64 entry_size) { + size_t memory_requirements = capacity * entry_size; + void* backing_buf = arena_alloc(a, memory_requirements); + + assert(entry_size >= sizeof(void_pool_header)); // TODO: create my own assert with error message + + void_pool pool = { .capacity = capacity, + .entry_size = entry_size, + .count = 0, + .backing_buffer = backing_buf, + .free_list_head = NULL, + .debug_label = debug_label }; + + void_pool_free_all(&pool); + + return pool; +} + +void void_pool_free_all(void_pool* pool) { + // set all entries to be free + for (u64 i = 0; i < pool->capacity; i++) { + void* ptr = &pool->backing_buffer[i * pool->entry_size]; + void_pool_header* free_node = + (void_pool_header*)ptr; // we reuse the actual entry itself to hold the header + if (i == (pool->capacity - 1)) { + // if the last one we make its next pointer NULL indicating its full + free_node->next = NULL; + } + free_node->next = pool->free_list_head; + // now the head points to this entry + pool->free_list_head = free_node; + } +} + +void* void_pool_get(void_pool* pool, u32 raw_handle) { + // An handle is an index into the array essentially + void* ptr = pool->backing_buffer + (raw_handle * pool->entry_size); + return ptr; +} + +void* void_pool_alloc(void_pool* pool, u32* out_raw_handle) { + // get the next free node + if (pool->count == pool->capacity) { + WARN("Pool is full!"); + return NULL; + } + if (pool->free_list_head == NULL) { + ERROR("%s Pool is full (head = null)", pool->debug_label); + return NULL; + } + void_pool_header* free_node = pool->free_list_head; + + // What index does this become? + uintptr_t start = (uintptr_t)pool->backing_buffer; + uintptr_t cur = (uintptr_t)free_node; + // TRACE("%ld %ld ", start, cur); + assert(cur > start); + u32 index = (u32)((cur - start) / pool->entry_size); + /* printf("Index %d\n", index); */ + if (out_raw_handle != NULL) { + *out_raw_handle = index; + } + + pool->free_list_head = free_node->next; + + memset(free_node, 0, pool->entry_size); + pool->count++; + return (void*)free_node; +} + +void void_pool_dealloc(void_pool* pool, u32 raw_handle) { + // push free node back onto the free list + void* ptr = void_pool_get(pool, raw_handle); + void_pool_header* freed_node = (void_pool_header*)ptr; + + freed_node->next = pool->free_list_head; + pool->free_list_head = freed_node; + + pool->count--; +} + +u32 void_pool_insert(void_pool* pool, void* item) { + u32 raw_handle; + void* item_dest = void_pool_alloc(pool, &raw_handle); + memcpy(item_dest, item, pool->entry_size); + return raw_handle; +} diff --git a/src/archive/src/std/mem.h b/src/archive/src/std/mem.h new file mode 100644 index 0000000..56c1230 --- /dev/null +++ b/src/archive/src/std/mem.h @@ -0,0 +1,96 @@ +/** + * @file mem.h + * @brief Allocators, memory tracking + * @version 0.1 + * @date 2024-02-24 + * + * @copyright Copyright (c) 2024 + * + */ +#pragma once + +#include +#include "defines.h" + +typedef void* (*alloc_fn)(size_t size); +typedef void (*free_fn)(void* ptr); + +typedef struct allocator_t { + alloc_fn alloc; + free_fn free; +} allocator_t; + +// --- Arena + +// Inspired by https://nullprogram.com/blog/2023/09/27/ +typedef struct arena { + char* begin; + char* curr; + char* end; +} arena; + +typedef struct arena_save { + arena* arena; + char* savepoint; +} arena_save; + +arena arena_create(void* backing_buffer, size_t capacity); +void* arena_alloc(arena* a, size_t size); +void* arena_alloc_align(arena* a, size_t size, size_t align); +void arena_free_all(arena* a); +void arena_free_storage(arena* a); +arena_save arena_savepoint(arena* a); +void arena_rewind(arena_save savepoint); +// TODO: arena_resize + +// --- Pool + +typedef struct void_pool_header void_pool_header; +struct void_pool_header { + void_pool_header* next; +}; + +typedef struct void_pool { + u64 capacity; + u64 entry_size; + u64 count; + void* backing_buffer; + void_pool_header* free_list_head; + const char* debug_label; +} void_pool; + +void_pool void_pool_create(arena* a, const char* debug_label, u64 capacity, u64 entry_size); +void void_pool_free_all(void_pool* pool); +bool void_pool_is_empty(void_pool* pool); +bool void_pool_is_full(void_pool* pool); +void* void_pool_get(void_pool* pool, u32 raw_handle); +void* void_pool_alloc(void_pool* pool, u32* out_raw_handle); +void void_pool_dealloc(void_pool* pool, u32 raw_handle); +u32 void_pool_insert(void_pool* pool, void* item); +// TODO: fn to dealloc from the pointer that was handed out + +// TODO: macro that lets us specialise + +/* typedef struct Name##_handle Name##_handle; \ */ +#define TYPED_POOL(T, Name) \ + typedef struct Name##_pool { \ + void_pool inner; \ + } Name##_pool; \ + \ + static Name##_pool Name##_pool_create(arena* a, u64 cap, u64 entry_size) { \ + void_pool p = void_pool_create(a, "\"" #Name "\"", cap, entry_size); \ + return (Name##_pool){ .inner = p }; \ + } \ + static inline T* Name##_pool_get(Name##_pool* pool, Name##Handle handle) { \ + return (T*)void_pool_get(&pool->inner, handle.raw); \ + } \ + static inline T* Name##_pool_alloc(Name##_pool* pool, Name##Handle* out_handle) { \ + return (T*)void_pool_alloc(&pool->inner, &out_handle->raw); \ + } \ + static inline void Name##_pool_dealloc(Name##_pool* pool, Name##Handle handle) { \ + void_pool_dealloc(&pool->inner, handle.raw); \ + } \ + static Name##Handle Name##_pool_insert(Name##_pool* pool, T* item) { \ + u32 raw_handle = void_pool_insert(pool, item); \ + return (Name##Handle){ .raw = raw_handle }; \ + } diff --git a/src/archive/src/std/str.c b/src/archive/src/std/str.c new file mode 100644 index 0000000..89c76a0 --- /dev/null +++ b/src/archive/src/std/str.c @@ -0,0 +1,74 @@ +#include "str.h" +#include +#include +#include "log.h" +#include "mem.h" + +Str8 Str8_create(u8* buf, size_t len) { return (Str8){ .buf = buf, .len = len }; } + +Str8 Str8_cstr_view(char* string) { return Str8_create((u8*)string, strlen(string)); } + +bool Str8_equals(Str8 a, Str8 b) { + if (a.len != b.len) { + return false; + } + + for (size_t i = 0; i < a.len; i++) { + if (a.buf[i] != b.buf[i]) { + return false; + } + } + return true; +} + +char* Str8_to_cstr(arena* a, Str8 s) { + bool is_null_terminated = s.buf[s.len - 1] == 0; + size_t n_bytes = is_null_terminated ? s.len : s.len + 1; + + u8* dest = arena_alloc(a, n_bytes); + + memcpy(dest, s.buf, s.len); + if (is_null_terminated) { + dest[s.len] = '\0'; + } + return (char*)dest; +} + +char* Clone_cstr(arena* a, const char* s) { + if (s == NULL) { + WARN("Tried to clone a NULL char*"); + return NULL; + } + Str8 st = Str8_cstr_view(s); + return Str8_to_cstr(a, st); +} + +Str8 Str8_concat(arena* a, Str8 left, Str8 right) { + size_t n_bytes = left.len + right.len + 1; + + u8* dest = arena_alloc(a, n_bytes); + memcpy(dest, left.buf, left.len); + memcpy(dest + right.len, right.buf, right.len); + + dest[n_bytes - 1] = '\0'; + + return Str8_create(dest, n_bytes); +} + +Str8 Str8_substr(Str8 s, u64 min, u64 max) { + assert(min >= 0); + assert(min < s.len); + assert(max >= 0); + assert(max <= s.len); + uint8_t* start = s.buf + (ptrdiff_t)min; + size_t new_len = max - min; + return (Str8){ .buf = start, .len = new_len }; +} + +Str8 Str8_take(Str8 s, u64 first_n) { return Str8_substr(s, 0, first_n); } + +Str8 Str8_drop(Str8 s, u64 last_n) { return Str8_substr(s, s.len - last_n, s.len); } + +Str8 Str8_skip(Str8 s, u64 n) { return Str8_substr(s, n, s.len); } + +Str8 Str8_chop(Str8 s, u64 n) { return Str8_substr(s, 0, s.len - n); } diff --git a/src/archive/src/std/str.h b/src/archive/src/std/str.h new file mode 100644 index 0000000..a29bf9a --- /dev/null +++ b/src/archive/src/std/str.h @@ -0,0 +1,89 @@ +/** + * @file str.h + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-02-25 + * + * @copyright Copyright (c) 2024 + * + */ +#pragma once + +#include + +#include "defines.h" +#include "mem.h" + +/** + * @brief Fat pointer representing a UTF8 (TODO some APIs supporting utf8) encoded string + * @note when using `printf` you must use %s.*s length, string until our own modified + print routines are written. alternatively wrap in `cstr()` and pass to `%s`. + */ +typedef struct { + u8* buf; + size_t len; +} Str8; + +// --- Constructors + +/** @brief Take a string literal and turn it into a `str8` */ +#define str8(s) \ + (Str8) { (u8*)s, ((sizeof(s) / sizeof(*(s)) - 1)) } + +Str8 Str8_create(u8* buf, size_t len); + +// TODO: Str8_OntoArena(arena* a, Str8 s); + +/** @brief Return a null-terminated C string cloned onto an arena */ +char* Str8_to_cstr(arena* a, Str8 s); + +#define cstr(a, s) (Str8_to_cstr(a, s)) // Shorthand + +/** @brief Return a Str8 that references a statically allocated string. + `string` therefore must already be null-terminated. + @note The backing `string` cannot be modified. */ +Str8 Str8_cstr_view(char* string); + +char* Clone_cstr(arena* a, const char* s); + +// --- Comparisons + +/** @brief Compare two strings for exact equality */ +bool Str8_equals(Str8 a, Str8 b); + +/** + * @brief Compare the first `first_nchars` of each string for equality + * @details If either of the strings are shorter than the number only the characters up until the + end of the shorter string will be compared. + * @returns 0 if they are fully equal up until `first_nchars`, i.e they never differed, else it + returns the index at which the first string differed from the second string. +*/ +size_t Str8_nequals(Str8 a, Str8 b, size_t first_nchars); + +bool Str8_ends_with(Str8 input_str, Str8 suffix); + +/// --- Subviews + +Str8 Str8_substr(Str8 s, u64 min, u64 max); +/** @brief Keeps only the `first_n` chars of `s` */ +Str8 Str8_take(Str8 s, u64 first_n); +/** @brief Keeps only the `last_n` chars of `s` */ +Str8 Str8_drop(Str8 s, u64 last_n); +/** @brief Keeps everything after the first `n` chars of `s` */ +Str8 Str8_skip(Str8 s, u64 n); +/** @brief Keeps everything before the last `n` chars of `s` */ +Str8 Str8_chop(Str8 s, u64 n); + +Str8 Str8_concat(arena* a, Str8 left, Str8 right); + +/// --- Misc + +static inline bool Str8_is_null_term(Str8 a) { + return a.buf[a.len] == 0; // This doesn't seem safe. YOLO +} + +// TODO: move or delete this and replace with handling using our internal type +static void skip_space(char* p) { + while (isspace((unsigned char)*p)) ++p; +} diff --git a/src/archive/src/std/utils.h b/src/archive/src/std/utils.h new file mode 100644 index 0000000..c9827a3 --- /dev/null +++ b/src/archive/src/std/utils.h @@ -0,0 +1,4 @@ +#pragma once +#include + +const char* bool_str(bool input) { return input ? "True" : "False"; } \ No newline at end of file diff --git a/src/archive/src/systems/grid.c b/src/archive/src/systems/grid.c new file mode 100644 index 0000000..e907865 --- /dev/null +++ b/src/archive/src/systems/grid.c @@ -0,0 +1,84 @@ +#include "grid.h" +#include "file.h" +#include "log.h" +#include "maths.h" +#include "maths_types.h" +#include "primitives.h" +#include "ral_common.h" +#include "ral_impl.h" +#include "ral_types.h" +#include "render.h" +#include "render_types.h" +#include "shader_layouts.h" + +void Grid_Init(Grid_Storage* storage) { + INFO("Infinite Grid initialisation"); + Geometry plane_geo = Geo_CreatePlane(f32x2(1.0, 1.0), 1, 1); + Mesh plane_mesh = Mesh_Create(&plane_geo, true); + storage->plane_vertices = plane_mesh.vertex_buffer; + + u32 indices[6] = { 5, 4, 3, 2, 1, 0 }; + storage->plane_indices = + GPU_BufferCreate(6 * sizeof(u32), BUFFER_INDEX, BUFFER_FLAG_GPU, &indices); + + GPU_RenderpassDesc rpass_desc = { + .default_framebuffer = true, + }; + storage->renderpass = GPU_Renderpass_Create(rpass_desc); + + arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024); + + Str8 vert_path = str8("assets/shaders/grid.vert"); + Str8 frag_path = str8("assets/shaders/grid.frag"); + str8_opt vertex_shader = str8_from_file(&scratch, vert_path); + str8_opt fragment_shader = str8_from_file(&scratch, frag_path); + if (!vertex_shader.has_value || !fragment_shader.has_value) { + ERROR_EXIT("Failed to load shaders from disk") + } + + ShaderDataLayout camera_data = Binding_Camera_GetLayout(NULL); + + GraphicsPipelineDesc pipeline_desc = { + .debug_name = "Infinite grid pipeline", + .vertex_desc = static_3d_vertex_description(), + .data_layouts = { camera_data }, + .data_layouts_count = 1, + .vs = { + .debug_name = "Grid vertex shader", + .filepath = vert_path, + .code = vertex_shader.contents, + }, + .fs = { + .debug_name = "Grid fragment shader", + .filepath = frag_path, + .code = fragment_shader.contents, + }, + .wireframe = false, + }; + storage->pipeline = GPU_GraphicsPipeline_Create(pipeline_desc, storage->renderpass); +} + +void Grid_Draw() { + Grid_Storage* grid = Render_GetGridStorage(); + Grid_Execute(grid); +} + +void Grid_Execute(Grid_Storage* storage) { + RenderScene* scene = Render_GetScene(); + GPU_CmdEncoder* enc = GPU_GetDefaultEncoder(); + GPU_CmdEncoder_BeginRender(enc, storage->renderpass); + GPU_EncodeBindPipeline(enc, storage->pipeline); + Mat4 view, proj; + u32x2 dimensions = GPU_Swapchain_GetDimensions(); + Camera camera = scene->camera; + Camera_ViewProj(&camera, (f32)dimensions.x, (f32)dimensions.y, &view, &proj); + Binding_Camera camera_data = { .view = view, + .projection = proj, + .viewPos = vec4(camera.position.x, camera.position.y, + camera.position.z, 1.0) }; + GPU_EncodeBindShaderData(enc, 0, Binding_Camera_GetLayout(&camera_data)); + GPU_EncodeSetVertexBuffer(enc, storage->plane_vertices); + GPU_EncodeSetIndexBuffer(enc, storage->plane_indices); + GPU_EncodeDrawIndexedTris(enc, 6); + GPU_CmdEncoder_EndRender(enc); +} diff --git a/src/archive/src/systems/grid.h b/src/archive/src/systems/grid.h new file mode 100644 index 0000000..d8bc567 --- /dev/null +++ b/src/archive/src/systems/grid.h @@ -0,0 +1,21 @@ +#pragma once + +#include "ral_impl.h" +#include "ral_types.h" + +typedef struct Grid_Storage { + GPU_Renderpass* renderpass; + GPU_Pipeline* pipeline; + BufferHandle plane_vertices; + BufferHandle plane_indices; +} Grid_Storage; + +// --- Public API +PUB void Grid_Init(Grid_Storage* storage); +// void Grid_Shutdown(Grid_Storage* storage); +PUB void Grid_Draw(); + +// --- Internal +void Grid_Execute(Grid_Storage* storage); +// typedef struct GridUniforms {} GridUniforms; +// ShaderDataLayout GridUniforms_GetLayout(void* data); \ No newline at end of file diff --git a/src/archive/src/systems/input.c b/src/archive/src/systems/input.c new file mode 100644 index 0000000..c3af96a --- /dev/null +++ b/src/archive/src/systems/input.c @@ -0,0 +1,105 @@ +#include "input.h" + +#include +#include +#include + +#include "keys.h" +#include "log.h" + +static Input_State* g_input; // Use a global to simplify caller code + +bool Input_Init(Input_State* input, GLFWwindow* window) { + INFO("Input init"); + memset(input, 0, sizeof(Input_State)); + + input->window = window; + // Set everything to false. Could just set memory to zero but where's the fun in that + for (int i = KEYCODE_SPACE; i < KEYCODE_MAX; i++) { + input->depressed_keys[i] = false; + input->just_pressed_keys[i] = false; + input->just_released_keys[i] = false; + } + + g_input = input; + + assert(input->mouse.x_delta == 0); + assert(input->mouse.y_delta == 0); + + INFO("Finish input init"); + return true; +} + +void Input_Shutdown(Input_State* input) {} + +void Input_Update(Input_State* input) { + glfwPollEvents(); + // --- update keyboard input + + // if we go from un-pressed -> pressed, set as "just pressed" + // if we go from pressed -> un-pressed, set as "just released" + for (int i = KEYCODE_SPACE; i < KEYCODE_MAX; i++) { + bool new_state = false; + if (glfwGetKey(input->window, i) == GLFW_PRESS) { + new_state = true; + } else { + new_state = false; + } + if (!input->depressed_keys[i] == false && new_state) { + input->just_pressed_keys[i] = true; + } else { + input->just_pressed_keys[i] = false; + } + + if (input->depressed_keys[i] && !new_state) { + input->just_released_keys[i] = true; + } else { + input->just_released_keys[i] = false; + } + + input->depressed_keys[i] = new_state; + } + + // --- update mouse input + + // cursor position + f64 current_x, current_y; + glfwGetCursorPos(input->window, ¤t_x, ¤t_y); + i32 quantised_cur_x = (i32)current_x; + i32 quantised_cur_y = (i32)current_y; + + mouse_state new_mouse_state = { 0 }; + new_mouse_state.x = quantised_cur_x; + new_mouse_state.y = quantised_cur_y; + new_mouse_state.x_delta = quantised_cur_x - input->mouse.x; + new_mouse_state.y_delta = quantised_cur_y - input->mouse.y; + + // buttons + int left_state = glfwGetMouseButton(input->window, GLFW_MOUSE_BUTTON_LEFT); + int right_state = glfwGetMouseButton(input->window, GLFW_MOUSE_BUTTON_RIGHT); + + for (int i = 0; i < 3; i++) { + new_mouse_state.prev_pressed_states[i] = input->mouse.cur_pressed_states[i]; + } + new_mouse_state.cur_pressed_states[MOUSEBTN_LEFT] = left_state == GLFW_PRESS; + new_mouse_state.cur_pressed_states[MOUSEBTN_RIGHT] = right_state == GLFW_PRESS; + + // this was dumb! need to also check button state changes lol + // if (new_mouse_state.x != input->mouse.x || new_mouse_state.y != input->mouse.y) + // TRACE("Mouse (x,y) = (%d,%d)", input->mouse.x, input->mouse.y); + + input->mouse = new_mouse_state; +} + +bool key_is_pressed(keycode key) { return g_input->depressed_keys[key]; } + +bool key_just_pressed(keycode key) { return g_input->just_pressed_keys[key]; } + +bool key_just_released(keycode key) { return g_input->just_released_keys[key]; } + +bool MouseBtn_Held(MouseBtn btn) { + assert(btn < 3); + return g_input->mouse.prev_pressed_states[btn] && g_input->mouse.cur_pressed_states[btn]; +} + +mouse_state Input_GetMouseState() { return g_input->mouse; } \ No newline at end of file diff --git a/src/archive/src/systems/input.h b/src/archive/src/systems/input.h new file mode 100644 index 0000000..c3b2500 --- /dev/null +++ b/src/archive/src/systems/input.h @@ -0,0 +1,53 @@ +/** + * @brief + */ +#pragma once + +#include "defines.h" +#include "keys.h" + +struct GLFWWindow; + +typedef enum MouseBtn { + MOUSEBTN_LEFT = 0, + MOUSEBTN_RIGHT = 1, + MOUSEBTN_MIDDLE = 2, +} MouseBtn; + +typedef struct mouse_state { + i32 x; + i32 y; + i32 x_delta; + i32 y_delta; + bool prev_pressed_states[3]; + bool cur_pressed_states[3]; +} mouse_state; + +typedef struct Input_State { + struct GLFWwindow* window; + mouse_state mouse; + bool depressed_keys[KEYCODE_MAX]; + bool just_pressed_keys[KEYCODE_MAX]; + bool just_released_keys[KEYCODE_MAX]; +} Input_State; + +/** @brief `key` is currently being held down */ +PUB bool key_is_pressed(keycode key); + +/** @brief `key` was just pressed */ +PUB bool key_just_pressed(keycode key); + +/** @brief `key` was just released */ +PUB bool key_just_released(keycode key); + +// TODO: right btn as well +PUB bool MouseBtn_Held(MouseBtn btn); + +// --- Lifecycle + +PUB bool Input_Init(Input_State* input, struct GLFWwindow* window); +PUB void Input_Shutdown(Input_State* input); + +PUB void Input_Update(Input_State* state); // must be run once per main loop + +PUB mouse_state Input_GetMouseState(); \ No newline at end of file diff --git a/src/archive/src/systems/keys.h b/src/archive/src/systems/keys.h new file mode 100644 index 0000000..6082a59 --- /dev/null +++ b/src/archive/src/systems/keys.h @@ -0,0 +1,59 @@ +#pragma once + +typedef enum keycode { + // TODO: add all keycodes + KEYCODE_SPACE = 32, + KEYCODE_APOSTROPHE = 39, + KEYCODE_COMMA = 44, + KEYCODE_MINUS = 45, + KEYCODE_PERIOD = 46, + KEYCODE_SLASH = 47, + KEYCODE_0 = 48, + KEYCODE_1 = 49, + KEYCODE_2 = 50, + KEYCODE_3 = 51, + KEYCODE_4 = 52, + KEYCODE_5 = 53, + KEYCODE_6 = 54, + KEYCODE_7 = 55, + KEYCODE_8 = 56, + KEYCODE_9 = 57, + KEYCODE_SEMICOLON = 59, + KEYCODE_EQUAL = 61, + KEYCODE_A = 65, + KEYCODE_B = 66, + KEYCODE_C = 67, + KEYCODE_D = 68, + KEYCODE_E = 69, + KEYCODE_F = 70, + KEYCODE_G = 71, + KEYCODE_H = 72, + KEYCODE_I = 73, + KEYCODE_J = 74, + KEYCODE_K = 75, + KEYCODE_L = 76, + KEYCODE_M = 77, + KEYCODE_N = 78, + KEYCODE_O = 79, + KEYCODE_P = 80, + KEYCODE_Q = 81, + KEYCODE_R = 82, + KEYCODE_S = 83, + KEYCODE_T = 84, + KEYCODE_U = 85, + KEYCODE_V = 86, + KEYCODE_W = 87, + KEYCODE_X = 88, + KEYCODE_Y = 89, + KEYCODE_Z = 90, + + KEYCODE_ESCAPE = 256, + KEYCODE_ENTER = 257, + KEYCODE_TAB = 258, + KEYCODE_BACKSPACE = 259, + KEYCODE_KEY_RIGHT = 262, + KEYCODE_KEY_LEFT = 263, + KEYCODE_KEY_DOWN = 264, + KEYCODE_KEY_UP = 265, + KEYCODE_MAX = 348 +} keycode; diff --git a/src/archive/src/systems/screenspace.h b/src/archive/src/systems/screenspace.h new file mode 100644 index 0000000..5f0c579 --- /dev/null +++ b/src/archive/src/systems/screenspace.h @@ -0,0 +1,53 @@ +/** + * @brief Drawing shapes for UI or other reasons in screenspace + */ +#pragma once + +#include "colours.h" +#include "darray.h" +#include "defines.h" +#include "render_types.h" + +/** A draw_cmd packet for rendering a rectangle */ +struct draw_rect { + i32 x, y; // signed ints so we can draw things offscreen (e.g. a window half inside the viewport) + u32 width, height; + rgba colour; + // TODO: border colour, gradients +}; + +/** A draw_cmd packet for rendering a circle */ +struct draw_circle { + i32 x, y; + f32 radius; + rgba colour; +}; + +/** @brief Tagged union that represents a UI shape to be drawn. */ +typedef struct draw_cmd { + enum { DRAW_RECT, CIRCLE } draw_cmd_type; + union { + struct draw_rect rect; + struct draw_circle circle; + }; +} draw_cmd; + +KITC_DECL_TYPED_ARRAY(draw_cmd) + +typedef struct screenspace_state { + u32 rect_vbo; + u32 rect_vao; + // shader rect_shader; + draw_cmd_darray* draw_cmd_buf; +} screenspace_state; + +// --- Lifecycle +bool screenspace_2d_init(screenspace_state* state); +void screenspace_2d_shutdown(screenspace_state* state); +/** Drains the draw_cmd buffer and emits draw calls to render each one */ +void screenspace_2d_render(screenspace_state* state); + +struct core; + +/** @brief Draw a rectangle to the screen. (0,0) is the bottom-left */ +void draw_rectangle(struct core* core, rgba colour, i32 x, i32 y, u32 width, u32 height); \ No newline at end of file diff --git a/src/archive/src/systems/terrain.c b/src/archive/src/systems/terrain.c new file mode 100644 index 0000000..069000e --- /dev/null +++ b/src/archive/src/systems/terrain.c @@ -0,0 +1,204 @@ +/** + * @brief + */ +#include "terrain.h" +#include +#include "file.h" +#include "glad/glad.h" +#include "log.h" +#include "maths.h" +#include "mem.h" +#include "ral_common.h" +#include "ral_impl.h" +#include "ral_types.h" +#include "render.h" +#include "shader_layouts.h" +#include "str.h" + +#define TERRAIN_GRID_U 505 +#define TERRAIN_GRID_V 505 + +bool Terrain_Init(Terrain_Storage* storage) { + storage->grid_dimensions = u32x2(TERRAIN_GRID_U, TERRAIN_GRID_V); + storage->hmap_loaded = false; + + GPU_RenderpassDesc rpass_desc = { + .default_framebuffer = true, + }; + storage->hmap_renderpass = GPU_Renderpass_Create(rpass_desc); + + arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024); + + Str8 vert_path = str8("assets/shaders/terrain.vert"); + Str8 frag_path = str8("assets/shaders/terrain.frag"); + str8_opt vertex_shader = str8_from_file(&scratch, vert_path); + str8_opt fragment_shader = str8_from_file(&scratch, frag_path); + if (!vertex_shader.has_value || !fragment_shader.has_value) { + ERROR_EXIT("Failed to load shaders from disk") + } + + ShaderDataLayout camera_data = Binding_Camera_GetLayout(NULL); + ShaderDataLayout terrain_data = TerrainUniforms_GetLayout(NULL); + + GraphicsPipelineDesc pipeline_desc = { + .debug_name = "terrain rendering pipeline", + .vertex_desc = static_3d_vertex_description(), + .data_layouts = { camera_data, terrain_data }, + .data_layouts_count = 2, + .vs = { + .debug_name = "terrain vertex shader", + .filepath = vert_path, + .code = vertex_shader.contents, + }, + .fs = { + .debug_name = "terrain fragment shader", + .filepath = frag_path, + .code = fragment_shader.contents, + }, + .wireframe = false, + }; + storage->hmap_pipeline = GPU_GraphicsPipeline_Create(pipeline_desc, storage->hmap_renderpass); + + storage->texture = TextureLoadFromFile("assets/demo/textures/grass2.png"); + + return true; +} + +void Terrain_Shutdown(Terrain_Storage* storage) {} + +void Terrain_LoadHeightmap(Terrain_Storage* storage, Heightmap hmap, f32 grid_scale, + bool free_on_upload) { + // If there's a current one we will delete it and reallocate buffers + if (storage->hmap_loaded) { + GPU_BufferDestroy(storage->vertex_buffer); + GPU_BufferDestroy(storage->index_buffer); + } + + u32 width = hmap.pixel_dimensions.x; + u32 height = hmap.pixel_dimensions.y; + storage->grid_scale = grid_scale; + + size_t num_vertices = storage->grid_dimensions.x * storage->grid_dimensions.y; + storage->num_vertices = num_vertices; + + Vertex_darray* vertices = Vertex_darray_new(num_vertices); + u32 index = 0; + for (u32 i = 0; i < storage->grid_dimensions.x; i++) { + for (u32 j = 0; j < storage->grid_dimensions.y; j++) { + size_t position = j * storage->grid_dimensions.x + i; + u8* bytes = hmap.image_data; + u8 channel = bytes[position]; + float value = (float)channel / 255.0; + // printf("(%d, %d) %d : %f \n", i, j, channel, value); + + assert(index < num_vertices); + f32 height = Heightmap_HeightXZ(&hmap, i, j); + Vec3 v_pos = vec3_create(i * grid_scale, height, j * grid_scale); + Vec3 v_normal = VEC3_Y; + float tiling_factor = 505.0f; + Vec2 v_uv = vec2((f32)i / width * tiling_factor, (f32)j / height * tiling_factor); + Vertex v = { .static_3d = { .position = v_pos, .normal = v_normal, .tex_coords = v_uv } }; + Vertex_darray_push(vertices, v); + index++; + } + } + BufferHandle vertices_handle = GPU_BufferCreate(num_vertices * sizeof(Vertex), BUFFER_VERTEX, + BUFFER_FLAG_GPU, vertices->data); + storage->vertex_buffer = vertices_handle; + + u32 quad_count = (width - 1) * (height - 1); + u32 indices_count = quad_count * 6; + storage->indices_count = indices_count; + u32_darray* indices = u32_darray_new(indices_count); + for (u32 i = 0; i < (width - 1); i++) { // row + for (u32 j = 0; j < (height - 1); j++) { // col + u32 bot_left = i * width + j; + u32 top_left = (i + 1) * width + j; + u32 top_right = (i + 1) * width + (j + 1); + u32 bot_right = i * width + j + 1; + + // top left tri + u32_darray_push(indices, top_right); + u32_darray_push(indices, top_left); + u32_darray_push(indices, bot_left); + + // bottom right tri + u32_darray_push(indices, bot_right); + u32_darray_push(indices, top_right); + u32_darray_push(indices, bot_left); + } + } + + BufferHandle indices_handle = + GPU_BufferCreate(indices_count * sizeof(u32), BUFFER_INDEX, BUFFER_FLAG_GPU, indices->data); + storage->index_buffer = indices_handle; +} + +Heightmap Heightmap_FromImage(Str8 filepath) { + size_t max_size = MB(16); + arena arena = arena_create(malloc(max_size), max_size); + // str8_opt maybe_file = str8_from_file(&arena, filepath); + // assert(maybe_file.has_value); + + TextureData hmap_tex = TextureDataLoad(Str8_to_cstr(&arena, filepath), false); + + // arena_free_storage(&arena); + + return (Heightmap){ + .pixel_dimensions = hmap_tex.description.extents, + .filepath = filepath, + .image_data = hmap_tex.image_data, + .num_channels = hmap_tex.description.num_channels, + .is_uploaded = false, + }; +} + +void Terrain_Draw(Terrain_Storage* storage) { + GPU_CmdEncoder* enc = GPU_GetDefaultEncoder(); + GPU_EncodeBindPipeline(enc, storage->hmap_pipeline); + RenderScene* scene = Render_GetScene(); + + Mat4 view, proj; + u32x2 dimensions = GPU_Swapchain_GetDimensions(); + Camera_ViewProj(&scene->camera, (f32)dimensions.x, (f32)dimensions.y, &view, &proj); + Binding_Camera camera_data = { .view = view, + .projection = proj, + .viewPos = vec4(scene->camera.position.x, scene->camera.position.y, + scene->camera.position.z, 1.0) }; + GPU_EncodeBindShaderData(enc, 0, Binding_Camera_GetLayout(&camera_data)); + + TerrainUniforms uniforms = { .tex_slot_1 = storage->texture }; + ShaderDataLayout terrain_data = TerrainUniforms_GetLayout(&uniforms); + GPU_EncodeBindShaderData(enc, 1, terrain_data); + + GPU_EncodeSetVertexBuffer(enc, storage->vertex_buffer); + GPU_EncodeSetIndexBuffer(enc, storage->index_buffer); + + GPU_EncodeDrawIndexedTris(enc, storage->indices_count); + // glDrawArrays(GL_POINTS, 0, storage->num_vertices); +} + +f32 Heightmap_HeightXZ(const Heightmap* hmap, u32 x, u32 z) { + // its single channel so only one byte per pixel + size_t position = x * hmap->pixel_dimensions.x + z; + u8* bytes = hmap->image_data; + u8 channel = bytes[position]; + float value = (float)channel / 2.0; /// 255.0; + return value; +} + +ShaderDataLayout TerrainUniforms_GetLayout(void* data) { + TerrainUniforms* d = data; + bool has_data = data != NULL; + + ShaderBinding b1 = { + .label = "TextureSlot1", + .kind = BINDING_TEXTURE, + .vis = VISIBILITY_FRAGMENT, + }; + + if (has_data) { + b1.data.texture.handle = d->tex_slot_1; + } + return (ShaderDataLayout){ .bindings = { b1 }, .binding_count = 1 }; +} diff --git a/src/archive/src/systems/terrain.h b/src/archive/src/systems/terrain.h new file mode 100644 index 0000000..5a96132 --- /dev/null +++ b/src/archive/src/systems/terrain.h @@ -0,0 +1,72 @@ +/** + * @file terrain.h + * @brief + */ + +#pragma once + +/* +Future: + - Chunked terrain + - Dynamic LOD +*/ + +#include "defines.h" +#include "maths_types.h" +#include "ral_types.h" +#include "render.h" +#include "str.h" + +typedef struct Heightmap { + Str8 filepath; + u32x2 pixel_dimensions; + void* image_data; + u32 num_channels; + bool is_uploaded; +} Heightmap; + +typedef struct Terrain_Storage { + // arena terrain_allocator; + u32x2 grid_dimensions; + f32 grid_scale; + u32 num_vertices; + Heightmap heightmap; // NULL = no heightmap + GPU_Renderpass* hmap_renderpass; + GPU_Pipeline* hmap_pipeline; + TextureHandle texture; + + bool hmap_loaded; + BufferHandle vertex_buffer; + BufferHandle index_buffer; + u32 indices_count; +} Terrain_Storage; + +// --- Public API +PUB bool Terrain_Init(Terrain_Storage* storage); +PUB void Terrain_Shutdown(Terrain_Storage* storage); +PUB void Terrain_Draw( + Terrain_Storage* storage); // NOTE: For now it renders directly to main framebuffer + +/** @brief Sets the active heightmap to be rendered and collided against. */ +PUB void Terrain_LoadHeightmap(Terrain_Storage* storage, Heightmap hmap, f32 grid_scale, + bool free_on_upload); +PUB Heightmap Heightmap_FromImage(Str8 filepath); +PUB Heightmap Heightmap_FromPerlin(/* TODO: perlin noise generation parameters */); + +PUB bool Terrain_IsActive(); // checks whether we have a loaded heightmap and it's being rendered + +/** @brief Get the height (the Y component) for a vertex at a particular coordinate in the heightmap + */ +PUB f32 Heightmap_HeightXZ(const Heightmap* hmap, u32 x, u32 z); + +/** @brief Calculate the normal vector of a vertex at a particular coordinate in the heightmap */ +PUB Vec3 Heightmap_NormalXZ(const Heightmap* hmap, f32 x, f32 z); + +// /** @brief Generate the `geometry_data` for a heightmap ready to be uploaded to the GPU */ +// Geometry geo_heightmap(arena* a, Heightmap heightmap); + +typedef struct TerrainUniforms { + TextureHandle tex_slot_1; +} TerrainUniforms; + +ShaderDataLayout TerrainUniforms_GetLayout(void* data); \ No newline at end of file diff --git a/src/archive/src/systems/text.c b/src/archive/src/systems/text.c new file mode 100644 index 0000000..2bb5399 --- /dev/null +++ b/src/archive/src/systems/text.c @@ -0,0 +1 @@ +// TODO: Port from previous repo \ No newline at end of file diff --git a/src/archive/src/systems/text.h b/src/archive/src/systems/text.h new file mode 100644 index 0000000..983ffd6 --- /dev/null +++ b/src/archive/src/systems/text.h @@ -0,0 +1,53 @@ +/** + * @brief + */ +#pragma once + +#include + +#include "darray.h" +#include "defines.h" +#include "ral.h" +#include "render_types.h" + +// struct core; + +// /** @brief internal font struct */ +// typedef struct font { +// const char *name; +// stbtt_fontinfo stbtt_font; +// stbtt_bakedchar c_data[96]; +// texture_handle bitmap_tex; +// } font; + +// typedef struct draw_text_packet { +// char *contents; +// f32 x; +// f32 y; +// } draw_text_packet; + +// KITC_DECL_TYPED_ARRAY(draw_text_packet) + +// typedef struct text_system_state { +// font default_font; +// shader_handle glyph_shader; +// u32 glyph_vbo; +// u32 glyph_vao; +// draw_text_packet_darray *draw_cmd_buf; +// // TODO: fonts array or hashtable +// } text_system_state; + +// void text_system_render(text_system_state *text); + +// // --- Lifecycle functions +// bool text_system_init(text_system_state *text); +// void text_system_shutdown(text_system_state *text); + +// // --- Drawing + +// /** +// * @brief immediate mode draw text. +// * @note immediately emits draw calls causing a shader program switch if you weren't previously +// drawing text in the current frame. +// */ +// void draw_text(struct core *core, f32 x, f32 y, char *contents); diff --git a/src/archive/src/transform_hierarchy.c b/src/archive/src/transform_hierarchy.c new file mode 100644 index 0000000..a5f4d97 --- /dev/null +++ b/src/archive/src/transform_hierarchy.c @@ -0,0 +1,185 @@ + +/** + * @file transform_hierarchy.h + */ +#pragma once +#include "transform_hierarchy.h" +#include +#include + +#include "core.h" +#include "log.h" +#include "maths.h" +#include "maths_types.h" +#include "render_types.h" + +// struct transform_hierarchy { +// transform_node root; +// }; + +// transform_hierarchy* transform_hierarchy_create() { +// transform_hierarchy* tfh = malloc(sizeof(struct transform_hierarchy)); + +// tfh->root = (transform_node){ .model = { ABSENT_MODEL_HANDLE }, +// .tf = TRANSFORM_DEFAULT, +// .local_matrix_tf = mat4_ident(), +// .world_matrix_tf = mat4_ident(), +// .parent = NULL, +// .children = { 0 }, +// .n_children = 0, +// .tfh = tfh }; +// return tfh; +// } + +// bool free_node(transform_node* node, void* _ctx_data) { +// if (!node) return true; // leaf node +// if (node == &node->tfh->root) { +// WARN("You can't free the root node!"); +// return false; +// } + +// printf("Freed node\n"); +// free(node); +// return true; +// } + +// void transform_hierarchy_free(transform_hierarchy* tfh) { +// transform_hierarchy_dfs(&tfh->root, free_node, false, NULL); +// free(tfh); +// } + +// transform_node* transform_hierarchy_root_node(transform_hierarchy* tfh) { return &tfh->root; } + +// transform_node* transform_hierarchy_add_node(transform_node* parent, ModelHandle model, +// Transform tf) { +// if (!parent) { +// WARN("You tried to add a node to a bad parent (NULL?)"); +// return NULL; +// } +// transform_node* node = malloc(sizeof(transform_node)); +// node->model = model; +// node->tf = tf; +// node->local_matrix_tf = mat4_ident(); +// node->world_matrix_tf = mat4_ident(); +// node->parent = parent; +// memset(node->children, 0, sizeof(node->children)); +// node->n_children = 0; +// node->tfh = parent->tfh; + +// // push into parent's children array +// u32 next_index = parent->n_children; +// if (next_index == MAX_TF_NODE_CHILDREN) { +// ERROR("This transform hierarchy node already has MAX children. Dropping."); +// free(node); +// } else { +// parent->children[next_index] = node; +// parent->n_children++; +// } + +// return node; +// } + +// void transform_hierarchy_delete_node(transform_node* node) { +// // delete all children +// for (u32 i = 0; i < node->n_children; i++) { +// transform_node* child = node->children[i]; +// transform_hierarchy_dfs(child, free_node, false, NULL); +// } + +// if (node->parent) { +// for (u32 i = 0; i < node->parent->n_children; i++) { +// transform_node* child = node->parent->children[i]; +// if (child == node) { +// node->parent->children[i] = NULL; // HACK: this will leave behind empty slots in the +// // children array of the parent. oh well. +// } +// } +// } + +// free(node); +// } + +// void transform_hierarchy_dfs(transform_node* start_node, +// bool (*visit_node)(transform_node* node, void* ctx_data), +// bool is_pre_order, void* ctx_data) { +// if (!start_node) return; + +// bool continue_traversal = true; +// if (is_pre_order) { +// continue_traversal = visit_node(start_node, ctx_data); +// } + +// if (continue_traversal) { +// for (u32 i = 0; i < start_node->n_children; i++) { +// transform_node* child = start_node->children[i]; +// transform_hierarchy_dfs(child, visit_node, is_pre_order, ctx_data); +// } +// } + +// if (!is_pre_order) { +// // post-order +// visit_node(start_node, ctx_data); +// } +// } + +// // Update matrix for the current node +// bool update_matrix(transform_node* node, void* _ctx_data) { +// if (!node) return true; // leaf node + +// if (node->parent && node->parent->tf.is_dirty) { +// node->tf.is_dirty = true; +// } + +// if (node->tf.is_dirty) { +// // invalidates children +// Mat4 updated_local_transform = transform_to_mat(&node->tf); +// node->local_matrix_tf = updated_local_transform; +// if (node->parent) { +// Mat4 updated_world_transform = +// mat4_mult(node->parent->world_matrix_tf, updated_local_transform); +// node->world_matrix_tf = updated_world_transform; +// } +// } + +// return true; +// } + +// void transform_hierarchy_propagate_transforms(transform_hierarchy* tfh) { +// // kickoff traversal +// transform_hierarchy_dfs(&tfh->root, update_matrix, false, NULL); +// } + +// struct print_ctx { +// Core* core; +// u32 indentation_lvl; +// }; + +// bool print_node(transform_node* node, void* ctx_data) { +// struct print_ctx* ctx = (struct print_ctx*)ctx_data; + +// if (!node) return true; +// if (!node->parent) { +// printf("Root Node\n"); +// ctx->indentation_lvl++; +// return true; +// } + +// // Grab the model +// // FIXME +// // model m = ctx->core->models->data[node->model.raw]; +// for (int i = 0; i < ctx->indentation_lvl; i++) { +// printf(" "); +// } +// // printf("Node %s\n", m.name.buf); +// ctx->indentation_lvl++; + +// return true; +// } + +// void transform_hierarchy_debug_print(transform_node* start_node, Core* core) { +// struct print_ctx* ctx = malloc(sizeof(struct print_ctx)); +// ctx->core = core; +// ctx->indentation_lvl = 0; +// transform_hierarchy_dfs(start_node, print_node, true, (void*)ctx); +// free(ctx); +// } diff --git a/src/archive/src/transform_hierarchy.h b/src/archive/src/transform_hierarchy.h new file mode 100644 index 0000000..142ea99 --- /dev/null +++ b/src/archive/src/transform_hierarchy.h @@ -0,0 +1,80 @@ +/** + * @file transform_hierarchy.h + */ +#pragma once + +#include "maths_types.h" +#include "ral.h" +#include "render_types.h" + +#define MAX_TF_NODE_CHILDREN \ + 32 /** TEMP: Make it simpler to manage children in `transform_node`s */ + +typedef struct TransformHierarchy TransformHierarchy; + +struct Transform_Node { + ModelHandle model; /** A handle back to what model this node represents */ + Transform tf; + Mat4 local_matrix_tf; /** cached local affine transform */ + Mat4 world_matrix_tf; /** cached world-space affine transform */ + + struct transform_node* parent; + struct transform_node* children[MAX_TF_NODE_CHILDREN]; + u32 n_children; + struct transform_hierarchy* tfh; +}; +typedef struct Transform_Node Transform_Node; +typedef struct Transform_Node TF_Node; + +// --- Lifecycle + +/** @brief Allocates and returns an empty transform hierarchy with a root node */ +TransformHierarchy* TransformHierarchy_Create(); + +// /** +// * @brief recursively frees all the children and then finally itself +// * @note in the future we can use an object pool for the nodes +// */ +// void transform_hierarchy_free(transform_hierarchy* tfh); + +// // --- Main usecase + +// /** @brief Updates matrices of any invalidated nodes based on the `is_dirty` flag inside +// `transform` +// */ +// void transform_hierarchy_propagate_transforms(transform_hierarchy* tfh); + +// // --- Queries + +// /** @brief Get a pointer to the root node */ +// Transform_Node* TransformHierarchy_RootNode(TransformHierarchy* tfh); + +// // --- Mutations +// Transform_Node* TransformHierarchy_AddNode(transform_node* parent, ModelHandle model, +// Transform tf); +// void transform_hierarchy_delete_node(transform_node* node); + +// // --- Traversal + +// /** +// * @brief Perform a depth-first search traversal starting from `start_node`. +// * @param start_node The starting node of the traversal. +// * @param visit_node The function to call for each node visited. The callback should return false +// to stop the traversal early. +// * @param is_pre_order Indicates whether to do pre-order or post-order traversal i.e. when to +// call the `visit_node` function. +// * @param ctx_data An optional pointer to data that is be passed on each call to `visit_node`. +// Can be used to carry additional information or context. +// * +// * @note The main use-cases are: +// 1. traversing the whole tree to update cached 4x4 affine transform matrices +// (post-order) +// 2. freeing child nodes after deleting a node in the tree (post-order) +// 3. debug pretty printing the whole tree (post-order) +// */ +// void transform_hierarchy_dfs(transform_node* start_node, +// bool (*visit_node)(transform_node* node, void* ctx_data), +// bool is_pre_order, void* ctx_data); + +// struct Core; +// void transform_hierarchy_debug_print(transform_node* start_node, struct Core* core); diff --git a/src/archive/xmake.lua b/src/archive/xmake.lua new file mode 100644 index 0000000..3c05a70 --- /dev/null +++ b/src/archive/xmake.lua @@ -0,0 +1,205 @@ +-- set_project("celeritas") +-- set_version("0.1.0") +-- set_config("cc", "clang") + +-- add_rules("mode.debug", "mode.release") -- we have two modes: debug & release + +-- -- -Wall : base set of warnings +-- -- -Wextra : additional warnings not covered by -Wall +-- -- -Wundef : undefined macros +-- -- -Wdouble-promotion : catch implicit converion of float to double +-- add_cflags("-Wall", "-Wextra", "-Wundef", "-Wdouble-promotion") + +-- if is_mode("debug") then +-- add_cflags("-g") -- Add debug symbols in debug mode +-- add_defines("CDEBUG") +-- elseif is_mode("release") then +-- add_defines("CRELEASE") +-- end + +-- -- Platform defines and system packages +-- if is_plat("linux") then +-- add_defines("CEL_PLATFORM_LINUX") +-- add_syslinks("dl", "X11", "pthread") --, "vulkan") +-- elseif is_plat("windows") then +-- add_defines("CEL_PLATFORM_WINDOWS") +-- add_syslinks("user32", "gdi32", "kernel32", "shell32") +-- -- add_requires("vulkansdk", { system = true }) +-- -- add_links("pthreadVC2-w64") +-- elseif is_plat("macosx") then +-- add_defines("CEL_PLATFORM_MAC") +-- add_frameworks("Cocoa", "IOKit", "CoreVideo", "OpenGL") +-- add_frameworks("Foundation", "Metal", "QuartzCore") +-- set_runenv("MTL_DEBUG_LAYER", "1") +-- add_requires("vulkansdk", { system = true }) +-- -- add_syslinks("GL") +-- end + +-- -- Compile GLFW from source +-- package("local_glfw") +-- add_deps("cmake") +-- set_sourcedir(path.join(os.scriptdir(), "deps/glfw-3.3.8")) +-- on_install(function(package) +-- local configs = {} +-- -- NOTE(omni): Keeping these around as comments in case we need to modify glfw flags +-- -- table.insert(configs, "-DCMAKE_BUILD_TYPE=" .. (package:debug() and "Debug" or "Release")) +-- -- table.insert(configs, "-DBUILD_SHARED_LIBS=" .. (package:config("shared") and "ON" or "OFF")) +-- import("package.tools.cmake").install(package, configs) +-- end) +-- on_test(function(package) +-- -- assert(package:has_cfuncs("add", {includes = "foo.h"})) +-- end) +-- package_end() + +-- add_requires("local_glfw") + +-- local core_sources = { +-- "deps/glad/src/glad.c", +-- "src/*.c", +-- "src/core/*.c", +-- "src/logos/*.c", +-- "src/maths/*.c", +-- "src/platform/*.c", +-- "src/ral/*.c", +-- "src/ral/backends/opengl/*.c", +-- "src/render/*.c", +-- "src/resources/*.c", +-- "src/std/*.c", +-- "src/std/containers/*.c", +-- "src/systems/*.c", +-- } + +-- local unity_sources = { +-- "deps/Unity/src/unity.c", +-- "deps/Unity/extras/fixture/src/unity_fixture.c", +-- "deps/Unity/extras/memory/src/unity_memory.c", +-- } + +-- rule("compile_glsl_vert_shaders") +-- set_extensions(".vert") +-- on_buildcmd_file(function(target, batchcmds, sourcefile, opt) +-- local targetfile = path.join(target:targetdir(), path.basename(sourcefile) .. ".vert.spv") + +-- print("Compiling shader: %s to %s", sourcefile, targetfile) +-- batchcmds:vrunv('glslc', { sourcefile, "-o", targetfile }) +-- -- batchcmds:add_depfiles(sourcefile) +-- end) + +-- rule("compile_glsl_frag_shaders") +-- set_extensions(".frag") +-- on_buildcmd_file(function(target, batchcmds, sourcefile, opt) +-- local targetfile = path.join(target:targetdir(), path.basename(sourcefile) .. ".frag.spv") + +-- print("Compiling shader: %s to %s", sourcefile, targetfile) +-- batchcmds:vrunv('glslc', { sourcefile, "-o", targetfile }) +-- -- batchcmds:add_depfiles(sourcefile) +-- end) +-- -- TODO: Metal shaders compilation + +-- -- common configuration for both static and shared libraries +-- target("core_config") +-- set_kind("static") -- kind is required but you can ignore it since it's just for common settings +-- add_packages("local_glfw") +-- add_defines("CEL_REND_BACKEND_OPENGL") +-- add_includedirs("deps/cgltf", { public = true }) +-- add_includedirs("deps/glfw-3.3.8/include/GLFW", { public = true }) +-- add_includedirs("deps/glad/include", { public = true }) +-- add_includedirs("deps/stb_image", { public = true }) +-- add_includedirs("deps/stb_image_write", { public = true }) +-- add_includedirs("deps/stb_truetype", { public = true }) +-- add_includedirs("include/", { public = true }) +-- add_includedirs("src/", { public = true }) +-- add_includedirs("src/core", { public = true }) +-- add_includedirs("src/logos/", { public = true }) +-- add_includedirs("src/maths/", { public = true }) +-- add_includedirs("src/platform/", { public = true }) +-- add_includedirs("src/ral", { public = true }) +-- add_includedirs("src/ral/backends/opengl", { public = true }) +-- add_includedirs("src/render", { public = true }) +-- add_includedirs("src/ral/backends/vulkan", { public = true }) +-- add_includedirs("src/resources/", { public = true }) +-- add_includedirs("src/std/", { public = true }) +-- add_includedirs("src/std/containers", { public = true }) +-- add_includedirs("src/systems/", { public = true }) +-- add_files("src/empty.c") -- for some reason we need this on Mac so it doesnt call 'ar' with no files and error +-- -- add_rules("compile_glsl_vert_shaders") +-- -- add_rules("compile_glsl_frag_shaders") +-- -- add_files("assets/shaders/*.frag") +-- if is_plat("windows") then +-- -- add_includedirs("$(env VULKAN_SDK)/Include", { public = true }) +-- -- add_linkdirs("$(env VULKAN_SDK)/Lib", { public = true }) +-- -- add_links("vulkan-1") +-- end +-- if is_plat("macosx") then +-- -- add_files("src/renderer/backends/metal/*.m") +-- -- add_files("src/ral/backends/vulkan/*.c") +-- end +-- set_default(false) -- prevents standalone building of this target + +-- target("core_static") +-- set_kind("static") +-- add_deps("core_config") -- inherit common configurations +-- set_policy("build.merge_archive", true) +-- add_files(core_sources) +-- -- Link against static CRT +-- if is_plat("windows") then +-- add_links("libcmt", "legacy_stdio_definitions") -- for release builds +-- add_links("libcmtd", "legacy_stdio_definitions") -- for debug builds +-- end + +-- target("core_shared") +-- set_kind("shared") +-- add_deps("core_config") -- inherit common configurations +-- add_files(core_sources) +-- -- Link against dynamic CRT +-- if is_plat("windows") then +-- add_links("msvcrt", "legacy_stdio_definitions") -- for release builds +-- add_links("msvcrtd", "legacy_stdio_definitions") -- for debug builds +-- end + +-- -- target("main_loop") +-- -- set_kind("binary") +-- -- set_group("examples") +-- -- add_deps("core_static") +-- -- add_files("examples/main_loop/ex_main_loop.c") +-- -- set_rundir("$(projectdir)") + +-- -- target("tri") +-- -- set_kind("binary") +-- -- set_group("examples") +-- -- add_deps("core_static") +-- -- add_files("examples/triangle/ex_triangle.c") +-- -- set_rundir("$(projectdir)") +-- -- if is_plat("macosx") then +-- -- before_build(function (target) +-- -- print("build metal shaders lib") +-- -- os.exec("mkdir -p build/shaders") +-- -- os.exec("xcrun -sdk macosx metal -c assets/shaders/triangle.metal -o build/shaders/gfx.air") +-- -- os.exec("xcrun -sdk macosx metallib build/shaders/gfx.air -o build/gfx.metallib") +-- -- end) +-- -- end + +-- target("skinned") +-- set_kind("binary") +-- set_group("examples") +-- add_deps("core_shared") +-- add_files("examples/skinned_animation/ex_skinned_animation.c") +-- set_rundir("$(projectdir)") + +-- target("game") +-- set_kind("binary") +-- set_group("examples") +-- add_deps("core_static") +-- add_files("examples/game_demo/game_demo.c") +-- set_rundir("$(projectdir)") + +-- target("pool_tests") +-- set_kind("binary") +-- set_group("tests") +-- add_deps("core_static") +-- add_files(unity_sources) +-- add_includedirs("deps/Unity/src", {public = true}) +-- add_includedirs("deps/Unity/extras/fixture/src", {public = true}) +-- add_includedirs("deps/Unity/extras/memory/src", {public = true}) +-- add_files("tests/pool_tests.c") +-- add_files("tests/pool_test_runner.c") -- cgit v1.2.3-70-g09d2