diff options
| -rw-r--r-- | CMakeLists.txt | 91 | ||||
| -rw-r--r-- | README.md (renamed from gfx/README.md) | 0 | ||||
| -rwxr-xr-x | bin/txt2c.py (renamed from gfx/bin/txt2c.py) | 0 | ||||
| -rw-r--r-- | cmake/shader.txt (renamed from gfx/cmake/shader.txt) | 0 | ||||
| -rw-r--r-- | cmake/txt2c.txt (renamed from gfx/cmake/txt2c.txt) | 0 | ||||
| -rw-r--r-- | contrib/cgltf-tangents/CMakeLists.txt (renamed from gfx/contrib/cgltf-tangents/CMakeLists.txt) | 0 | ||||
| -rw-r--r-- | contrib/cgltf-tangents/LICENSE (renamed from gfx/contrib/cgltf-tangents/LICENSE) | 0 | ||||
| -rw-r--r-- | contrib/cgltf-tangents/MikkTSpace/README.md (renamed from gfx/contrib/cgltf-tangents/MikkTSpace/README.md) | 0 | ||||
| -rw-r--r-- | contrib/cgltf-tangents/MikkTSpace/mikktspace.c (renamed from gfx/contrib/cgltf-tangents/MikkTSpace/mikktspace.c) | 0 | ||||
| -rw-r--r-- | contrib/cgltf-tangents/MikkTSpace/mikktspace.h (renamed from gfx/contrib/cgltf-tangents/MikkTSpace/mikktspace.h) | 0 | ||||
| -rw-r--r-- | contrib/cgltf-tangents/README.md (renamed from gfx/contrib/cgltf-tangents/README.md) | 0 | ||||
| -rw-r--r-- | contrib/cgltf-tangents/cgltf_tangents.c (renamed from gfx/contrib/cgltf-tangents/cgltf_tangents.c) | 0 | ||||
| -rw-r--r-- | contrib/cgltf-tangents/cgltf_tangents.h (renamed from gfx/contrib/cgltf-tangents/cgltf_tangents.h) | 0 | ||||
| -rw-r--r-- | contrib/cgltf-tangents/test/CMakeLists.txt (renamed from gfx/contrib/cgltf-tangents/test/CMakeLists.txt) | 0 | ||||
| -rw-r--r-- | contrib/cgltf-tangents/test/main.c (renamed from gfx/contrib/cgltf-tangents/test/main.c) | 0 | ||||
| -rw-r--r-- | contrib/cgltf/CMakeLists.txt (renamed from gfx/contrib/cgltf/CMakeLists.txt) | 0 | ||||
| -rw-r--r-- | contrib/cgltf/LICENSE (renamed from gfx/contrib/cgltf/LICENSE) | 0 | ||||
| -rw-r--r-- | contrib/cgltf/README.md (renamed from gfx/contrib/cgltf/README.md) | 0 | ||||
| -rw-r--r-- | contrib/cgltf/cgltf.h (renamed from gfx/contrib/cgltf/cgltf.h) | 0 | ||||
| -rw-r--r-- | contrib/cgltf/cgltf_write.h (renamed from gfx/contrib/cgltf/cgltf_write.h) | 0 | ||||
| -rw-r--r-- | contrib/stb/CMakeLists.txt (renamed from gfx/contrib/stb/CMakeLists.txt) | 0 | ||||
| -rw-r--r-- | contrib/stb/stb_image.h (renamed from gfx/contrib/stb/stb_image.h) | 0 | ||||
| -rw-r--r-- | doc/extern/2013SiggraphPresentationsNotes-26915738.pdf (renamed from gfx/doc/extern/2013SiggraphPresentationsNotes-26915738.pdf) | bin | 2947929 -> 2947929 bytes | |||
| -rw-r--r-- | doc/extern/Scene Graph - CSE 167.pdf (renamed from gfx/doc/extern/Scene Graph - CSE 167.pdf) | bin | 890801 -> 890801 bytes | |||
| -rw-r--r-- | doc/gfx.png (renamed from gfx/doc/gfx.png) | bin | 6272 -> 6272 bytes | |||
| -rw-r--r-- | doc/gfx.txt (renamed from gfx/doc/gfx.txt) | 0 | ||||
| -rw-r--r-- | doc/gltfOverview-2.0.0b.png (renamed from gfx/doc/gltfOverview-2.0.0b.png) | bin | 4757973 -> 4757973 bytes | |||
| -rw-r--r-- | doc/pipeline.png (renamed from gfx/doc/pipeline.png) | bin | 10318 -> 10318 bytes | |||
| -rw-r--r-- | doc/pipeline.txt (renamed from gfx/doc/pipeline.txt) | 0 | ||||
| -rw-r--r-- | doc/renderer.png (renamed from gfx/doc/renderer.png) | bin | 13144 -> 13144 bytes | |||
| -rw-r--r-- | doc/renderer.txt (renamed from gfx/doc/renderer.txt) | 0 | ||||
| -rw-r--r-- | doc/scene.png (renamed from gfx/doc/scene.png) | bin | 59119 -> 59119 bytes | |||
| -rw-r--r-- | doc/scene.txt (renamed from gfx/doc/scene.txt) | 0 | ||||
| -rw-r--r-- | game/CMakeLists.txt | 22 | ||||
| -rw-r--r-- | game/src/game.c | 218 | ||||
| -rw-r--r-- | game/src/game.h | 21 | ||||
| -rw-r--r-- | game/src/plugins/CMakeLists.txt | 29 | ||||
| -rw-r--r-- | game/src/plugins/plugin.h | 52 | ||||
| -rw-r--r-- | game/src/plugins/pong.c | 237 | ||||
| -rw-r--r-- | game/src/plugins/texture_view.c | 144 | ||||
| -rw-r--r-- | game/src/plugins/viewer.c | 374 | ||||
| -rw-r--r-- | gfx-iso/CMakeLists.txt | 42 | ||||
| -rw-r--r-- | gfx-iso/demos/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | gfx-iso/demos/checkerboard/CMakeLists.txt | 16 | ||||
| -rw-r--r-- | gfx-iso/demos/checkerboard/checkerboard.c | 166 | ||||
| -rw-r--r-- | gfx-iso/demos/isomap/CMakeLists.txt | 16 | ||||
| -rw-r--r-- | gfx-iso/demos/isomap/isomap.c | 105 | ||||
| -rw-r--r-- | gfx-iso/include/isogfx/backend.h | 28 | ||||
| -rw-r--r-- | gfx-iso/include/isogfx/isogfx.h | 136 | ||||
| -rw-r--r-- | gfx-iso/src/backend.c | 199 | ||||
| -rw-r--r-- | gfx-iso/src/isogfx.c | 952 | ||||
| -rw-r--r-- | gfx-iso/tools/mkasset.py | 324 | ||||
| -rw-r--r-- | gfx/CMakeLists.txt | 89 | ||||
| -rw-r--r-- | include/gfx/asset.h (renamed from gfx/include/gfx/asset.h) | 0 | ||||
| -rw-r--r-- | include/gfx/core.h (renamed from gfx/include/gfx/core.h) | 0 | ||||
| -rw-r--r-- | include/gfx/gfx.h (renamed from gfx/include/gfx/gfx.h) | 0 | ||||
| -rw-r--r-- | include/gfx/renderer.h (renamed from gfx/include/gfx/renderer.h) | 0 | ||||
| -rw-r--r-- | include/gfx/scene.h (renamed from gfx/include/gfx/scene.h) | 0 | ||||
| -rw-r--r-- | include/gfx/scene/animation.h (renamed from gfx/include/gfx/scene/animation.h) | 0 | ||||
| -rw-r--r-- | include/gfx/scene/camera.h (renamed from gfx/include/gfx/scene/camera.h) | 0 | ||||
| -rw-r--r-- | include/gfx/scene/light.h (renamed from gfx/include/gfx/scene/light.h) | 0 | ||||
| -rw-r--r-- | include/gfx/scene/material.h (renamed from gfx/include/gfx/scene/material.h) | 0 | ||||
| -rw-r--r-- | include/gfx/scene/mesh.h (renamed from gfx/include/gfx/scene/mesh.h) | 0 | ||||
| -rw-r--r-- | include/gfx/scene/model.h (renamed from gfx/include/gfx/scene/model.h) | 0 | ||||
| -rw-r--r-- | include/gfx/scene/node.h (renamed from gfx/include/gfx/scene/node.h) | 0 | ||||
| -rw-r--r-- | include/gfx/scene/object.h (renamed from gfx/include/gfx/scene/object.h) | 0 | ||||
| -rw-r--r-- | include/gfx/scene/scene.h (renamed from gfx/include/gfx/scene/scene.h) | 0 | ||||
| -rw-r--r-- | include/gfx/sizes.h (renamed from gfx/include/gfx/sizes.h) | 0 | ||||
| -rw-r--r-- | include/gfx/util/geometry.h (renamed from gfx/include/gfx/util/geometry.h) | 0 | ||||
| -rw-r--r-- | include/gfx/util/ibl.h (renamed from gfx/include/gfx/util/ibl.h) | 0 | ||||
| -rw-r--r-- | include/gfx/util/shader.h (renamed from gfx/include/gfx/util/shader.h) | 0 | ||||
| -rw-r--r-- | include/gfx/util/skyquad.h (renamed from gfx/include/gfx/util/skyquad.h) | 0 | ||||
| -rw-r--r-- | shaders/brdf_integration_map.frag (renamed from gfx/shaders/brdf_integration_map.frag) | 0 | ||||
| -rw-r--r-- | shaders/cook_torrance.frag (renamed from gfx/shaders/cook_torrance.frag) | 0 | ||||
| -rw-r--r-- | shaders/cook_torrance.vert (renamed from gfx/shaders/cook_torrance.vert) | 0 | ||||
| -rw-r--r-- | shaders/cubemap_filtering.vert (renamed from gfx/shaders/cubemap_filtering.vert) | 0 | ||||
| -rw-r--r-- | shaders/debug3d.frag (renamed from gfx/shaders/debug3d.frag) | 0 | ||||
| -rw-r--r-- | shaders/debug3d.vert (renamed from gfx/shaders/debug3d.vert) | 0 | ||||
| -rw-r--r-- | shaders/immediate_mode.frag (renamed from gfx/shaders/immediate_mode.frag) | 0 | ||||
| -rw-r--r-- | shaders/immediate_mode.vert (renamed from gfx/shaders/immediate_mode.vert) | 0 | ||||
| -rw-r--r-- | shaders/irradiance_map.frag (renamed from gfx/shaders/irradiance_map.frag) | 0 | ||||
| -rw-r--r-- | shaders/prefiltered_environment_map.frag (renamed from gfx/shaders/prefiltered_environment_map.frag) | 0 | ||||
| -rw-r--r-- | shaders/quad.vert (renamed from gfx/shaders/quad.vert) | 0 | ||||
| -rw-r--r-- | shaders/skyquad.frag (renamed from gfx/shaders/skyquad.frag) | 0 | ||||
| -rw-r--r-- | shaders/skyquad.vert (renamed from gfx/shaders/skyquad.vert) | 0 | ||||
| -rw-r--r-- | shaders/view_normal_mapped_normals.frag (renamed from gfx/shaders/view_normal_mapped_normals.frag) | 0 | ||||
| -rw-r--r-- | shaders/view_normal_mapped_normals.vert (renamed from gfx/shaders/view_normal_mapped_normals.vert) | 0 | ||||
| -rw-r--r-- | shaders/view_normals.frag (renamed from gfx/shaders/view_normals.frag) | 0 | ||||
| -rw-r--r-- | shaders/view_normals.vert (renamed from gfx/shaders/view_normals.vert) | 0 | ||||
| -rw-r--r-- | shaders/view_tangents.frag (renamed from gfx/shaders/view_tangents.frag) | 0 | ||||
| -rw-r--r-- | shaders/view_tangents.vert (renamed from gfx/shaders/view_tangents.vert) | 0 | ||||
| -rw-r--r-- | shaders/view_texture.frag (renamed from gfx/shaders/view_texture.frag) | 0 | ||||
| -rw-r--r-- | shaders/view_texture.vert (renamed from gfx/shaders/view_texture.vert) | 0 | ||||
| -rw-r--r-- | src/asset/asset_cache.c (renamed from gfx/src/asset/asset_cache.c) | 0 | ||||
| -rw-r--r-- | src/asset/asset_cache.h (renamed from gfx/src/asset/asset_cache.h) | 0 | ||||
| -rw-r--r-- | src/asset/model.c (renamed from gfx/src/asset/model.c) | 0 | ||||
| -rw-r--r-- | src/asset/model.h (renamed from gfx/src/asset/model.h) | 0 | ||||
| -rw-r--r-- | src/asset/texture.c (renamed from gfx/src/asset/texture.c) | 0 | ||||
| -rw-r--r-- | src/asset/texture.h (renamed from gfx/src/asset/texture.h) | 0 | ||||
| -rw-r--r-- | src/core/buffer.c (renamed from gfx/src/core/buffer.c) | 0 | ||||
| -rw-r--r-- | src/core/buffer.h (renamed from gfx/src/core/buffer.h) | 0 | ||||
| -rw-r--r-- | src/core/constants.h (renamed from gfx/src/core/constants.h) | 0 | ||||
| -rw-r--r-- | src/core/core.c (renamed from gfx/src/core/core.c) | 0 | ||||
| -rw-r--r-- | src/core/core_impl.h (renamed from gfx/src/core/core_impl.h) | 0 | ||||
| -rw-r--r-- | src/core/framebuffer.c (renamed from gfx/src/core/framebuffer.c) | 0 | ||||
| -rw-r--r-- | src/core/framebuffer.h (renamed from gfx/src/core/framebuffer.h) | 0 | ||||
| -rw-r--r-- | src/core/geometry.c (renamed from gfx/src/core/geometry.c) | 0 | ||||
| -rw-r--r-- | src/core/geometry.h (renamed from gfx/src/core/geometry.h) | 0 | ||||
| -rw-r--r-- | src/core/gl_util.h (renamed from gfx/src/core/gl_util.h) | 0 | ||||
| -rw-r--r-- | src/core/renderbuffer.c (renamed from gfx/src/core/renderbuffer.c) | 0 | ||||
| -rw-r--r-- | src/core/renderbuffer.h (renamed from gfx/src/core/renderbuffer.h) | 0 | ||||
| -rw-r--r-- | src/core/shader.c (renamed from gfx/src/core/shader.c) | 0 | ||||
| -rw-r--r-- | src/core/shader.h (renamed from gfx/src/core/shader.h) | 0 | ||||
| -rw-r--r-- | src/core/shader_program.c (renamed from gfx/src/core/shader_program.c) | 0 | ||||
| -rw-r--r-- | src/core/shader_program.h (renamed from gfx/src/core/shader_program.h) | 0 | ||||
| -rw-r--r-- | src/core/texture.c (renamed from gfx/src/core/texture.c) | 0 | ||||
| -rw-r--r-- | src/core/texture.h (renamed from gfx/src/core/texture.h) | 0 | ||||
| -rw-r--r-- | src/gfx.c (renamed from gfx/src/gfx.c) | 0 | ||||
| -rw-r--r-- | src/gfx_assert.h (renamed from gfx/src/gfx_assert.h) | 0 | ||||
| -rw-r--r-- | src/renderer/imm_renderer.c (renamed from gfx/src/renderer/imm_renderer.c) | 0 | ||||
| -rw-r--r-- | src/renderer/imm_renderer_impl.h (renamed from gfx/src/renderer/imm_renderer_impl.h) | 0 | ||||
| -rw-r--r-- | src/renderer/renderer.c (renamed from gfx/src/renderer/renderer.c) | 0 | ||||
| -rw-r--r-- | src/renderer/renderer_impl.h (renamed from gfx/src/renderer/renderer_impl.h) | 0 | ||||
| -rw-r--r-- | src/scene/animation.c (renamed from gfx/src/scene/animation.c) | 0 | ||||
| -rw-r--r-- | src/scene/animation_impl.h (renamed from gfx/src/scene/animation_impl.h) | 0 | ||||
| -rw-r--r-- | src/scene/camera.c (renamed from gfx/src/scene/camera.c) | 0 | ||||
| -rw-r--r-- | src/scene/camera_impl.h (renamed from gfx/src/scene/camera_impl.h) | 0 | ||||
| -rw-r--r-- | src/scene/light.c (renamed from gfx/src/scene/light.c) | 0 | ||||
| -rw-r--r-- | src/scene/light_impl.h (renamed from gfx/src/scene/light_impl.h) | 0 | ||||
| -rw-r--r-- | src/scene/material.c (renamed from gfx/src/scene/material.c) | 0 | ||||
| -rw-r--r-- | src/scene/material_impl.h (renamed from gfx/src/scene/material_impl.h) | 0 | ||||
| -rw-r--r-- | src/scene/mesh.c (renamed from gfx/src/scene/mesh.c) | 0 | ||||
| -rw-r--r-- | src/scene/mesh_impl.h (renamed from gfx/src/scene/mesh_impl.h) | 0 | ||||
| -rw-r--r-- | src/scene/model.c (renamed from gfx/src/scene/model.c) | 0 | ||||
| -rw-r--r-- | src/scene/model_impl.h (renamed from gfx/src/scene/model_impl.h) | 0 | ||||
| -rw-r--r-- | src/scene/node.c (renamed from gfx/src/scene/node.c) | 0 | ||||
| -rw-r--r-- | src/scene/node_impl.h (renamed from gfx/src/scene/node_impl.h) | 0 | ||||
| -rw-r--r-- | src/scene/object.c (renamed from gfx/src/scene/object.c) | 0 | ||||
| -rw-r--r-- | src/scene/object_impl.h (renamed from gfx/src/scene/object_impl.h) | 0 | ||||
| -rw-r--r-- | src/scene/scene.c (renamed from gfx/src/scene/scene.c) | 0 | ||||
| -rw-r--r-- | src/scene/scene_graph.h (renamed from gfx/src/scene/scene_graph.h) | 0 | ||||
| -rw-r--r-- | src/scene/scene_impl.h (renamed from gfx/src/scene/scene_impl.h) | 0 | ||||
| -rw-r--r-- | src/scene/scene_memory.c (renamed from gfx/src/scene/scene_memory.c) | 0 | ||||
| -rw-r--r-- | src/scene/scene_memory.h (renamed from gfx/src/scene/scene_memory.h) | 0 | ||||
| -rw-r--r-- | src/scene/types.h (renamed from gfx/src/scene/types.h) | 0 | ||||
| -rw-r--r-- | src/util/geometry.c (renamed from gfx/src/util/geometry.c) | 0 | ||||
| -rw-r--r-- | src/util/ibl.c (renamed from gfx/src/util/ibl.c) | 0 | ||||
| -rw-r--r-- | src/util/shader.c (renamed from gfx/src/util/shader.c) | 0 | ||||
| -rw-r--r-- | src/util/skyquad.c (renamed from gfx/src/util/skyquad.c) | 0 |
149 files changed, 87 insertions, 3176 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 25c7560..b13f28b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -1,8 +1,91 @@ | |||
| 1 | cmake_minimum_required(VERSION 3.0) | 1 | cmake_minimum_required(VERSION 3.0) |
| 2 | 2 | ||
| 3 | project(gfx-all) | 3 | include(cmake/shader.txt) |
| 4 | |||
| 5 | add_subdirectory(contrib/cgltf) | ||
| 6 | add_subdirectory(contrib/cgltf-tangents) | ||
| 7 | add_subdirectory(contrib/stb) | ||
| 4 | 8 | ||
| 5 | add_subdirectory(app) | 9 | add_subdirectory(app) |
| 6 | add_subdirectory(gfx) | 10 | |
| 7 | add_subdirectory(gfx-iso) | 11 | project(gfx) |
| 8 | add_subdirectory(game) | 12 | |
| 13 | add_shader_library(shaders | ||
| 14 | shaders/brdf_integration_map.frag | ||
| 15 | shaders/cook_torrance.frag | ||
| 16 | shaders/cook_torrance.vert | ||
| 17 | shaders/cubemap_filtering.vert | ||
| 18 | shaders/debug3d.frag | ||
| 19 | shaders/debug3d.vert | ||
| 20 | shaders/immediate_mode.frag | ||
| 21 | shaders/immediate_mode.vert | ||
| 22 | shaders/irradiance_map.frag | ||
| 23 | shaders/prefiltered_environment_map.frag | ||
| 24 | shaders/quad.vert | ||
| 25 | shaders/skyquad.frag | ||
| 26 | shaders/skyquad.vert | ||
| 27 | shaders/view_normal_mapped_normals.frag | ||
| 28 | shaders/view_normal_mapped_normals.vert | ||
| 29 | shaders/view_normals.frag | ||
| 30 | shaders/view_normals.vert | ||
| 31 | shaders/view_tangents.frag | ||
| 32 | shaders/view_tangents.vert | ||
| 33 | shaders/view_texture.frag | ||
| 34 | shaders/view_texture.vert) | ||
| 35 | |||
| 36 | add_library(gfx SHARED | ||
| 37 | src/asset/asset_cache.c | ||
| 38 | src/asset/model.c | ||
| 39 | src/asset/texture.c | ||
| 40 | src/core/buffer.c | ||
| 41 | src/core/core.c | ||
| 42 | src/core/framebuffer.c | ||
| 43 | src/core/geometry.c | ||
| 44 | src/core/renderbuffer.c | ||
| 45 | src/core/shader_program.c | ||
| 46 | src/core/shader.c | ||
| 47 | src/core/texture.c | ||
| 48 | src/renderer/imm_renderer.c | ||
| 49 | src/renderer/renderer.c | ||
| 50 | src/scene/animation.c | ||
| 51 | src/scene/camera.c | ||
| 52 | src/scene/light.c | ||
| 53 | src/scene/material.c | ||
| 54 | src/scene/mesh.c | ||
| 55 | src/scene/model.c | ||
| 56 | src/scene/node.c | ||
| 57 | src/scene/object.c | ||
| 58 | src/scene/scene.c | ||
| 59 | src/scene/scene_memory.c | ||
| 60 | src/gfx.c | ||
| 61 | src/util/geometry.c | ||
| 62 | src/util/ibl.c | ||
| 63 | src/util/shader.c | ||
| 64 | src/util/skyquad.c) | ||
| 65 | |||
| 66 | target_include_directories(gfx PUBLIC | ||
| 67 | include) | ||
| 68 | |||
| 69 | target_include_directories(gfx PRIVATE | ||
| 70 | src) | ||
| 71 | |||
| 72 | target_compile_options(gfx PRIVATE -std=gnu11 -Wall -Wextra -Wpedantic) | ||
| 73 | |||
| 74 | target_link_libraries(gfx PUBLIC | ||
| 75 | cstring | ||
| 76 | math) | ||
| 77 | |||
| 78 | target_link_libraries(gfx PRIVATE | ||
| 79 | cassert | ||
| 80 | cgltf | ||
| 81 | cgltf-tangents | ||
| 82 | error | ||
| 83 | gfx-app | ||
| 84 | log | ||
| 85 | mempool | ||
| 86 | shaders | ||
| 87 | stb | ||
| 88 | # System libraries. | ||
| 89 | GL | ||
| 90 | # Required to initialize GLAD. | ||
| 91 | -ldl) | ||
diff --git a/gfx/README.md b/README.md index f0b103d..f0b103d 100644 --- a/gfx/README.md +++ b/README.md | |||
diff --git a/gfx/bin/txt2c.py b/bin/txt2c.py index 1d8ff70..1d8ff70 100755 --- a/gfx/bin/txt2c.py +++ b/bin/txt2c.py | |||
diff --git a/gfx/cmake/shader.txt b/cmake/shader.txt index 8273f4d..8273f4d 100644 --- a/gfx/cmake/shader.txt +++ b/cmake/shader.txt | |||
diff --git a/gfx/cmake/txt2c.txt b/cmake/txt2c.txt index 0cb11a9..0cb11a9 100644 --- a/gfx/cmake/txt2c.txt +++ b/cmake/txt2c.txt | |||
diff --git a/gfx/contrib/cgltf-tangents/CMakeLists.txt b/contrib/cgltf-tangents/CMakeLists.txt index 2c0771e..2c0771e 100644 --- a/gfx/contrib/cgltf-tangents/CMakeLists.txt +++ b/contrib/cgltf-tangents/CMakeLists.txt | |||
diff --git a/gfx/contrib/cgltf-tangents/LICENSE b/contrib/cgltf-tangents/LICENSE index 7796e37..7796e37 100644 --- a/gfx/contrib/cgltf-tangents/LICENSE +++ b/contrib/cgltf-tangents/LICENSE | |||
diff --git a/gfx/contrib/cgltf-tangents/MikkTSpace/README.md b/contrib/cgltf-tangents/MikkTSpace/README.md index 9fda155..9fda155 100644 --- a/gfx/contrib/cgltf-tangents/MikkTSpace/README.md +++ b/contrib/cgltf-tangents/MikkTSpace/README.md | |||
diff --git a/gfx/contrib/cgltf-tangents/MikkTSpace/mikktspace.c b/contrib/cgltf-tangents/MikkTSpace/mikktspace.c index 0342ae0..0342ae0 100644 --- a/gfx/contrib/cgltf-tangents/MikkTSpace/mikktspace.c +++ b/contrib/cgltf-tangents/MikkTSpace/mikktspace.c | |||
diff --git a/gfx/contrib/cgltf-tangents/MikkTSpace/mikktspace.h b/contrib/cgltf-tangents/MikkTSpace/mikktspace.h index 52c44a7..52c44a7 100644 --- a/gfx/contrib/cgltf-tangents/MikkTSpace/mikktspace.h +++ b/contrib/cgltf-tangents/MikkTSpace/mikktspace.h | |||
diff --git a/gfx/contrib/cgltf-tangents/README.md b/contrib/cgltf-tangents/README.md index 2a68b27..2a68b27 100644 --- a/gfx/contrib/cgltf-tangents/README.md +++ b/contrib/cgltf-tangents/README.md | |||
diff --git a/gfx/contrib/cgltf-tangents/cgltf_tangents.c b/contrib/cgltf-tangents/cgltf_tangents.c index 80b1e56..80b1e56 100644 --- a/gfx/contrib/cgltf-tangents/cgltf_tangents.c +++ b/contrib/cgltf-tangents/cgltf_tangents.c | |||
diff --git a/gfx/contrib/cgltf-tangents/cgltf_tangents.h b/contrib/cgltf-tangents/cgltf_tangents.h index 79e3502..79e3502 100644 --- a/gfx/contrib/cgltf-tangents/cgltf_tangents.h +++ b/contrib/cgltf-tangents/cgltf_tangents.h | |||
diff --git a/gfx/contrib/cgltf-tangents/test/CMakeLists.txt b/contrib/cgltf-tangents/test/CMakeLists.txt index 422c950..422c950 100644 --- a/gfx/contrib/cgltf-tangents/test/CMakeLists.txt +++ b/contrib/cgltf-tangents/test/CMakeLists.txt | |||
diff --git a/gfx/contrib/cgltf-tangents/test/main.c b/contrib/cgltf-tangents/test/main.c index 0d70008..0d70008 100644 --- a/gfx/contrib/cgltf-tangents/test/main.c +++ b/contrib/cgltf-tangents/test/main.c | |||
diff --git a/gfx/contrib/cgltf/CMakeLists.txt b/contrib/cgltf/CMakeLists.txt index 0ac840a..0ac840a 100644 --- a/gfx/contrib/cgltf/CMakeLists.txt +++ b/contrib/cgltf/CMakeLists.txt | |||
diff --git a/gfx/contrib/cgltf/LICENSE b/contrib/cgltf/LICENSE index 0afe8c7..0afe8c7 100644 --- a/gfx/contrib/cgltf/LICENSE +++ b/contrib/cgltf/LICENSE | |||
diff --git a/gfx/contrib/cgltf/README.md b/contrib/cgltf/README.md index 3b49d52..3b49d52 100644 --- a/gfx/contrib/cgltf/README.md +++ b/contrib/cgltf/README.md | |||
diff --git a/gfx/contrib/cgltf/cgltf.h b/contrib/cgltf/cgltf.h index 077cf36..077cf36 100644 --- a/gfx/contrib/cgltf/cgltf.h +++ b/contrib/cgltf/cgltf.h | |||
diff --git a/gfx/contrib/cgltf/cgltf_write.h b/contrib/cgltf/cgltf_write.h index 2096a5b..2096a5b 100644 --- a/gfx/contrib/cgltf/cgltf_write.h +++ b/contrib/cgltf/cgltf_write.h | |||
diff --git a/gfx/contrib/stb/CMakeLists.txt b/contrib/stb/CMakeLists.txt index 8cee003..8cee003 100644 --- a/gfx/contrib/stb/CMakeLists.txt +++ b/contrib/stb/CMakeLists.txt | |||
diff --git a/gfx/contrib/stb/stb_image.h b/contrib/stb/stb_image.h index 97038e6..97038e6 100644 --- a/gfx/contrib/stb/stb_image.h +++ b/contrib/stb/stb_image.h | |||
diff --git a/gfx/doc/extern/2013SiggraphPresentationsNotes-26915738.pdf b/doc/extern/2013SiggraphPresentationsNotes-26915738.pdf index 989658e..989658e 100644 --- a/gfx/doc/extern/2013SiggraphPresentationsNotes-26915738.pdf +++ b/doc/extern/2013SiggraphPresentationsNotes-26915738.pdf | |||
| Binary files differ | |||
diff --git a/gfx/doc/extern/Scene Graph - CSE 167.pdf b/doc/extern/Scene Graph - CSE 167.pdf index 5fbbb10..5fbbb10 100644 --- a/gfx/doc/extern/Scene Graph - CSE 167.pdf +++ b/doc/extern/Scene Graph - CSE 167.pdf | |||
| Binary files differ | |||
diff --git a/gfx/doc/gfx.png b/doc/gfx.png index e64f6e1..e64f6e1 100644 --- a/gfx/doc/gfx.png +++ b/doc/gfx.png | |||
| Binary files differ | |||
diff --git a/gfx/doc/gfx.txt b/doc/gfx.txt index d3ce01b..d3ce01b 100644 --- a/gfx/doc/gfx.txt +++ b/doc/gfx.txt | |||
diff --git a/gfx/doc/gltfOverview-2.0.0b.png b/doc/gltfOverview-2.0.0b.png index 6a5bb61..6a5bb61 100644 --- a/gfx/doc/gltfOverview-2.0.0b.png +++ b/doc/gltfOverview-2.0.0b.png | |||
| Binary files differ | |||
diff --git a/gfx/doc/pipeline.png b/doc/pipeline.png index 426f39e..426f39e 100644 --- a/gfx/doc/pipeline.png +++ b/doc/pipeline.png | |||
| Binary files differ | |||
diff --git a/gfx/doc/pipeline.txt b/doc/pipeline.txt index 51523d6..51523d6 100644 --- a/gfx/doc/pipeline.txt +++ b/doc/pipeline.txt | |||
diff --git a/gfx/doc/renderer.png b/doc/renderer.png index d0516b0..d0516b0 100644 --- a/gfx/doc/renderer.png +++ b/doc/renderer.png | |||
| Binary files differ | |||
diff --git a/gfx/doc/renderer.txt b/doc/renderer.txt index 90b18f8..90b18f8 100644 --- a/gfx/doc/renderer.txt +++ b/doc/renderer.txt | |||
diff --git a/gfx/doc/scene.png b/doc/scene.png index 85d2447..85d2447 100644 --- a/gfx/doc/scene.png +++ b/doc/scene.png | |||
| Binary files differ | |||
diff --git a/gfx/doc/scene.txt b/doc/scene.txt index a771488..a771488 100644 --- a/gfx/doc/scene.txt +++ b/doc/scene.txt | |||
diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt deleted file mode 100644 index 3a88bb7..0000000 --- a/game/CMakeLists.txt +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | cmake_minimum_required(VERSION 3.0) | ||
| 2 | |||
| 3 | add_subdirectory(src/plugins) | ||
| 4 | |||
| 5 | project(game) | ||
| 6 | |||
| 7 | add_executable(game | ||
| 8 | src/game.c) | ||
| 9 | |||
| 10 | target_include_directories(game PRIVATE | ||
| 11 | src/) | ||
| 12 | |||
| 13 | target_link_libraries(game PRIVATE | ||
| 14 | cstring | ||
| 15 | error | ||
| 16 | gfx | ||
| 17 | gfx-app | ||
| 18 | list | ||
| 19 | log | ||
| 20 | math | ||
| 21 | mempool | ||
| 22 | plugin) | ||
diff --git a/game/src/game.c b/game/src/game.c deleted file mode 100644 index 51f5cbe..0000000 --- a/game/src/game.c +++ /dev/null | |||
| @@ -1,218 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Main game module with entry point and game loop. | ||
| 3 | * | ||
| 4 | * The game module sets up the window and GL context and defers the core game | ||
| 5 | * logic to a plugin. | ||
| 6 | */ | ||
| 7 | #define _GNU_SOURCE 200112L // For readlink() | ||
| 8 | |||
| 9 | #include "game.h" | ||
| 10 | |||
| 11 | #include "plugins/plugin.h" | ||
| 12 | |||
| 13 | #include <gfx/app.h> | ||
| 14 | #include <gfx/core.h> | ||
| 15 | #include <gfx/gfx.h> | ||
| 16 | #include <gfx/renderer.h> | ||
| 17 | |||
| 18 | #include <error.h> | ||
| 19 | #include <log/log.h> | ||
| 20 | #include <plugin.h> | ||
| 21 | |||
| 22 | #include <assert.h> | ||
| 23 | #include <stdbool.h> | ||
| 24 | #include <stdio.h> | ||
| 25 | #include <stdlib.h> | ||
| 26 | |||
| 27 | #include <linux/limits.h> | ||
| 28 | |||
| 29 | #include <unistd.h> | ||
| 30 | |||
| 31 | #undef _GNU_SOURCE | ||
| 32 | |||
| 33 | static const int WIDTH = 1350; | ||
| 34 | static const int HEIGHT = 900; | ||
| 35 | static const int MAX_FPS = 60; | ||
| 36 | |||
| 37 | typedef struct GfxAppState { | ||
| 38 | Game game; | ||
| 39 | } GfxAppState; | ||
| 40 | |||
| 41 | /// Initialize the game's plugin. | ||
| 42 | static bool init_plugin(Game* game) { | ||
| 43 | assert(game); | ||
| 44 | assert(game->plugin); | ||
| 45 | // Plugin state is allowed to be null, either when the plugin does not | ||
| 46 | // expose an init() or when init() does not initialize a state. | ||
| 47 | if (plugin_resolve(game->plugin, plugin_init, "init")) { | ||
| 48 | State* plugin_state = 0; | ||
| 49 | if (!plugin_call(game->plugin, plugin_init, "init", game, &plugin_state)) { | ||
| 50 | return false; | ||
| 51 | } | ||
| 52 | set_plugin_state(game->plugin, plugin_state); | ||
| 53 | } | ||
| 54 | return true; // Plugin does not need to expose an init(). | ||
| 55 | } | ||
| 56 | |||
| 57 | /// Shutdown the game's plugin. | ||
| 58 | /// The game's plugin is allowed to be null in the call to this function. | ||
| 59 | static void shutdown_plugin(Game* game) { | ||
| 60 | assert(game); | ||
| 61 | if (game->plugin && | ||
| 62 | (plugin_resolve(game->plugin, plugin_shutdown, "shutdown"))) { | ||
| 63 | void* plugin_state = get_plugin_state(game->plugin); | ||
| 64 | plugin_call(game->plugin, plugin_shutdown, "shutdown", game, plugin_state); | ||
| 65 | set_plugin_state(game->plugin, 0); | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | /// Boot the game's plugin. | ||
| 70 | static bool boot_plugin(Game* game) { | ||
| 71 | assert(game); | ||
| 72 | assert(game->plugin); | ||
| 73 | if (plugin_resolve(game->plugin, plugin_boot, "boot")) { | ||
| 74 | void* plugin_state = get_plugin_state(game->plugin); | ||
| 75 | return plugin_call(game->plugin, plugin_boot, "boot", game, plugin_state); | ||
| 76 | } | ||
| 77 | return true; // Plugin does not need to expose a boot(). | ||
| 78 | } | ||
| 79 | |||
| 80 | /// Update the plugin's state. | ||
| 81 | static void update_plugin(Game* game, double t, double dt) { | ||
| 82 | assert(game); | ||
| 83 | assert(game->plugin); | ||
| 84 | if (plugin_resolve(game->plugin, plugin_update, "update")) { | ||
| 85 | void* plugin_state = get_plugin_state(game->plugin); | ||
| 86 | plugin_call( | ||
| 87 | game->plugin, plugin_update, "update", game, plugin_state, t, dt); | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | /// Plugin render. | ||
| 92 | static void render_plugin(const Game* game) { | ||
| 93 | assert(game); | ||
| 94 | assert(game->plugin); | ||
| 95 | if (plugin_resolve(game->plugin, plugin_render, "render")) { | ||
| 96 | void* plugin_state = get_plugin_state(game->plugin); | ||
| 97 | plugin_call(game->plugin, plugin_render, "render", game, plugin_state); | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 101 | /// Plugin resize. | ||
| 102 | static void resize_plugin(Game* game, int width, int height) { | ||
| 103 | assert(game); | ||
| 104 | assert(game->plugin); | ||
| 105 | if (plugin_resolve(game->plugin, plugin_resize, "resize")) { | ||
| 106 | void* plugin_state = get_plugin_state(game->plugin); | ||
| 107 | plugin_call( | ||
| 108 | game->plugin, plugin_resize, "resize", game, plugin_state, width, | ||
| 109 | height); | ||
| 110 | } | ||
| 111 | } | ||
| 112 | |||
| 113 | static void Shutdown(Game* game); | ||
| 114 | |||
| 115 | static bool Init(Game* game, int argc, const char** argv) { | ||
| 116 | assert(game); | ||
| 117 | |||
| 118 | if (argc <= 1) { | ||
| 119 | LOGE("Usage: %s <plugin> [plugin args]", argv[0]); | ||
| 120 | return false; | ||
| 121 | } | ||
| 122 | |||
| 123 | // Syntax: game <plugin> [plugin args] | ||
| 124 | // | ||
| 125 | // Here we consume the <plugin> arg so that plugins receive the remainder | ||
| 126 | // args starting from 0. | ||
| 127 | game->argc = argc - 1; | ||
| 128 | game->argv = argv + 1; | ||
| 129 | |||
| 130 | char exe_path_buf[NAME_MAX] = {0}; | ||
| 131 | if (readlink("/proc/self/exe", exe_path_buf, sizeof(exe_path_buf)) == -1) { | ||
| 132 | LOGE("readlink(/proc/self/exe) failed"); | ||
| 133 | goto cleanup; | ||
| 134 | } | ||
| 135 | |||
| 136 | // Replace the last / with a null terminator to remove the exe file from the | ||
| 137 | // path. This gets the file's parent directory. | ||
| 138 | *strrchr(exe_path_buf, '/') = 0; | ||
| 139 | |||
| 140 | const mstring exe_dir = mstring_make(exe_path_buf); | ||
| 141 | const mstring plugins_path = mstring_concat_cstr(exe_dir, "/src/plugins"); | ||
| 142 | |||
| 143 | if (!(game->plugin_engine = new_plugin_engine( | ||
| 144 | &(PluginEngineDesc){.plugins_dir = mstring_cstr(&plugins_path)}))) { | ||
| 145 | goto cleanup; | ||
| 146 | } | ||
| 147 | |||
| 148 | const char* plugin = argv[1]; | ||
| 149 | if (!(game->plugin = load_plugin(game->plugin_engine, plugin))) { | ||
| 150 | goto cleanup; | ||
| 151 | } | ||
| 152 | |||
| 153 | if (!(game->gfx = gfx_init())) { | ||
| 154 | goto cleanup; | ||
| 155 | } | ||
| 156 | |||
| 157 | if (!init_plugin(game)) { | ||
| 158 | goto cleanup; | ||
| 159 | } | ||
| 160 | if (!boot_plugin(game)) { | ||
| 161 | goto cleanup; | ||
| 162 | } | ||
| 163 | |||
| 164 | return true; | ||
| 165 | |||
| 166 | cleanup: | ||
| 167 | LOGE("Gfx error: %s", get_error()); | ||
| 168 | Shutdown(game); | ||
| 169 | return false; | ||
| 170 | } | ||
| 171 | |||
| 172 | static void Shutdown(Game* game) { | ||
| 173 | assert(game); | ||
| 174 | shutdown_plugin(game); | ||
| 175 | if (game->gfx) { | ||
| 176 | gfx_destroy(&game->gfx); | ||
| 177 | } | ||
| 178 | if (game->plugin) { | ||
| 179 | delete_plugin(&game->plugin); | ||
| 180 | } | ||
| 181 | if (game->plugin_engine) { | ||
| 182 | delete_plugin_engine(&game->plugin_engine); | ||
| 183 | } | ||
| 184 | } | ||
| 185 | |||
| 186 | static void Update(Game* game, double t, double dt) { | ||
| 187 | plugin_engine_update(game->plugin_engine); | ||
| 188 | if (plugin_reloaded(game->plugin)) { | ||
| 189 | shutdown_plugin(game); | ||
| 190 | const bool result = init_plugin(game); | ||
| 191 | assert(result); // TODO: handle error better. | ||
| 192 | |||
| 193 | // Trigger a resize just like the initial resize that occurs when the gfx | ||
| 194 | // application starts. | ||
| 195 | resize_plugin(game, game->width, game->height); | ||
| 196 | } | ||
| 197 | |||
| 198 | update_plugin(game, t, dt); | ||
| 199 | } | ||
| 200 | |||
| 201 | static void Render(const Game* game) { | ||
| 202 | GfxCore* gfxcore = gfx_get_core(game->gfx); | ||
| 203 | gfx_start_frame(gfxcore); | ||
| 204 | render_plugin(game); | ||
| 205 | gfx_end_frame(gfxcore); | ||
| 206 | } | ||
| 207 | |||
| 208 | static void Resize(Game* game, int width, int height) { | ||
| 209 | game->width = width; | ||
| 210 | game->height = height; | ||
| 211 | |||
| 212 | GfxCore* gfxcore = gfx_get_core(game->gfx); | ||
| 213 | gfx_set_viewport(gfxcore, 0, 0, width, height); | ||
| 214 | |||
| 215 | resize_plugin(game, width, height); | ||
| 216 | } | ||
| 217 | |||
| 218 | GFX_APP_MAIN(WIDTH, HEIGHT, MAX_FPS, "Game"); | ||
diff --git a/game/src/game.h b/game/src/game.h deleted file mode 100644 index 579ba3c..0000000 --- a/game/src/game.h +++ /dev/null | |||
| @@ -1,21 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Header file defining the game state, included by plugins. | ||
| 3 | */ | ||
| 4 | #pragma once | ||
| 5 | |||
| 6 | typedef struct PluginEngine PluginEngine; | ||
| 7 | typedef struct Plugin Plugin; | ||
| 8 | typedef struct Gfx Gfx; | ||
| 9 | typedef struct Scene Scene; | ||
| 10 | typedef struct SceneCamera SceneCamera; | ||
| 11 | |||
| 12 | /// Game state. | ||
| 13 | typedef struct { | ||
| 14 | int argc; | ||
| 15 | const char** argv; | ||
| 16 | PluginEngine* plugin_engine; | ||
| 17 | Plugin* plugin; | ||
| 18 | Gfx* gfx; | ||
| 19 | int width; | ||
| 20 | int height; | ||
| 21 | } Game; | ||
diff --git a/game/src/plugins/CMakeLists.txt b/game/src/plugins/CMakeLists.txt deleted file mode 100644 index 8661598..0000000 --- a/game/src/plugins/CMakeLists.txt +++ /dev/null | |||
| @@ -1,29 +0,0 @@ | |||
| 1 | cmake_minimum_required(VERSION 3.0) | ||
| 2 | |||
| 3 | project(plugins) | ||
| 4 | |||
| 5 | set(LINK_LIBRARIES cstring math gfx gfx-app) | ||
| 6 | |||
| 7 | # Viewer | ||
| 8 | |||
| 9 | add_library(viewer SHARED | ||
| 10 | viewer.c) | ||
| 11 | |||
| 12 | target_link_libraries(viewer PUBLIC | ||
| 13 | ${LINK_LIBRARIES}) | ||
| 14 | |||
| 15 | # Texture viewer | ||
| 16 | |||
| 17 | add_library(texture_view SHARED | ||
| 18 | texture_view.c) | ||
| 19 | |||
| 20 | target_link_libraries(texture_view PUBLIC | ||
| 21 | ${LINK_LIBRARIES}) | ||
| 22 | |||
| 23 | # Pong | ||
| 24 | |||
| 25 | add_library(pong SHARED | ||
| 26 | pong.c) | ||
| 27 | |||
| 28 | target_link_libraries(pong PUBLIC | ||
| 29 | ${LINK_LIBRARIES}) | ||
diff --git a/game/src/plugins/plugin.h b/game/src/plugins/plugin.h deleted file mode 100644 index f7219c6..0000000 --- a/game/src/plugins/plugin.h +++ /dev/null | |||
| @@ -1,52 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Game plugin. | ||
| 3 | */ | ||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "../game.h" | ||
| 7 | |||
| 8 | #include <gfx/gfx.h> | ||
| 9 | #include <gfx/scene.h> | ||
| 10 | |||
| 11 | #include <stdbool.h> | ||
| 12 | |||
| 13 | typedef struct State State; | ||
| 14 | |||
| 15 | /// Initialize the plugin, which may optionally return a state object. | ||
| 16 | /// | ||
| 17 | /// This function is called every time the plugin is (re)loaded. | ||
| 18 | /// | ||
| 19 | /// It is assumed that the plugin's state is fully encapsulated in the returned | ||
| 20 | /// state object. The plugin should not store any (mutable) state outside of the | ||
| 21 | /// returned state object (e.g., no mutable global variables.) | ||
| 22 | bool init(Game*, State**); | ||
| 23 | |||
| 24 | /// Shut down the plugin. | ||
| 25 | /// | ||
| 26 | /// This function is called before the plugin is unloaded. | ||
| 27 | /// | ||
| 28 | /// The plugin should perform any destruction needed, but not free the state | ||
| 29 | /// object; freeing the state object's memory is handled by the caller. | ||
| 30 | void shutdown(Game*, State*); | ||
| 31 | |||
| 32 | /// Function called the first time the plugin is loaded throughout the | ||
| 33 | /// application's lifetime. This allows the plugin to do one-time initialization | ||
| 34 | /// of the game state. | ||
| 35 | bool boot(Game*, State*); | ||
| 36 | |||
| 37 | /// Update the plugin's and the game's state. | ||
| 38 | void update(Game*, State*, double t, double dt); | ||
| 39 | |||
| 40 | /// Render hook. | ||
| 41 | void render(const Game*, const State*); | ||
| 42 | |||
| 43 | /// Called when the game's window is resized. | ||
| 44 | void resize(Game*, State*, int width, int height); | ||
| 45 | |||
| 46 | // Signatures for the plugin's exposed functions. | ||
| 47 | typedef bool (*plugin_init)(Game*, State**); | ||
| 48 | typedef bool (*plugin_shutdown)(Game*, State*); | ||
| 49 | typedef bool (*plugin_boot)(Game*, State*); | ||
| 50 | typedef void (*plugin_update)(Game*, State*, double t, double dt); | ||
| 51 | typedef void (*plugin_render)(const Game*, const State*); | ||
| 52 | typedef void (*plugin_resize)(Game* game, State* state, int width, int height); | ||
diff --git a/game/src/plugins/pong.c b/game/src/plugins/pong.c deleted file mode 100644 index c1c55be..0000000 --- a/game/src/plugins/pong.c +++ /dev/null | |||
| @@ -1,237 +0,0 @@ | |||
| 1 | #include "plugin.h" | ||
| 2 | |||
| 3 | #include <gfx/app.h> | ||
| 4 | #include <gfx/gfx.h> | ||
| 5 | #include <gfx/renderer.h> | ||
| 6 | |||
| 7 | #include <math/mat4.h> | ||
| 8 | #include <math/vec2.h> | ||
| 9 | #include <math/vec4.h> | ||
| 10 | |||
| 11 | #include <stdlib.h> | ||
| 12 | |||
| 13 | static const vec2 PAD_SIZE = (vec2){120, 20}; | ||
| 14 | static const R PLAYER_Y_OFFSET = 50; | ||
| 15 | static const R PLAYER_SPEED = 800; | ||
| 16 | |||
| 17 | static const R ENEMY_SPEED = 2; | ||
| 18 | |||
| 19 | static const R BALL_SIZE = 18; | ||
| 20 | static const R BALL_SPEED = 360; // In each dimension. | ||
| 21 | |||
| 22 | static const R EPS = (R)1e-3; | ||
| 23 | |||
| 24 | typedef struct Player { | ||
| 25 | vec2 position; | ||
| 26 | } Player; | ||
| 27 | |||
| 28 | typedef struct Ball { | ||
| 29 | vec2 position; | ||
| 30 | vec2 velocity; | ||
| 31 | } Ball; | ||
| 32 | |||
| 33 | typedef struct State { | ||
| 34 | bool game_started; | ||
| 35 | Player human; | ||
| 36 | Player enemy; | ||
| 37 | Ball ball; | ||
| 38 | mat4 viewProjection; | ||
| 39 | } State; | ||
| 40 | |||
| 41 | bool init(Game* game, State** pp_state) { | ||
| 42 | assert(game); | ||
| 43 | |||
| 44 | State* state = calloc(1, sizeof(State)); | ||
| 45 | if (!state) { | ||
| 46 | return false; | ||
| 47 | } | ||
| 48 | |||
| 49 | *pp_state = state; | ||
| 50 | return true; | ||
| 51 | |||
| 52 | cleanup: | ||
| 53 | free(state); | ||
| 54 | return false; | ||
| 55 | } | ||
| 56 | |||
| 57 | void shutdown(Game* game, State* state) { | ||
| 58 | assert(game); | ||
| 59 | assert(state); | ||
| 60 | } | ||
| 61 | |||
| 62 | static void move_ball(Ball* ball, R dt, int width, int height) { | ||
| 63 | assert(ball); | ||
| 64 | |||
| 65 | const R offset = BALL_SIZE / 2; | ||
| 66 | |||
| 67 | ball->position = vec2_add(ball->position, vec2_scale(ball->velocity, dt)); | ||
| 68 | |||
| 69 | // Right wall. | ||
| 70 | if (ball->position.x + offset > (R)width) { | ||
| 71 | ball->position.x = (R)width - offset - EPS; | ||
| 72 | ball->velocity.x = -ball->velocity.x; | ||
| 73 | } | ||
| 74 | // Left wall. | ||
| 75 | else if (ball->position.x - offset < 0) { | ||
| 76 | ball->position.x = offset + EPS; | ||
| 77 | ball->velocity.x = -ball->velocity.x; | ||
| 78 | } | ||
| 79 | // Top wall. | ||
| 80 | if (ball->position.y + offset > (R)height) { | ||
| 81 | ball->position.y = (R)height - offset - EPS; | ||
| 82 | ball->velocity.y = -ball->velocity.y; | ||
| 83 | } | ||
| 84 | // Bottom wall. | ||
| 85 | else if (ball->position.y - offset < 0) { | ||
| 86 | ball->position.y = offset + EPS; | ||
| 87 | ball->velocity.y = -ball->velocity.y; | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | void move_enemy_player(int width, Player* player, R t) { | ||
| 92 | const R half_width = (R)width / 2; | ||
| 93 | const R amplitude = half_width - (PAD_SIZE.x / 2); | ||
| 94 | player->position.x = half_width + amplitude * sinf(t * ENEMY_SPEED); | ||
| 95 | } | ||
| 96 | |||
| 97 | void move_human_player(Player* player, R dt) { | ||
| 98 | assert(player); | ||
| 99 | |||
| 100 | R speed = 0; | ||
| 101 | if (gfx_app_is_key_pressed('a')) { | ||
| 102 | speed -= PLAYER_SPEED; | ||
| 103 | } | ||
| 104 | if (gfx_app_is_key_pressed('d')) { | ||
| 105 | speed += PLAYER_SPEED; | ||
| 106 | } | ||
| 107 | |||
| 108 | player->position.x += speed * dt; | ||
| 109 | } | ||
| 110 | |||
| 111 | void clamp_player(Player* player, int width) { | ||
| 112 | assert(player); | ||
| 113 | |||
| 114 | const R offset = PAD_SIZE.x / 2; | ||
| 115 | |||
| 116 | // Left wall. | ||
| 117 | if (player->position.x + offset > (R)width) { | ||
| 118 | player->position.x = (R)width - offset; | ||
| 119 | } | ||
| 120 | // Right wall. | ||
| 121 | else if (player->position.x - offset < 0) { | ||
| 122 | player->position.x = offset; | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | void collide_ball(vec2 old_ball_position, const Player* player, Ball* ball) { | ||
| 127 | assert(player); | ||
| 128 | assert(ball); | ||
| 129 | |||
| 130 | // Discrete but simple collision. Checks for intersection and moves the ball | ||
| 131 | // back by a small epsilon. | ||
| 132 | |||
| 133 | // Player bounding box. | ||
| 134 | const vec2 player_pmin = vec2_make( | ||
| 135 | player->position.x - PAD_SIZE.x / 2, player->position.y - PAD_SIZE.y / 2); | ||
| 136 | const vec2 player_pmax = vec2_make( | ||
| 137 | player->position.x + PAD_SIZE.x / 2, player->position.y + PAD_SIZE.y / 2); | ||
| 138 | |||
| 139 | // Ball bounding box. | ||
| 140 | const vec2 ball_pmin = vec2_make( | ||
| 141 | ball->position.x - BALL_SIZE / 2, ball->position.y - BALL_SIZE / 2); | ||
| 142 | const vec2 ball_pmax = vec2_make( | ||
| 143 | ball->position.x + BALL_SIZE / 2, ball->position.y + BALL_SIZE / 2); | ||
| 144 | |||
| 145 | // Check for intersection and update ball. | ||
| 146 | if (!((ball_pmax.x < player_pmin.x) || (ball_pmin.x > player_pmax.x) || | ||
| 147 | (ball_pmax.y < player_pmin.y) || (ball_pmin.y > player_pmax.y))) { | ||
| 148 | ball->position = | ||
| 149 | vec2_add(old_ball_position, vec2_scale(ball->velocity, -EPS)); | ||
| 150 | ball->velocity.y = -ball->velocity.y; | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | void update(Game* game, State* state, double t, double dt) { | ||
| 155 | assert(game); | ||
| 156 | assert(state); | ||
| 157 | |||
| 158 | // TODO: Move game width/height to GfxApp query functions? | ||
| 159 | const vec2 old_ball_position = state->ball.position; | ||
| 160 | move_ball(&state->ball, (R)dt, game->width, game->height); | ||
| 161 | move_human_player(&state->human, (R)dt); | ||
| 162 | move_enemy_player(game->width, &state->enemy, (R)t); | ||
| 163 | clamp_player(&state->human, game->width); | ||
| 164 | collide_ball(old_ball_position, &state->human, &state->ball); | ||
| 165 | collide_ball(old_ball_position, &state->enemy, &state->ball); | ||
| 166 | } | ||
| 167 | |||
| 168 | static void draw_player(ImmRenderer* imm, const Player* player) { | ||
| 169 | assert(imm); | ||
| 170 | assert(player); | ||
| 171 | |||
| 172 | const vec2 half_box = vec2_div(PAD_SIZE, vec2_make(2, 2)); | ||
| 173 | |||
| 174 | const vec2 pmin = vec2_sub(player->position, half_box); | ||
| 175 | const vec2 pmax = vec2_add(player->position, half_box); | ||
| 176 | const aabb2 box = aabb2_make(pmin, pmax); | ||
| 177 | |||
| 178 | gfx_imm_draw_aabb2(imm, box); | ||
| 179 | } | ||
| 180 | |||
| 181 | static void draw_ball(ImmRenderer* imm, const Ball* ball) { | ||
| 182 | assert(imm); | ||
| 183 | assert(ball); | ||
| 184 | |||
| 185 | const vec2 half_box = vec2_make(BALL_SIZE / 2, BALL_SIZE / 2); | ||
| 186 | const vec2 pmin = vec2_sub(ball->position, half_box); | ||
| 187 | const vec2 pmax = vec2_add(ball->position, half_box); | ||
| 188 | const aabb2 box = aabb2_make(pmin, pmax); | ||
| 189 | |||
| 190 | gfx_imm_draw_aabb2(imm, box); | ||
| 191 | } | ||
| 192 | |||
| 193 | void render(const Game* game, const State* state) { | ||
| 194 | assert(game); | ||
| 195 | assert(state); | ||
| 196 | |||
| 197 | ImmRenderer* imm = gfx_get_imm_renderer(game->gfx); | ||
| 198 | gfx_imm_start(imm); | ||
| 199 | gfx_imm_set_view_projection_matrix(imm, &state->viewProjection); | ||
| 200 | gfx_imm_load_identity(imm); | ||
| 201 | gfx_imm_set_colour(imm, vec4_make(1, 1, 1, 1)); | ||
| 202 | draw_player(imm, &state->human); | ||
| 203 | draw_player(imm, &state->enemy); | ||
| 204 | draw_ball(imm, &state->ball); | ||
| 205 | gfx_imm_end(imm); | ||
| 206 | } | ||
| 207 | |||
| 208 | static R clamp_to_width(int width, R x, R extent) { | ||
| 209 | return min(x, (R)width - extent); | ||
| 210 | } | ||
| 211 | |||
| 212 | void resize(Game* game, State* state, int width, int height) { | ||
| 213 | assert(game); | ||
| 214 | assert(state); | ||
| 215 | |||
| 216 | state->viewProjection = mat4_ortho(0, (R)width, 0, (R)height, -1, 1); | ||
| 217 | |||
| 218 | state->human.position.y = PLAYER_Y_OFFSET; | ||
| 219 | state->enemy.position.y = (R)height - PLAYER_Y_OFFSET; | ||
| 220 | |||
| 221 | if (!state->game_started) { | ||
| 222 | state->human.position.x = (R)width / 2; | ||
| 223 | state->enemy.position.x = (R)width / 2; | ||
| 224 | |||
| 225 | state->ball.position = | ||
| 226 | vec2_div(vec2_make((R)width, (R)height), vec2_make(2, 2)); | ||
| 227 | |||
| 228 | state->ball.velocity = vec2_make(BALL_SPEED, BALL_SPEED); | ||
| 229 | |||
| 230 | state->game_started = true; | ||
| 231 | } else { | ||
| 232 | state->human.position.x = | ||
| 233 | clamp_to_width(width, state->human.position.x, PAD_SIZE.x / 2); | ||
| 234 | state->enemy.position.x = | ||
| 235 | clamp_to_width(width, state->enemy.position.x, PAD_SIZE.x / 2); | ||
| 236 | } | ||
| 237 | } | ||
diff --git a/game/src/plugins/texture_view.c b/game/src/plugins/texture_view.c deleted file mode 100644 index a8b2a94..0000000 --- a/game/src/plugins/texture_view.c +++ /dev/null | |||
| @@ -1,144 +0,0 @@ | |||
| 1 | #include "plugin.h" | ||
| 2 | |||
| 3 | #include <gfx/asset.h> | ||
| 4 | #include <gfx/core.h> | ||
| 5 | #include <gfx/renderer.h> | ||
| 6 | #include <gfx/scene.h> | ||
| 7 | #include <gfx/util/geometry.h> | ||
| 8 | #include <gfx/util/shader.h> | ||
| 9 | |||
| 10 | #include <math/camera.h> | ||
| 11 | |||
| 12 | #include <assert.h> | ||
| 13 | #include <stdlib.h> | ||
| 14 | |||
| 15 | // Default texture to load if no texture is provided. | ||
| 16 | static const char* DEFAULT_TEXTURE = "/assets/skybox/clouds1/clouds1_west.bmp"; | ||
| 17 | // static const char* DEFAULT_TEXTURE = "/assets/checkerboard.jpg"; | ||
| 18 | |||
| 19 | struct State { | ||
| 20 | Scene* scene; | ||
| 21 | SceneCamera* camera; | ||
| 22 | }; | ||
| 23 | |||
| 24 | bool init(Game* game, State** pp_state) { | ||
| 25 | assert(game); | ||
| 26 | assert(pp_state); | ||
| 27 | |||
| 28 | State* state = calloc(1, sizeof(State)); | ||
| 29 | if (!state) { | ||
| 30 | goto cleanup; | ||
| 31 | } | ||
| 32 | |||
| 33 | // Usage: [texture file] | ||
| 34 | const char* texture_file = game->argc > 1 ? game->argv[1] : DEFAULT_TEXTURE; | ||
| 35 | |||
| 36 | GfxCore* gfxcore = gfx_get_core(game->gfx); | ||
| 37 | |||
| 38 | const Texture* texture = gfx_load_texture( | ||
| 39 | game->gfx, &(LoadTextureCmd){ | ||
| 40 | .origin = AssetFromFile, | ||
| 41 | .type = LoadTexture, | ||
| 42 | .filtering = LinearFiltering, | ||
| 43 | .mipmaps = false, | ||
| 44 | .data.texture.filepath = mstring_make(texture_file)}); | ||
| 45 | if (!texture) { | ||
| 46 | goto cleanup; | ||
| 47 | } | ||
| 48 | |||
| 49 | ShaderProgram* shader = gfx_make_view_texture_shader(gfxcore); | ||
| 50 | if (!shader) { | ||
| 51 | goto cleanup; | ||
| 52 | } | ||
| 53 | |||
| 54 | Geometry* geometry = gfx_make_quad_11(gfxcore); | ||
| 55 | if (!geometry) { | ||
| 56 | goto cleanup; | ||
| 57 | } | ||
| 58 | |||
| 59 | MaterialDesc material_desc = (MaterialDesc){.num_uniforms = 1}; | ||
| 60 | material_desc.uniforms[0] = (ShaderUniform){ | ||
| 61 | .type = UniformTexture, | ||
| 62 | .value.texture = texture, | ||
| 63 | .name = sstring_make("Texture")}; | ||
| 64 | Material* material = gfx_make_material(&material_desc); | ||
| 65 | if (!material) { | ||
| 66 | goto cleanup; | ||
| 67 | } | ||
| 68 | |||
| 69 | const MeshDesc mesh_desc = | ||
| 70 | (MeshDesc){.geometry = geometry, .material = material, .shader = shader}; | ||
| 71 | Mesh* mesh = gfx_make_mesh(&mesh_desc); | ||
| 72 | if (!mesh) { | ||
| 73 | goto cleanup; | ||
| 74 | } | ||
| 75 | |||
| 76 | SceneObject* object = | ||
| 77 | gfx_make_object(&(ObjectDesc){.num_meshes = 1, .meshes = {mesh}}); | ||
| 78 | if (!object) { | ||
| 79 | goto cleanup; | ||
| 80 | } | ||
| 81 | |||
| 82 | if (!(state->scene = gfx_make_scene())) { | ||
| 83 | goto cleanup; | ||
| 84 | } | ||
| 85 | |||
| 86 | SceneNode* node = gfx_make_object_node(object); | ||
| 87 | if (!node) { | ||
| 88 | goto cleanup; | ||
| 89 | } | ||
| 90 | SceneNode* root = gfx_get_scene_root(state->scene); | ||
| 91 | if (!root) { | ||
| 92 | goto cleanup; | ||
| 93 | } | ||
| 94 | gfx_set_node_parent(node, root); | ||
| 95 | |||
| 96 | if (!(state->camera = gfx_make_camera())) { | ||
| 97 | goto cleanup; | ||
| 98 | } | ||
| 99 | |||
| 100 | *pp_state = state; | ||
| 101 | return true; | ||
| 102 | |||
| 103 | cleanup: | ||
| 104 | shutdown(game, state); | ||
| 105 | if (state) { | ||
| 106 | free(state); | ||
| 107 | } | ||
| 108 | return false; | ||
| 109 | } | ||
| 110 | |||
| 111 | void shutdown(Game* game, State* state) { | ||
| 112 | assert(game); | ||
| 113 | if (state) { | ||
| 114 | gfx_destroy_camera(&state->camera); | ||
| 115 | gfx_destroy_scene(&state->scene); | ||
| 116 | // State freed by plugin engine. | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | void render(const Game* game, const State* state) { | ||
| 121 | assert(game); | ||
| 122 | assert(state); | ||
| 123 | |||
| 124 | Renderer* renderer = gfx_get_renderer(game->gfx); | ||
| 125 | gfx_render_scene( | ||
| 126 | renderer, &(RenderSceneParams){ | ||
| 127 | .mode = RenderDefault, | ||
| 128 | .scene = state->scene, | ||
| 129 | .camera = state->camera}); | ||
| 130 | } | ||
| 131 | |||
| 132 | void resize(Game* game, State* state, int width, int height) { | ||
| 133 | assert(game); | ||
| 134 | assert(state); | ||
| 135 | |||
| 136 | const R fovy = 90 * TO_RAD; | ||
| 137 | const R aspect = (R)width / (R)height; | ||
| 138 | const R near = 0.1; | ||
| 139 | const R far = 1000; | ||
| 140 | const mat4 projection = mat4_perspective(fovy, aspect, near, far); | ||
| 141 | |||
| 142 | Camera* camera = gfx_get_camera_camera(state->camera); | ||
| 143 | camera->projection = projection; | ||
| 144 | } | ||
diff --git a/game/src/plugins/viewer.c b/game/src/plugins/viewer.c deleted file mode 100644 index 23b9ffb..0000000 --- a/game/src/plugins/viewer.c +++ /dev/null | |||
| @@ -1,374 +0,0 @@ | |||
| 1 | #include "plugin.h" | ||
| 2 | |||
| 3 | #include <gfx/app.h> | ||
| 4 | #include <gfx/asset.h> | ||
| 5 | #include <gfx/renderer.h> | ||
| 6 | #include <gfx/scene.h> | ||
| 7 | #include <gfx/util/skyquad.h> | ||
| 8 | #include <math/camera.h> | ||
| 9 | #include <math/spatial3.h> | ||
| 10 | |||
| 11 | #include <log/log.h> | ||
| 12 | |||
| 13 | #include <stdlib.h> | ||
| 14 | |||
| 15 | // Skybox. | ||
| 16 | static const char* skybox[6] = { | ||
| 17 | "/home/jeanne/Nextcloud/assets/textures/skybox/clouds1/clouds1_east.bmp", | ||
| 18 | "/home/jeanne/Nextcloud/assets/textures/skybox/clouds1/clouds1_west.bmp", | ||
| 19 | "/home/jeanne/Nextcloud/assets/textures/skybox/clouds1/clouds1_up.bmp", | ||
| 20 | "/home/jeanne/Nextcloud/assets/textures/skybox/clouds1/clouds1_down.bmp", | ||
| 21 | "/home/jeanne/Nextcloud/assets/textures/skybox/clouds1/clouds1_south.bmp", | ||
| 22 | "/home/jeanne/Nextcloud/assets/textures/skybox/clouds1/clouds1_north.bmp", | ||
| 23 | }; | ||
| 24 | |||
| 25 | // Paths to various scene files. | ||
| 26 | static const char* BOX = "/home/jeanne/Nextcloud/assets/models/box.gltf"; | ||
| 27 | static const char* SUZANNE = | ||
| 28 | "/home/jeanne/Nextcloud/assets/models/suzanne.gltf"; | ||
| 29 | static const char* SPONZA = "/home/jeanne/Nextcloud/assets/glTF-Sample-Models/" | ||
| 30 | "2.0/Sponza/glTF/Sponza.gltf"; | ||
| 31 | static const char* FLIGHT_HELMET = | ||
| 32 | "/home/jeanne/Nextcloud/assets/glTF-Sample-Models/2.0/FlightHelmet/glTF/" | ||
| 33 | "FlightHelmet.gltf"; | ||
| 34 | static const char* DAMAGED_HELMET = | ||
| 35 | "/home/jeanne/Nextcloud/assets/glTF-Sample-Models/2.0/DamagedHelmet/glTF/" | ||
| 36 | "DamagedHelmet.gltf"; | ||
| 37 | static const char* GIRL = | ||
| 38 | "/home/jeanne/Nextcloud/assets/models/girl/girl-with-ground.gltf"; | ||
| 39 | static const char* BOXES = | ||
| 40 | "/home/jeanne/Nextcloud/assets/models/boxes/boxes.gltf"; | ||
| 41 | |||
| 42 | #define DEFAULT_SCENE_FILE GIRL | ||
| 43 | |||
| 44 | static const bool RenderBoundingBoxes = false; | ||
| 45 | static const R DefaultCameraSpeed = (R)6.0; | ||
| 46 | static const R DefaultMouseSensitivity = (R)(10 * TO_RAD); | ||
| 47 | static const vec3 DefaultCameraPosition = (vec3){0, 2, 5}; | ||
| 48 | |||
| 49 | typedef struct CameraCommand { | ||
| 50 | bool CameraMoveLeft : 1; | ||
| 51 | bool CameraMoveRight : 1; | ||
| 52 | bool CameraMoveForward : 1; | ||
| 53 | bool CameraMoveBackward : 1; | ||
| 54 | } CameraCommand; | ||
| 55 | |||
| 56 | typedef struct CameraController { | ||
| 57 | R camera_speed; // Camera movement speed. | ||
| 58 | R mouse_sensitivity; // Controls the degree with which mouse movements | ||
| 59 | // rotate the camera. | ||
| 60 | vec2 prev_mouse_position; // Mouse position in the previous frame. | ||
| 61 | bool rotating; // When true, subsequent mouse movements cause the | ||
| 62 | // camera to rotate. | ||
| 63 | } CameraController; | ||
| 64 | |||
| 65 | typedef struct State { | ||
| 66 | Scene* scene; | ||
| 67 | Model* model; | ||
| 68 | SceneCamera* camera; | ||
| 69 | CameraController camera_controller; | ||
| 70 | } State; | ||
| 71 | |||
| 72 | /// Load the skyquad texture. | ||
| 73 | static const Texture* load_environment_map(Gfx* gfx) { | ||
| 74 | assert(gfx); | ||
| 75 | return gfx_load_texture( | ||
| 76 | gfx, &(LoadTextureCmd){ | ||
| 77 | .origin = AssetFromFile, | ||
| 78 | .type = LoadCubemap, | ||
| 79 | .colour_space = sRGB, | ||
| 80 | .filtering = NearestFiltering, | ||
| 81 | .mipmaps = false, | ||
| 82 | .data.cubemap.filepaths = { | ||
| 83 | mstring_make(skybox[0]), mstring_make(skybox[1]), | ||
| 84 | mstring_make(skybox[2]), mstring_make(skybox[3]), | ||
| 85 | mstring_make(skybox[4]), mstring_make(skybox[5])} | ||
| 86 | }); | ||
| 87 | } | ||
| 88 | |||
| 89 | /// Load the skyquad and return the environment light node. | ||
| 90 | static SceneNode* load_skyquad(Gfx* gfx, SceneNode* root) { | ||
| 91 | assert(gfx); | ||
| 92 | assert(root); | ||
| 93 | |||
| 94 | GfxCore* gfxcore = gfx_get_core(gfx); | ||
| 95 | |||
| 96 | const Texture* environment_map = load_environment_map(gfx); | ||
| 97 | if (!environment_map) { | ||
| 98 | return 0; | ||
| 99 | } | ||
| 100 | |||
| 101 | return gfx_setup_skyquad(gfxcore, root, environment_map); | ||
| 102 | } | ||
| 103 | |||
| 104 | /// Load the 3D scene. | ||
| 105 | /// Return the loaded model. | ||
| 106 | static Model* load_scene(Game* game, State* state, const char* scene_filepath) { | ||
| 107 | assert(game); | ||
| 108 | assert(game->gfx); | ||
| 109 | assert(state); | ||
| 110 | assert(state->scene); | ||
| 111 | |||
| 112 | Camera* camera = gfx_get_camera_camera(state->camera); | ||
| 113 | spatial3_set_position(&camera->spatial, vec3_make(0, 0, 2)); | ||
| 114 | |||
| 115 | SceneNode* root = gfx_get_scene_root(state->scene); | ||
| 116 | SceneNode* sky_light_node = load_skyquad(game->gfx, root); | ||
| 117 | if (!sky_light_node) { | ||
| 118 | return 0; // test | ||
| 119 | } | ||
| 120 | |||
| 121 | Model* model = gfx_load_model( | ||
| 122 | game->gfx, &(LoadModelCmd){.origin = AssetFromFile, | ||
| 123 | .filepath = mstring_make(scene_filepath)}); | ||
| 124 | if (!model) { | ||
| 125 | return 0; | ||
| 126 | } | ||
| 127 | SceneNode* model_node = gfx_make_model_node(model); | ||
| 128 | if (!model_node) { | ||
| 129 | return 0; | ||
| 130 | } | ||
| 131 | gfx_set_node_parent(model_node, sky_light_node); | ||
| 132 | |||
| 133 | gfx_log_node_hierarchy(root); | ||
| 134 | |||
| 135 | return model; | ||
| 136 | } | ||
| 137 | |||
| 138 | bool init(Game* game, State** pp_state) { | ||
| 139 | assert(game); | ||
| 140 | |||
| 141 | // Usage: <scene file> | ||
| 142 | const char* scene_filepath = | ||
| 143 | game->argc > 1 ? game->argv[1] : DEFAULT_SCENE_FILE; | ||
| 144 | |||
| 145 | State* state = calloc(1, sizeof(State)); | ||
| 146 | if (!state) { | ||
| 147 | goto cleanup; | ||
| 148 | } | ||
| 149 | |||
| 150 | if (!(state->scene = gfx_make_scene())) { | ||
| 151 | goto cleanup; | ||
| 152 | } | ||
| 153 | if (!(state->camera = gfx_make_camera())) { | ||
| 154 | goto cleanup; | ||
| 155 | } | ||
| 156 | |||
| 157 | state->model = load_scene(game, state, scene_filepath); | ||
| 158 | if (!state->model) { | ||
| 159 | goto cleanup; | ||
| 160 | } | ||
| 161 | |||
| 162 | Anima* anima = gfx_get_model_anima(state->model); | ||
| 163 | if (anima) { | ||
| 164 | gfx_play_animation( | ||
| 165 | anima, &(AnimationPlaySettings){.name = "Walk", .loop = true}); | ||
| 166 | // TODO: Interpolate animations. | ||
| 167 | /*gfx_play_animation( | ||
| 168 | anima, | ||
| 169 | &(AnimationPlaySettings){.name = "Jumping-jack-lower", .loop = true}); | ||
| 170 | gfx_play_animation( | ||
| 171 | anima, &(AnimationPlaySettings){ | ||
| 172 | .name = "Jumping-jack-arms-mid", .loop = true});*/ | ||
| 173 | } | ||
| 174 | |||
| 175 | spatial3_set_position( | ||
| 176 | &gfx_get_camera_camera(state->camera)->spatial, DefaultCameraPosition); | ||
| 177 | |||
| 178 | state->camera_controller.camera_speed = DefaultCameraSpeed; | ||
| 179 | state->camera_controller.mouse_sensitivity = DefaultMouseSensitivity; | ||
| 180 | |||
| 181 | *pp_state = state; | ||
| 182 | return true; | ||
| 183 | |||
| 184 | cleanup: | ||
| 185 | shutdown(game, state); | ||
| 186 | if (state) { | ||
| 187 | free(state); | ||
| 188 | } | ||
| 189 | return false; | ||
| 190 | } | ||
| 191 | |||
| 192 | void shutdown(Game* game, State* state) { | ||
| 193 | assert(game); | ||
| 194 | if (state) { | ||
| 195 | gfx_destroy_camera(&state->camera); | ||
| 196 | gfx_destroy_scene(&state->scene); | ||
| 197 | // State freed by plugin engine. | ||
| 198 | } | ||
| 199 | } | ||
| 200 | |||
| 201 | static void update_camera( | ||
| 202 | CameraController* controller, R dt, vec2 mouse_position, | ||
| 203 | CameraCommand command, Spatial3* camera) { | ||
| 204 | assert(controller); | ||
| 205 | assert(camera); | ||
| 206 | |||
| 207 | // Translation. | ||
| 208 | const R move_x = (R)(command.CameraMoveLeft ? -1 : 0) + | ||
| 209 | (R)(command.CameraMoveRight ? 1 : 0); | ||
| 210 | const R move_y = (R)(command.CameraMoveForward ? 1 : 0) + | ||
| 211 | (R)(command.CameraMoveBackward ? -1 : 0); | ||
| 212 | const vec2 translation = | ||
| 213 | vec2_scale(vec2_make(move_x, move_y), controller->camera_speed * dt); | ||
| 214 | spatial3_move_right(camera, translation.x); | ||
| 215 | spatial3_move_forwards(camera, translation.y); | ||
| 216 | |||
| 217 | // Rotation. | ||
| 218 | if (controller->rotating) { | ||
| 219 | const vec2 mouse_delta = | ||
| 220 | vec2_sub(mouse_position, controller->prev_mouse_position); | ||
| 221 | |||
| 222 | const vec2 rotation = | ||
| 223 | vec2_scale(mouse_delta, controller->mouse_sensitivity * dt); | ||
| 224 | |||
| 225 | spatial3_global_yaw(camera, -rotation.x); | ||
| 226 | spatial3_pitch(camera, -rotation.y); | ||
| 227 | } | ||
| 228 | |||
| 229 | // Update controller state. | ||
| 230 | controller->prev_mouse_position = mouse_position; | ||
| 231 | } | ||
| 232 | |||
| 233 | void update(Game* game, State* state, double t, double dt) { | ||
| 234 | assert(game); | ||
| 235 | assert(state); | ||
| 236 | assert(state->scene); | ||
| 237 | assert(state->camera); | ||
| 238 | |||
| 239 | double mouse_x, mouse_y; | ||
| 240 | gfx_app_get_mouse_position(&mouse_x, &mouse_y); | ||
| 241 | const vec2 mouse_position = {(R)mouse_x, (R)mouse_y}; | ||
| 242 | |||
| 243 | const CameraCommand camera_command = (CameraCommand){ | ||
| 244 | .CameraMoveLeft = gfx_app_is_key_pressed(KeyA), | ||
| 245 | .CameraMoveRight = gfx_app_is_key_pressed(KeyD), | ||
| 246 | .CameraMoveForward = gfx_app_is_key_pressed(KeyW), | ||
| 247 | .CameraMoveBackward = gfx_app_is_key_pressed(KeyS), | ||
| 248 | }; | ||
| 249 | |||
| 250 | state->camera_controller.rotating = gfx_app_is_mouse_button_pressed(LMB); | ||
| 251 | |||
| 252 | update_camera( | ||
| 253 | &state->camera_controller, (R)dt, mouse_position, camera_command, | ||
| 254 | &gfx_get_camera_camera(state->camera)->spatial); | ||
| 255 | |||
| 256 | // const vec3 orbit_point = vec3_make(0, 2, 0); | ||
| 257 | // Camera* camera = gfx_get_camera_camera(state->camera); | ||
| 258 | // spatial3_orbit( | ||
| 259 | // &camera->spatial, orbit_point, | ||
| 260 | // /*radius=*/5, | ||
| 261 | // /*azimuth=*/(R)(t * 0.5), /*zenith=*/0); | ||
| 262 | // spatial3_lookat(&camera->spatial, orbit_point); | ||
| 263 | |||
| 264 | gfx_update(state->scene, state->camera, (R)t); | ||
| 265 | } | ||
| 266 | |||
| 267 | /// Render the bounding boxes of all scene objects. | ||
| 268 | static void render_bounding_boxes_rec( | ||
| 269 | ImmRenderer* imm, const Anima* anima, const mat4* parent_model_matrix, | ||
| 270 | const SceneNode* node) { | ||
| 271 | assert(imm); | ||
| 272 | assert(node); | ||
| 273 | |||
| 274 | const mat4 model_matrix = | ||
| 275 | mat4_mul(*parent_model_matrix, gfx_get_node_transform(node)); | ||
| 276 | |||
| 277 | const NodeType node_type = gfx_get_node_type(node); | ||
| 278 | |||
| 279 | if (node_type == ModelNode) { | ||
| 280 | const Model* model = gfx_get_node_model(node); | ||
| 281 | const SceneNode* root = gfx_get_model_root(model); | ||
| 282 | render_bounding_boxes_rec(imm, anima, &model_matrix, root); | ||
| 283 | } else if (node_type == AnimaNode) { | ||
| 284 | anima = gfx_get_node_anima(node); | ||
| 285 | } else if (node_type == ObjectNode) { | ||
| 286 | gfx_imm_set_model_matrix(imm, &model_matrix); | ||
| 287 | |||
| 288 | const SceneObject* obj = gfx_get_node_object(node); | ||
| 289 | const Skeleton* skeleton = gfx_get_object_skeleton(obj); | ||
| 290 | |||
| 291 | if (skeleton) { // Animated model. | ||
| 292 | assert(anima); | ||
| 293 | const size_t num_joints = gfx_get_skeleton_num_joints(skeleton); | ||
| 294 | for (size_t i = 0; i < num_joints; ++i) { | ||
| 295 | if (gfx_joint_has_box(anima, skeleton, i)) { | ||
| 296 | const Box box = gfx_get_joint_box(anima, skeleton, i); | ||
| 297 | gfx_imm_draw_box3(imm, box.vertices); | ||
| 298 | } | ||
| 299 | } | ||
| 300 | } else { // Static model. | ||
| 301 | const aabb3 box = gfx_get_object_aabb(obj); | ||
| 302 | gfx_imm_draw_aabb3(imm, box); | ||
| 303 | } | ||
| 304 | } | ||
| 305 | |||
| 306 | // Render children's boxes. | ||
| 307 | const SceneNode* child = gfx_get_node_child(node); | ||
| 308 | while (child) { | ||
| 309 | render_bounding_boxes_rec(imm, anima, &model_matrix, child); | ||
| 310 | child = gfx_get_node_sibling(child); | ||
| 311 | } | ||
| 312 | } | ||
| 313 | |||
| 314 | /// Render the bounding boxes of all scene objects. | ||
| 315 | static void render_bounding_boxes(const Game* game, const State* state) { | ||
| 316 | assert(game); | ||
| 317 | assert(state); | ||
| 318 | |||
| 319 | GfxCore* gfxcore = gfx_get_core(game->gfx); | ||
| 320 | ImmRenderer* imm = gfx_get_imm_renderer(game->gfx); | ||
| 321 | assert(gfxcore); | ||
| 322 | assert(imm); | ||
| 323 | |||
| 324 | const mat4 id = mat4_id(); | ||
| 325 | Anima* anima = 0; | ||
| 326 | |||
| 327 | gfx_set_blending(gfxcore, true); | ||
| 328 | gfx_set_depth_mask(gfxcore, false); | ||
| 329 | gfx_set_polygon_offset(gfxcore, -1.5f, -1.0f); | ||
| 330 | |||
| 331 | gfx_imm_start(imm); | ||
| 332 | gfx_imm_set_camera(imm, gfx_get_camera_camera(state->camera)); | ||
| 333 | gfx_imm_set_colour(imm, vec4_make(0.3, 0.3, 0.9, 0.1)); | ||
| 334 | render_bounding_boxes_rec(imm, anima, &id, gfx_get_scene_root(state->scene)); | ||
| 335 | gfx_imm_end(imm); | ||
| 336 | |||
| 337 | gfx_reset_polygon_offset(gfxcore); | ||
| 338 | gfx_set_depth_mask(gfxcore, true); | ||
| 339 | gfx_set_blending(gfxcore, false); | ||
| 340 | } | ||
| 341 | |||
| 342 | void render(const Game* game, const State* state) { | ||
| 343 | assert(state); | ||
| 344 | assert(game); | ||
| 345 | assert(game->gfx); | ||
| 346 | assert(state->scene); | ||
| 347 | assert(state->camera); | ||
| 348 | |||
| 349 | Renderer* renderer = gfx_get_renderer(game->gfx); | ||
| 350 | assert(renderer); | ||
| 351 | |||
| 352 | gfx_render_scene( | ||
| 353 | renderer, &(RenderSceneParams){.mode = RenderDefault, | ||
| 354 | .scene = state->scene, | ||
| 355 | .camera = state->camera}); | ||
| 356 | |||
| 357 | if (RenderBoundingBoxes) { | ||
| 358 | render_bounding_boxes(game, state); | ||
| 359 | } | ||
| 360 | } | ||
| 361 | |||
| 362 | void resize(Game* game, State* state, int width, int height) { | ||
| 363 | assert(game); | ||
| 364 | assert(state); | ||
| 365 | |||
| 366 | const R fovy = 60 * TO_RAD; | ||
| 367 | const R aspect = (R)width / (R)height; | ||
| 368 | const R near = 0.1; | ||
| 369 | const R far = 1000; | ||
| 370 | const mat4 projection = mat4_perspective(fovy, aspect, near, far); | ||
| 371 | |||
| 372 | Camera* camera = gfx_get_camera_camera(state->camera); | ||
| 373 | camera->projection = projection; | ||
| 374 | } | ||
diff --git a/gfx-iso/CMakeLists.txt b/gfx-iso/CMakeLists.txt deleted file mode 100644 index e4a677d..0000000 --- a/gfx-iso/CMakeLists.txt +++ /dev/null | |||
| @@ -1,42 +0,0 @@ | |||
| 1 | cmake_minimum_required(VERSION 3.0) | ||
| 2 | |||
| 3 | project(isogfx) | ||
| 4 | |||
| 5 | set(CMAKE_C_STANDARD 17) | ||
| 6 | set(CMAKE_C_STANDARD_REQUIRED On) | ||
| 7 | set(CMAKE_C_EXTENSIONS Off) | ||
| 8 | |||
| 9 | # isogfx | ||
| 10 | |||
| 11 | add_library(isogfx | ||
| 12 | src/isogfx.c) | ||
| 13 | |||
| 14 | target_include_directories(isogfx PUBLIC | ||
| 15 | include) | ||
| 16 | |||
| 17 | target_link_libraries(isogfx PUBLIC | ||
| 18 | filesystem | ||
| 19 | mem | ||
| 20 | mempool) | ||
| 21 | |||
| 22 | target_compile_options(isogfx PRIVATE -Wall -Wextra -Wpedantic) | ||
| 23 | |||
| 24 | # Backend | ||
| 25 | |||
| 26 | add_library(isogfx-backend | ||
| 27 | src/backend.c) | ||
| 28 | |||
| 29 | target_include_directories(isogfx-backend PUBLIC | ||
| 30 | include) | ||
| 31 | |||
| 32 | target_link_libraries(isogfx-backend PUBLIC | ||
| 33 | isogfx) | ||
| 34 | |||
| 35 | target_link_libraries(isogfx-backend PRIVATE | ||
| 36 | gfx) | ||
| 37 | |||
| 38 | target_compile_options(isogfx-backend PRIVATE -Wall -Wextra -Wpedantic) | ||
| 39 | |||
| 40 | # Demos | ||
| 41 | |||
| 42 | add_subdirectory(demos) | ||
diff --git a/gfx-iso/demos/CMakeLists.txt b/gfx-iso/demos/CMakeLists.txt deleted file mode 100644 index c0a4101..0000000 --- a/gfx-iso/demos/CMakeLists.txt +++ /dev/null | |||
| @@ -1,2 +0,0 @@ | |||
| 1 | add_subdirectory(checkerboard) | ||
| 2 | add_subdirectory(isomap) | ||
diff --git a/gfx-iso/demos/checkerboard/CMakeLists.txt b/gfx-iso/demos/checkerboard/CMakeLists.txt deleted file mode 100644 index d1691c6..0000000 --- a/gfx-iso/demos/checkerboard/CMakeLists.txt +++ /dev/null | |||
| @@ -1,16 +0,0 @@ | |||
| 1 | cmake_minimum_required(VERSION 3.0) | ||
| 2 | |||
| 3 | project(checkerboard) | ||
| 4 | |||
| 5 | set(CMAKE_C_STANDARD 17) | ||
| 6 | set(CMAKE_C_STANDARD_REQUIRED On) | ||
| 7 | set(CMAKE_C_EXTENSIONS Off) | ||
| 8 | |||
| 9 | add_executable(checkerboard | ||
| 10 | checkerboard.c) | ||
| 11 | |||
| 12 | target_link_libraries(checkerboard PRIVATE | ||
| 13 | gfx-app | ||
| 14 | isogfx-backend) | ||
| 15 | |||
| 16 | target_compile_options(checkerboard PRIVATE -Wall -Wextra -Wpedantic) | ||
diff --git a/gfx-iso/demos/checkerboard/checkerboard.c b/gfx-iso/demos/checkerboard/checkerboard.c deleted file mode 100644 index dbc817c..0000000 --- a/gfx-iso/demos/checkerboard/checkerboard.c +++ /dev/null | |||
| @@ -1,166 +0,0 @@ | |||
| 1 | #include <isogfx/backend.h> | ||
| 2 | #include <isogfx/isogfx.h> | ||
| 3 | |||
| 4 | #include <gfx/app.h> | ||
| 5 | |||
| 6 | #include <assert.h> | ||
| 7 | #include <stdbool.h> | ||
| 8 | #include <stdio.h> | ||
| 9 | |||
| 10 | static const int WINDOW_WIDTH = 1408; | ||
| 11 | static const int WINDOW_HEIGHT = 960; | ||
| 12 | static const int MAX_FPS = 60; | ||
| 13 | |||
| 14 | // Virtual screen dimensions. | ||
| 15 | static const int SCREEN_WIDTH = 704; | ||
| 16 | static const int SCREEN_HEIGHT = 480; | ||
| 17 | |||
| 18 | static const int TILE_WIDTH = 32; | ||
| 19 | static const int TILE_HEIGHT = TILE_WIDTH / 2; | ||
| 20 | static const int WORLD_WIDTH = 20; | ||
| 21 | static const int WORLD_HEIGHT = 20; | ||
| 22 | |||
| 23 | static const TileDesc tile_set[] = { | ||
| 24 | {.type = TileFromColour, | ||
| 25 | .width = TILE_WIDTH, | ||
| 26 | .height = TILE_HEIGHT, | ||
| 27 | .colour = (Pixel){.r = 0x38, .g = 0x3b, .b = 0x46, .a = 0xff}}, | ||
| 28 | {.type = TileFromColour, | ||
| 29 | .width = TILE_WIDTH, | ||
| 30 | .height = TILE_HEIGHT, | ||
| 31 | .colour = (Pixel){.r = 0xA5, .g = 0xb3, .b = 0xc0, .a = 0xff}}, | ||
| 32 | {.type = TileFromColour, | ||
| 33 | .width = TILE_WIDTH, | ||
| 34 | .height = TILE_HEIGHT, | ||
| 35 | .colour = (Pixel){.r = 0xdc, .g = 0x76, .b = 0x84, .a = 0xff}}, | ||
| 36 | }; | ||
| 37 | |||
| 38 | typedef enum Colour { | ||
| 39 | Black, | ||
| 40 | White, | ||
| 41 | Red, | ||
| 42 | } Colour; | ||
| 43 | |||
| 44 | typedef struct GfxAppState { | ||
| 45 | IsoBackend* backend; | ||
| 46 | IsoGfx* iso; | ||
| 47 | Tile red; | ||
| 48 | int xpick; | ||
| 49 | int ypick; | ||
| 50 | } GfxAppState; | ||
| 51 | |||
| 52 | static void make_checkerboard(IsoGfx* iso, Tile black, Tile white) { | ||
| 53 | assert(iso); | ||
| 54 | for (int y = 0; y < isogfx_world_height(iso); ++y) { | ||
| 55 | for (int x = 0; x < isogfx_world_width(iso); ++x) { | ||
| 56 | const int odd_col = x & 1; | ||
| 57 | const int odd_row = y & 1; | ||
| 58 | const Tile value = (odd_row ^ odd_col) == 0 ? black : white; | ||
| 59 | isogfx_set_tile(iso, x, y, value); | ||
| 60 | } | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | static bool init(GfxAppState* state, int argc, const char** argv) { | ||
| 65 | assert(state); | ||
| 66 | |||
| 67 | (void)argc; | ||
| 68 | (void)argv; | ||
| 69 | |||
| 70 | if (!(state->iso = isogfx_new(&(IsoGfxDesc){ | ||
| 71 | .screen_width = SCREEN_WIDTH, .screen_height = SCREEN_HEIGHT}))) { | ||
| 72 | return false; | ||
| 73 | } | ||
| 74 | IsoGfx* iso = state->iso; | ||
| 75 | |||
| 76 | isogfx_resize(iso, SCREEN_WIDTH, SCREEN_HEIGHT); | ||
| 77 | |||
| 78 | if (!isogfx_make_world( | ||
| 79 | iso, &(WorldDesc){ | ||
| 80 | .tile_width = TILE_WIDTH, | ||
| 81 | .tile_height = TILE_HEIGHT, | ||
| 82 | .world_width = WORLD_WIDTH, | ||
| 83 | .world_height = WORLD_HEIGHT})) { | ||
| 84 | return false; | ||
| 85 | } | ||
| 86 | |||
| 87 | const Tile black = isogfx_make_tile(iso, &tile_set[Black]); | ||
| 88 | const Tile white = isogfx_make_tile(iso, &tile_set[White]); | ||
| 89 | state->red = isogfx_make_tile(iso, &tile_set[Red]); | ||
| 90 | make_checkerboard(iso, black, white); | ||
| 91 | |||
| 92 | if (!(state->backend = IsoBackendInit(iso))) { | ||
| 93 | return false; | ||
| 94 | } | ||
| 95 | |||
| 96 | return true; | ||
| 97 | } | ||
| 98 | |||
| 99 | static void shutdown(GfxAppState* state) { | ||
| 100 | assert(state); | ||
| 101 | |||
| 102 | IsoBackendShutdown(&state->backend); | ||
| 103 | isogfx_del(&state->iso); | ||
| 104 | } | ||
| 105 | |||
| 106 | static void update(GfxAppState* state, double t, double dt) { | ||
| 107 | assert(state); | ||
| 108 | (void)dt; | ||
| 109 | |||
| 110 | IsoGfx* iso = state->iso; | ||
| 111 | |||
| 112 | isogfx_update(iso, t); | ||
| 113 | |||
| 114 | // Get mouse position in window coordinates. | ||
| 115 | double mouse_x, mouse_y; | ||
| 116 | gfx_app_get_mouse_position(&mouse_x, &mouse_y); | ||
| 117 | |||
| 118 | // Map from window coordinates to virtual screen coordinates. | ||
| 119 | IsoBackendGetMousePosition( | ||
| 120 | state->backend, mouse_x, mouse_y, &mouse_x, &mouse_y); | ||
| 121 | |||
| 122 | isogfx_pick_tile(iso, mouse_x, mouse_y, &state->xpick, &state->ypick); | ||
| 123 | |||
| 124 | printf("Picked tile: (%d, %d)\n", state->xpick, state->ypick); | ||
| 125 | } | ||
| 126 | |||
| 127 | static void render(GfxAppState* state) { | ||
| 128 | assert(state); | ||
| 129 | |||
| 130 | IsoGfx* iso = state->iso; | ||
| 131 | |||
| 132 | isogfx_render(iso); | ||
| 133 | |||
| 134 | if ((state->xpick != -1) && (state->ypick != -1)) { | ||
| 135 | isogfx_draw_tile(iso, state->xpick, state->ypick, state->red); | ||
| 136 | } | ||
| 137 | |||
| 138 | IsoBackendRender(state->backend, iso); | ||
| 139 | } | ||
| 140 | |||
| 141 | static void resize(GfxAppState* state, int width, int height) { | ||
| 142 | assert(state); | ||
| 143 | |||
| 144 | IsoBackendResizeWindow(state->backend, state->iso, width, height); | ||
| 145 | } | ||
| 146 | |||
| 147 | int main(int argc, const char** argv) { | ||
| 148 | GfxAppState state = {0}; | ||
| 149 | gfx_app_run( | ||
| 150 | &(GfxAppDesc){ | ||
| 151 | .argc = argc, | ||
| 152 | .argv = argv, | ||
| 153 | .width = WINDOW_WIDTH, | ||
| 154 | .height = WINDOW_HEIGHT, | ||
| 155 | .max_fps = MAX_FPS, | ||
| 156 | .update_delta_time = MAX_FPS > 0 ? 1.0 / (double)MAX_FPS : 0.0, | ||
| 157 | .title = "Isometric Renderer", | ||
| 158 | .app_state = &state}, | ||
| 159 | &(GfxAppCallbacks){ | ||
| 160 | .init = init, | ||
| 161 | .update = update, | ||
| 162 | .render = render, | ||
| 163 | .resize = resize, | ||
| 164 | .shutdown = shutdown}); | ||
| 165 | return 0; | ||
| 166 | } | ||
diff --git a/gfx-iso/demos/isomap/CMakeLists.txt b/gfx-iso/demos/isomap/CMakeLists.txt deleted file mode 100644 index 2dbfd32..0000000 --- a/gfx-iso/demos/isomap/CMakeLists.txt +++ /dev/null | |||
| @@ -1,16 +0,0 @@ | |||
| 1 | cmake_minimum_required(VERSION 3.0) | ||
| 2 | |||
| 3 | project(isomap) | ||
| 4 | |||
| 5 | set(CMAKE_C_STANDARD 17) | ||
| 6 | set(CMAKE_C_STANDARD_REQUIRED On) | ||
| 7 | set(CMAKE_C_EXTENSIONS Off) | ||
| 8 | |||
| 9 | add_executable(isomap | ||
| 10 | isomap.c) | ||
| 11 | |||
| 12 | target_link_libraries(isomap PRIVATE | ||
| 13 | gfx-app | ||
| 14 | isogfx-backend) | ||
| 15 | |||
| 16 | target_compile_options(isomap PRIVATE -Wall -Wextra -Wpedantic) | ||
diff --git a/gfx-iso/demos/isomap/isomap.c b/gfx-iso/demos/isomap/isomap.c deleted file mode 100644 index a233659..0000000 --- a/gfx-iso/demos/isomap/isomap.c +++ /dev/null | |||
| @@ -1,105 +0,0 @@ | |||
| 1 | #include <isogfx/backend.h> | ||
| 2 | #include <isogfx/isogfx.h> | ||
| 3 | |||
| 4 | #include <gfx/app.h> | ||
| 5 | |||
| 6 | #include <assert.h> | ||
| 7 | #include <stdbool.h> | ||
| 8 | |||
| 9 | static const int WINDOW_WIDTH = 1408; | ||
| 10 | static const int WINDOW_HEIGHT = 960; | ||
| 11 | static const int MAX_FPS = 60; | ||
| 12 | |||
| 13 | // Virtual screen dimensions. | ||
| 14 | static const int SCREEN_WIDTH = 704; | ||
| 15 | static const int SCREEN_HEIGHT = 480; | ||
| 16 | |||
| 17 | typedef struct GfxAppState { | ||
| 18 | IsoBackend* backend; | ||
| 19 | IsoGfx* iso; | ||
| 20 | int xpick; | ||
| 21 | int ypick; | ||
| 22 | SpriteSheet stag_sheet; | ||
| 23 | Sprite stag; | ||
| 24 | } GfxAppState; | ||
| 25 | |||
| 26 | static bool init(GfxAppState* state, int argc, const char** argv) { | ||
| 27 | assert(state); | ||
| 28 | (void)argc; | ||
| 29 | (void)argv; | ||
| 30 | |||
| 31 | if (!(state->iso = isogfx_new(&(IsoGfxDesc){ | ||
| 32 | .screen_width = SCREEN_WIDTH, .screen_height = SCREEN_HEIGHT}))) { | ||
| 33 | return false; | ||
| 34 | } | ||
| 35 | IsoGfx* iso = state->iso; | ||
| 36 | |||
| 37 | isogfx_resize(iso, SCREEN_WIDTH, SCREEN_HEIGHT); | ||
| 38 | |||
| 39 | if (!isogfx_load_world(iso, "/home/jeanne/assets/tilemaps/demo1.tm")) { | ||
| 40 | return false; | ||
| 41 | } | ||
| 42 | |||
| 43 | if (!isogfx_load_sprite_sheet( | ||
| 44 | iso, "/home/jeanne/assets/tilesets/scrabling/critters/stag/stag.ss", | ||
| 45 | &state->stag_sheet)) { | ||
| 46 | return false; | ||
| 47 | } | ||
| 48 | |||
| 49 | state->stag = isogfx_make_sprite(iso, state->stag_sheet); | ||
| 50 | isogfx_set_sprite_position(iso, state->stag, 5, 4); | ||
| 51 | |||
| 52 | if (!(state->backend = IsoBackendInit(iso))) { | ||
| 53 | return false; | ||
| 54 | } | ||
| 55 | |||
| 56 | return true; | ||
| 57 | } | ||
| 58 | |||
| 59 | static void shutdown(GfxAppState* state) { | ||
| 60 | assert(state); | ||
| 61 | // | ||
| 62 | } | ||
| 63 | |||
| 64 | static void update(GfxAppState* state, double t, double dt) { | ||
| 65 | assert(state); | ||
| 66 | (void)dt; | ||
| 67 | |||
| 68 | IsoGfx* iso = state->iso; | ||
| 69 | isogfx_update(iso, t); | ||
| 70 | } | ||
| 71 | |||
| 72 | static void render(GfxAppState* state) { | ||
| 73 | assert(state); | ||
| 74 | |||
| 75 | IsoGfx* iso = state->iso; | ||
| 76 | isogfx_render(iso); | ||
| 77 | IsoBackendRender(state->backend, iso); | ||
| 78 | } | ||
| 79 | |||
| 80 | static void resize(GfxAppState* state, int width, int height) { | ||
| 81 | assert(state); | ||
| 82 | |||
| 83 | IsoBackendResizeWindow(state->backend, state->iso, width, height); | ||
| 84 | } | ||
| 85 | |||
| 86 | int main(int argc, const char** argv) { | ||
| 87 | GfxAppState state = {0}; | ||
| 88 | gfx_app_run( | ||
| 89 | &(GfxAppDesc){ | ||
| 90 | .argc = argc, | ||
| 91 | .argv = argv, | ||
| 92 | .width = WINDOW_WIDTH, | ||
| 93 | .height = WINDOW_HEIGHT, | ||
| 94 | .max_fps = MAX_FPS, | ||
| 95 | .update_delta_time = MAX_FPS > 0 ? 1.0 / (double)MAX_FPS : 0.0, | ||
| 96 | .title = "Isometric Renderer", | ||
| 97 | .app_state = &state}, | ||
| 98 | &(GfxAppCallbacks){ | ||
| 99 | .init = init, | ||
| 100 | .update = update, | ||
| 101 | .render = render, | ||
| 102 | .resize = resize, | ||
| 103 | .shutdown = shutdown}); | ||
| 104 | return 0; | ||
| 105 | } | ||
diff --git a/gfx-iso/include/isogfx/backend.h b/gfx-iso/include/isogfx/backend.h deleted file mode 100644 index 172991d..0000000 --- a/gfx-iso/include/isogfx/backend.h +++ /dev/null | |||
| @@ -1,28 +0,0 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <stdbool.h> | ||
| 4 | |||
| 5 | typedef struct Gfx Gfx; | ||
| 6 | typedef struct IsoGfx IsoGfx; | ||
| 7 | |||
| 8 | typedef struct IsoBackend IsoBackend; | ||
| 9 | |||
| 10 | /// Initialize the backend. | ||
| 11 | IsoBackend* IsoBackendInit(const IsoGfx*); | ||
| 12 | |||
| 13 | /// Shut down the backend. | ||
| 14 | void IsoBackendShutdown(IsoBackend**); | ||
| 15 | |||
| 16 | /// Notify the backend of a window resize event. | ||
| 17 | /// This allows the backend to determine how to position and scale the iso | ||
| 18 | /// screen buffer on the graphics window. | ||
| 19 | void IsoBackendResizeWindow(IsoBackend*, const IsoGfx*, int width, int height); | ||
| 20 | |||
| 21 | /// Render the iso screen to the graphics window. | ||
| 22 | void IsoBackendRender(const IsoBackend*, const IsoGfx*); | ||
| 23 | |||
| 24 | /// Map window coordinates to iso space coordinates. | ||
| 25 | /// This takes into account any possible resizing done by the backend in | ||
| 26 | /// response to calls to IsoBackendResizeWindow(). | ||
| 27 | bool IsoBackendGetMousePosition( | ||
| 28 | const IsoBackend*, double window_x, double window_y, double* x, double* y); | ||
diff --git a/gfx-iso/include/isogfx/isogfx.h b/gfx-iso/include/isogfx/isogfx.h deleted file mode 100644 index 3421a7b..0000000 --- a/gfx-iso/include/isogfx/isogfx.h +++ /dev/null | |||
| @@ -1,136 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Isometric rendering engine. | ||
| 3 | */ | ||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <stdbool.h> | ||
| 7 | #include <stdint.h> | ||
| 8 | |||
| 9 | typedef struct IsoGfx IsoGfx; | ||
| 10 | |||
| 11 | /// Sprite sheet handle. | ||
| 12 | typedef uint16_t SpriteSheet; | ||
| 13 | |||
| 14 | /// Sprite handle. | ||
| 15 | typedef uint16_t Sprite; | ||
| 16 | |||
| 17 | /// Tile handle. | ||
| 18 | typedef uint16_t Tile; | ||
| 19 | |||
| 20 | /// Colour channel. | ||
| 21 | typedef uint8_t Channel; | ||
| 22 | |||
| 23 | typedef struct Pixel { | ||
| 24 | Channel r, g, b, a; | ||
| 25 | } Pixel; | ||
| 26 | |||
| 27 | typedef enum TileDescType { | ||
| 28 | TileFromColour, | ||
| 29 | TileFromFile, | ||
| 30 | TileFromMemory, | ||
| 31 | } TileDescType; | ||
| 32 | |||
| 33 | typedef struct TileDesc { | ||
| 34 | TileDescType type; | ||
| 35 | int width; /// Tile width in pixels. | ||
| 36 | int height; /// Tile height in pixels. | ||
| 37 | union { | ||
| 38 | Pixel colour; /// Constant colour tile. | ||
| 39 | struct { | ||
| 40 | const char* path; | ||
| 41 | } file; | ||
| 42 | struct { | ||
| 43 | const uint8_t* data; /// sizeof(Pixel) * width * height | ||
| 44 | } mem; | ||
| 45 | }; | ||
| 46 | } TileDesc; | ||
| 47 | |||
| 48 | typedef struct WorldDesc { | ||
| 49 | int tile_width; /// Base tile width in pixels. | ||
| 50 | int tile_height; /// Base tile height in pixels. | ||
| 51 | int world_width; /// World width in tiles. | ||
| 52 | int world_height; /// World height in tiles. | ||
| 53 | int max_num_tiles; /// 0 for an implementation-defined default. | ||
| 54 | } WorldDesc; | ||
| 55 | |||
| 56 | typedef struct IsoGfxDesc { | ||
| 57 | int screen_width; /// Screen width in pixels. | ||
| 58 | int screen_height; /// Screen height in pixels. | ||
| 59 | int max_num_sprites; /// 0 for an implementation-defined default. | ||
| 60 | int sprite_sheet_pool_size_bytes; /// 0 for an implementation-defined default. | ||
| 61 | } IsoGfxDesc; | ||
| 62 | |||
| 63 | /// Create a new isometric graphics engine. | ||
| 64 | IsoGfx* isogfx_new(const IsoGfxDesc*); | ||
| 65 | |||
| 66 | /// Destroy the isometric graphics engine. | ||
| 67 | void isogfx_del(IsoGfx**); | ||
| 68 | |||
| 69 | /// Create an empty world. | ||
| 70 | bool isogfx_make_world(IsoGfx*, const WorldDesc*); | ||
| 71 | |||
| 72 | /// Load a world from a tile map (.TM) file. | ||
| 73 | bool isogfx_load_world(IsoGfx*, const char* filepath); | ||
| 74 | |||
| 75 | /// Return the world's width. | ||
| 76 | int isogfx_world_width(const IsoGfx*); | ||
| 77 | |||
| 78 | /// Return the world's height. | ||
| 79 | int isogfx_world_height(const IsoGfx*); | ||
| 80 | |||
| 81 | /// Create a new tile. | ||
| 82 | Tile isogfx_make_tile(IsoGfx*, const TileDesc*); | ||
| 83 | |||
| 84 | /// Set the tile at position (x,y). | ||
| 85 | void isogfx_set_tile(IsoGfx*, int x, int y, Tile); | ||
| 86 | |||
| 87 | /// Set the tiles in positions in the range (x0,y0) - (x1,y1). | ||
| 88 | void isogfx_set_tiles(IsoGfx*, int x0, int y0, int x1, int y1, Tile); | ||
| 89 | |||
| 90 | /// Load a sprite sheet (.SS) file. | ||
| 91 | bool isogfx_load_sprite_sheet(IsoGfx*, const char* filepath, SpriteSheet*); | ||
| 92 | |||
| 93 | /// Create an animated sprite. | ||
| 94 | Sprite isogfx_make_sprite(IsoGfx*, SpriteSheet); | ||
| 95 | |||
| 96 | /// Destroy the sprite. | ||
| 97 | void isogfx_del_sprite(IsoGfx*, Sprite); | ||
| 98 | |||
| 99 | /// Destroy all the sprites. | ||
| 100 | void isogfx_del_sprites(IsoGfx*); | ||
| 101 | |||
| 102 | /// Set the sprite's position. | ||
| 103 | void isogfx_set_sprite_position(IsoGfx*, Sprite, int x, int y); | ||
| 104 | |||
| 105 | /// Set the sprite's current animation. | ||
| 106 | void isogfx_set_sprite_animation(IsoGfx*, Sprite, int animation); | ||
| 107 | |||
| 108 | /// Update the renderer. | ||
| 109 | /// | ||
| 110 | /// Currently this updates the sprite animations. | ||
| 111 | void isogfx_update(IsoGfx*, double t); | ||
| 112 | |||
| 113 | /// Render the world. | ||
| 114 | void isogfx_render(IsoGfx*); | ||
| 115 | |||
| 116 | /// Draw/overlay a tile at position (x,y). | ||
| 117 | /// | ||
| 118 | /// This function just renders a tile at position (x,y) and should be called | ||
| 119 | /// after isogfx_render() to obtain the correct result. To set the tile at | ||
| 120 | /// position (x,y) instead, use isogfx_set_tile(). | ||
| 121 | void isogfx_draw_tile(IsoGfx*, int x, int y, Tile); | ||
| 122 | |||
| 123 | /// Resize the virtual screen's dimensions. | ||
| 124 | bool isogfx_resize(IsoGfx*, int screen_width, int screen_height); | ||
| 125 | |||
| 126 | /// Get the virtual screen's dimensions. | ||
| 127 | void isogfx_get_screen_size(const IsoGfx*, int* width, int* height); | ||
| 128 | |||
| 129 | /// Return a pointer to the virtual screen's colour buffer. | ||
| 130 | /// | ||
| 131 | /// Call after each call to isogfx_render() to retrieve the render output. | ||
| 132 | const Pixel* isogfx_get_screen_buffer(const IsoGfx*); | ||
| 133 | |||
| 134 | /// Translate Cartesian to isometric coordinates. | ||
| 135 | void isogfx_pick_tile( | ||
| 136 | const IsoGfx*, double xcart, double ycart, int* xiso, int* yiso); | ||
diff --git a/gfx-iso/src/backend.c b/gfx-iso/src/backend.c deleted file mode 100644 index db91647..0000000 --- a/gfx-iso/src/backend.c +++ /dev/null | |||
| @@ -1,199 +0,0 @@ | |||
| 1 | #include <isogfx/backend.h> | ||
| 2 | #include <isogfx/isogfx.h> | ||
| 3 | |||
| 4 | #include <gfx/core.h> | ||
| 5 | #include <gfx/gfx.h> | ||
| 6 | #include <gfx/renderer.h> | ||
| 7 | #include <gfx/scene.h> | ||
| 8 | #include <gfx/util/geometry.h> | ||
| 9 | #include <gfx/util/shader.h> | ||
| 10 | |||
| 11 | #include <assert.h> | ||
| 12 | #include <stdlib.h> | ||
| 13 | |||
| 14 | typedef struct IsoBackend { | ||
| 15 | Gfx* gfx; | ||
| 16 | Scene* scene; | ||
| 17 | /// The screen or "iso screen" refers to the colour buffer of the iso graphics | ||
| 18 | /// library. This texture is used to draw the iso screen onto the graphics | ||
| 19 | /// window. | ||
| 20 | Texture* screen_texture; | ||
| 21 | /// Window size. | ||
| 22 | int window_width; | ||
| 23 | int window_height; | ||
| 24 | /// The viewport refers to the area inside the window to which screen_texture | ||
| 25 | /// is drawn. It is a scaled version of the iso screen, scaled while | ||
| 26 | /// respecting the iso screen's aspect ratio to prevent distortion. | ||
| 27 | int viewport_x, viewport_y, viewport_width, viewport_height; | ||
| 28 | double stretch; // Stretch factor from iso screen dimensions to viewport | ||
| 29 | // dimensions. | ||
| 30 | } IsoBackend; | ||
| 31 | |||
| 32 | IsoBackend* IsoBackendInit(const IsoGfx* iso) { | ||
| 33 | assert(iso); | ||
| 34 | |||
| 35 | IsoBackend* backend = calloc(1, sizeof(IsoBackend)); | ||
| 36 | if (!backend) { | ||
| 37 | return 0; | ||
| 38 | } | ||
| 39 | |||
| 40 | if (!(backend->gfx = gfx_init())) { | ||
| 41 | goto cleanup; | ||
| 42 | } | ||
| 43 | GfxCore* gfxcore = gfx_get_core(backend->gfx); | ||
| 44 | |||
| 45 | int screen_width, screen_height; | ||
| 46 | isogfx_get_screen_size(iso, &screen_width, &screen_height); | ||
| 47 | |||
| 48 | if (!(backend->screen_texture = gfx_make_texture( | ||
| 49 | gfxcore, &(TextureDesc){ | ||
| 50 | .width = screen_width, | ||
| 51 | .height = screen_height, | ||
| 52 | .dimension = Texture2D, | ||
| 53 | .format = TextureSRGBA8, | ||
| 54 | .filtering = NearestFiltering, | ||
| 55 | .wrap = ClampToEdge, | ||
| 56 | .mipmaps = false}))) { | ||
| 57 | goto cleanup; | ||
| 58 | } | ||
| 59 | |||
| 60 | ShaderProgram* shader = gfx_make_view_texture_shader(gfxcore); | ||
| 61 | if (!shader) { | ||
| 62 | goto cleanup; | ||
| 63 | } | ||
| 64 | |||
| 65 | Geometry* geometry = gfx_make_quad_11(gfxcore); | ||
| 66 | if (!geometry) { | ||
| 67 | goto cleanup; | ||
| 68 | } | ||
| 69 | |||
| 70 | MaterialDesc material_desc = (MaterialDesc){.num_uniforms = 1}; | ||
| 71 | material_desc.uniforms[0] = (ShaderUniform){ | ||
| 72 | .type = UniformTexture, | ||
| 73 | .value.texture = backend->screen_texture, | ||
| 74 | .name = sstring_make("Texture")}; | ||
| 75 | Material* material = gfx_make_material(&material_desc); | ||
| 76 | if (!material) { | ||
| 77 | return false; | ||
| 78 | } | ||
| 79 | |||
| 80 | const MeshDesc mesh_desc = | ||
| 81 | (MeshDesc){.geometry = geometry, .material = material, .shader = shader}; | ||
| 82 | Mesh* mesh = gfx_make_mesh(&mesh_desc); | ||
| 83 | if (!mesh) { | ||
| 84 | goto cleanup; | ||
| 85 | } | ||
| 86 | |||
| 87 | SceneObject* object = | ||
| 88 | gfx_make_object(&(ObjectDesc){.num_meshes = 1, .meshes = {mesh}}); | ||
| 89 | if (!object) { | ||
| 90 | goto cleanup; | ||
| 91 | } | ||
| 92 | |||
| 93 | backend->scene = gfx_make_scene(); | ||
| 94 | SceneNode* node = gfx_make_object_node(object); | ||
| 95 | SceneNode* root = gfx_get_scene_root(backend->scene); | ||
| 96 | gfx_set_node_parent(node, root); | ||
| 97 | |||
| 98 | return backend; | ||
| 99 | |||
| 100 | cleanup: | ||
| 101 | if (backend->gfx) { | ||
| 102 | gfx_destroy(&backend->gfx); | ||
| 103 | } | ||
| 104 | free(backend); | ||
| 105 | return 0; | ||
| 106 | } | ||
| 107 | |||
| 108 | void IsoBackendShutdown(IsoBackend** ppApp) { | ||
| 109 | assert(ppApp); | ||
| 110 | |||
| 111 | IsoBackend* app = *ppApp; | ||
| 112 | if (!app) { | ||
| 113 | return; | ||
| 114 | } | ||
| 115 | |||
| 116 | gfx_destroy(&app->gfx); | ||
| 117 | } | ||
| 118 | |||
| 119 | void IsoBackendResizeWindow( | ||
| 120 | IsoBackend* app, const IsoGfx* iso, int width, int height) { | ||
| 121 | assert(app); | ||
| 122 | assert(iso); | ||
| 123 | |||
| 124 | app->window_width = width; | ||
| 125 | app->window_height = height; | ||
| 126 | |||
| 127 | // Virtual screen dimensions. | ||
| 128 | int screen_width, screen_height; | ||
| 129 | isogfx_get_screen_size(iso, &screen_width, &screen_height); | ||
| 130 | |||
| 131 | // Stretch the virtual screen onto the viewport while respecting the screen's | ||
| 132 | // aspect ratio to prevent distortion. | ||
| 133 | if (width > height) { // Wide screen. | ||
| 134 | app->stretch = (double)height / (double)screen_height; | ||
| 135 | app->viewport_width = (int)((double)screen_width * app->stretch); | ||
| 136 | app->viewport_height = height; | ||
| 137 | app->viewport_x = (width - app->viewport_width) / 2; | ||
| 138 | app->viewport_y = 0; | ||
| 139 | } else { // Tall screen. | ||
| 140 | app->stretch = (double)width / (double)screen_width; | ||
| 141 | app->viewport_width = width; | ||
| 142 | app->viewport_height = (int)((float)screen_height * app->stretch); | ||
| 143 | app->viewport_x = 0; | ||
| 144 | app->viewport_y = (height - app->viewport_height) / 2; | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | void IsoBackendRender(const IsoBackend* app, const IsoGfx* iso) { | ||
| 149 | assert(app); | ||
| 150 | assert(iso); | ||
| 151 | |||
| 152 | const Pixel* screen = isogfx_get_screen_buffer(iso); | ||
| 153 | assert(screen); | ||
| 154 | gfx_update_texture(app->screen_texture, &(TextureDataDesc){.pixels = screen}); | ||
| 155 | |||
| 156 | GfxCore* gfxcore = gfx_get_core(app->gfx); | ||
| 157 | Renderer* renderer = gfx_get_renderer(app->gfx); | ||
| 158 | |||
| 159 | // Clear the whole window. | ||
| 160 | gfx_set_viewport(gfxcore, 0, 0, app->window_width, app->window_height); | ||
| 161 | gfx_clear(gfxcore, vec4_make(0, 0, 0, 0)); | ||
| 162 | |||
| 163 | // Draw to the subregion where the virtual screen can stretch without | ||
| 164 | // distortion. | ||
| 165 | gfx_set_viewport( | ||
| 166 | gfxcore, app->viewport_x, app->viewport_y, app->viewport_width, | ||
| 167 | app->viewport_height); | ||
| 168 | |||
| 169 | // Render the iso screen. | ||
| 170 | gfx_start_frame(gfxcore); | ||
| 171 | gfx_render_scene( | ||
| 172 | renderer, &(RenderSceneParams){ | ||
| 173 | .mode = RenderDefault, .scene = app->scene, .camera = 0}); | ||
| 174 | gfx_end_frame(gfxcore); | ||
| 175 | } | ||
| 176 | |||
| 177 | bool IsoBackendGetMousePosition( | ||
| 178 | const IsoBackend* app, double window_x, double window_y, double* x, | ||
| 179 | double* y) { | ||
| 180 | assert(app); | ||
| 181 | |||
| 182 | // Translate from window coordinates to the subregion where the stretched | ||
| 183 | // iso screen is rendered. | ||
| 184 | const double screen_x = window_x - app->viewport_x; | ||
| 185 | const double screen_y = window_y - app->viewport_y; | ||
| 186 | |||
| 187 | // Position may be out of bounds. | ||
| 188 | if ((0 <= screen_x) && (screen_x < app->viewport_width) && (0 <= screen_y) && | ||
| 189 | (screen_y < app->viewport_height)) { | ||
| 190 | // Scale back from the stretched subregion to the iso screen dimensions. | ||
| 191 | *x = screen_x / app->stretch; | ||
| 192 | *y = screen_y / app->stretch; | ||
| 193 | return true; | ||
| 194 | } else { | ||
| 195 | *x = -1; | ||
| 196 | *y = -1; | ||
| 197 | return false; | ||
| 198 | } | ||
| 199 | } | ||
diff --git a/gfx-iso/src/isogfx.c b/gfx-iso/src/isogfx.c deleted file mode 100644 index 52c4ae2..0000000 --- a/gfx-iso/src/isogfx.c +++ /dev/null | |||
| @@ -1,952 +0,0 @@ | |||
| 1 | #include <isogfx/isogfx.h> | ||
| 2 | |||
| 3 | #include <filesystem.h> | ||
| 4 | #include <mem.h> | ||
| 5 | #include <mempool.h> | ||
| 6 | #include <path.h> | ||
| 7 | |||
| 8 | #include <linux/limits.h> | ||
| 9 | |||
| 10 | #include <assert.h> | ||
| 11 | #include <stdbool.h> | ||
| 12 | #include <stdint.h> | ||
| 13 | #include <stdio.h> | ||
| 14 | #include <stdlib.h> | ||
| 15 | #include <string.h> | ||
| 16 | |||
| 17 | /// Maximum number of tiles unless the user specifies a value. | ||
| 18 | #define DEFAULT_MAX_NUM_TILES 1024 | ||
| 19 | |||
| 20 | /// Maximum number of sprites unless the user specifies a value. | ||
| 21 | #define DEFAULT_MAX_NUM_SPRITES 128 | ||
| 22 | |||
| 23 | /// Size of sprite sheet pool in bytes unless the user specifies a value. | ||
| 24 | #define DEFAULT_SPRITE_SHEET_POOL_SIZE_BYTES (8 * 1024 * 1024) | ||
| 25 | |||
| 26 | /// Default animation speed. | ||
| 27 | #define ANIMATION_FPS 10 | ||
| 28 | |||
| 29 | /// Time between animation updates. | ||
| 30 | #define ANIMATION_UPDATE_DELTA (1.0 / ANIMATION_FPS) | ||
| 31 | |||
| 32 | typedef struct ivec2 { | ||
| 33 | int x, y; | ||
| 34 | } ivec2; | ||
| 35 | |||
| 36 | typedef struct vec2 { | ||
| 37 | double x, y; | ||
| 38 | } vec2; | ||
| 39 | |||
| 40 | // ----------------------------------------------------------------------------- | ||
| 41 | // Tile set (TS) and tile map (TM) file formats. | ||
| 42 | // ----------------------------------------------------------------------------- | ||
| 43 | |||
| 44 | /// Maximum length of path strings in .TS and .TM files. | ||
| 45 | #define MAX_PATH_LENGTH 128 | ||
| 46 | |||
| 47 | typedef struct Ts_Tile { | ||
| 48 | uint16_t width; /// Tile width in pixels. | ||
| 49 | uint16_t height; /// Tile height in pixels. | ||
| 50 | Pixel pixels[1]; /// Count: width * height. | ||
| 51 | } Ts_Tile; | ||
| 52 | |||
| 53 | typedef struct Ts_TileSet { | ||
| 54 | uint16_t num_tiles; | ||
| 55 | uint16_t max_tile_width; /// Maximum tile width in pixels. | ||
| 56 | uint16_t max_tile_height; /// Maximum tile height in pixels. | ||
| 57 | Ts_Tile tiles[1]; /// Count: num_tiles. | ||
| 58 | } Ts_TileSet; | ||
| 59 | |||
| 60 | typedef struct Tm_Layer { | ||
| 61 | union { | ||
| 62 | char tileset_path[MAX_PATH_LENGTH]; // Relative to the Tm_Map file. | ||
| 63 | }; | ||
| 64 | Tile tiles[1]; /// Count: world_width * world_height. | ||
| 65 | } Tm_Layer; | ||
| 66 | |||
| 67 | typedef struct Tm_Map { | ||
| 68 | uint16_t world_width; /// World width in number of tiles. | ||
| 69 | uint16_t world_height; /// World height in number of tiles. | ||
| 70 | uint16_t base_tile_width; | ||
| 71 | uint16_t base_tile_height; | ||
| 72 | uint16_t num_layers; | ||
| 73 | Tm_Layer layers[1]; // Count: num_layers. | ||
| 74 | } Tm_Map; | ||
| 75 | |||
| 76 | static inline const Tm_Layer* tm_map_get_next_layer( | ||
| 77 | const Tm_Map* map, const Tm_Layer* layer) { | ||
| 78 | assert(map); | ||
| 79 | assert(layer); | ||
| 80 | return (const Tm_Layer*)((const uint8_t*)layer + sizeof(Tm_Layer) + | ||
| 81 | ((map->world_width * map->world_height - 1) * | ||
| 82 | sizeof(Tile))); | ||
| 83 | } | ||
| 84 | |||
| 85 | static inline const Ts_Tile* ts_tileset_get_next_tile( | ||
| 86 | const Ts_TileSet* tileset, const Ts_Tile* tile) { | ||
| 87 | assert(tileset); | ||
| 88 | assert(tile); | ||
| 89 | return (const Ts_Tile*)((const uint8_t*)tile + sizeof(Ts_Tile) + | ||
| 90 | ((tile->width * tile->height - 1) * sizeof(Pixel))); | ||
| 91 | } | ||
| 92 | |||
| 93 | // ----------------------------------------------------------------------------- | ||
| 94 | // Sprite sheet file format. | ||
| 95 | // ----------------------------------------------------------------------------- | ||
| 96 | |||
| 97 | /// A row of sprites in a sprite sheet. | ||
| 98 | /// | ||
| 99 | /// Each row in a sprite sheet can have a different number of columns. | ||
| 100 | /// | ||
| 101 | /// The pixels of the row follow a "sprite-major" order. It contains the | ||
| 102 | /// 'sprite_width * sprite_height' pixels for the first column/sprite, then the | ||
| 103 | /// second column/sprite, etc. | ||
| 104 | /// | ||
| 105 | /// Pixels are 8-bit indices into the sprite sheet's colour palette. | ||
| 106 | typedef struct Ss_Row { | ||
| 107 | uint16_t num_cols; /// Number of columns in this row. | ||
| 108 | uint8_t pixels[1]; /// Count: num_cols * sprite_width * sprite_height. | ||
| 109 | } Ss_Row; | ||
| 110 | |||
| 111 | typedef struct Ss_Palette { | ||
| 112 | uint16_t num_colours; | ||
| 113 | Pixel colours[1]; /// Count: num_colors. | ||
| 114 | } Ss_Palette; | ||
| 115 | |||
| 116 | /// Sprite sheet top-level data definition. | ||
| 117 | /// | ||
| 118 | /// Sprite width and height are assumed constant throughout the sprite sheet. | ||
| 119 | typedef struct Ss_SpriteSheet { | ||
| 120 | uint16_t sprite_width; /// Sprite width in pixels. | ||
| 121 | uint16_t sprite_height; /// Sprite height in pixels. | ||
| 122 | uint16_t num_rows; | ||
| 123 | Ss_Palette palette; /// Variable size. | ||
| 124 | Ss_Row rows[1]; /// Count: num_rows. Variable offset. | ||
| 125 | } Ss_SpriteSheet; | ||
| 126 | |||
| 127 | static inline const Ss_Row* get_sprite_sheet_row( | ||
| 128 | const Ss_SpriteSheet* sheet, int row) { | ||
| 129 | assert(sheet); | ||
| 130 | assert(row >= 0); | ||
| 131 | assert(row < sheet->num_rows); | ||
| 132 | // Skip over the palette. | ||
| 133 | const Ss_Row* rows = | ||
| 134 | (const Ss_Row*)(&sheet->palette.colours[0] + sheet->palette.num_colours); | ||
| 135 | return &rows[row]; | ||
| 136 | } | ||
| 137 | |||
| 138 | static inline const uint8_t* get_sprite_sheet_sprite( | ||
| 139 | const Ss_SpriteSheet* sheet, const Ss_Row* row, int col) { | ||
| 140 | assert(sheet); | ||
| 141 | assert(row); | ||
| 142 | assert(col >= 0); | ||
| 143 | assert(col < row->num_cols); | ||
| 144 | const int sprite_offset = col * sheet->sprite_width * sheet->sprite_height; | ||
| 145 | const uint8_t* sprite = &row->pixels[sprite_offset]; | ||
| 146 | return sprite; | ||
| 147 | } | ||
| 148 | |||
| 149 | // ----------------------------------------------------------------------------- | ||
| 150 | // Renderer state. | ||
| 151 | // ----------------------------------------------------------------------------- | ||
| 152 | |||
| 153 | typedef struct TileData { | ||
| 154 | uint16_t width; | ||
| 155 | uint16_t height; | ||
| 156 | uint16_t pixels_handle; // Handle to the tile's pixels in the pixel pool. | ||
| 157 | } TileData; | ||
| 158 | |||
| 159 | // File format is already convenient for working in memory. | ||
| 160 | typedef Ss_Row SpriteSheetRow; | ||
| 161 | typedef Ss_SpriteSheet SpriteSheetData; | ||
| 162 | |||
| 163 | typedef struct SpriteData { | ||
| 164 | SpriteSheet sheet; // Handle to the sprite's sheet. | ||
| 165 | ivec2 position; | ||
| 166 | int animation; // Current animation. | ||
| 167 | int frame; // Current frame of animation. | ||
| 168 | } SpriteData; | ||
| 169 | |||
| 170 | DEF_MEMPOOL_DYN(TilePool, TileData) | ||
| 171 | DEF_MEM_DYN(PixelPool, Pixel) | ||
| 172 | |||
| 173 | DEF_MEMPOOL_DYN(SpritePool, SpriteData) | ||
| 174 | DEF_MEM_DYN(SpriteSheetPool, SpriteSheetData) | ||
| 175 | |||
| 176 | typedef struct IsoGfx { | ||
| 177 | int screen_width; | ||
| 178 | int screen_height; | ||
| 179 | int tile_width; | ||
| 180 | int tile_height; | ||
| 181 | int world_width; | ||
| 182 | int world_height; | ||
| 183 | int max_num_sprites; | ||
| 184 | int sprite_sheet_pool_size_bytes; | ||
| 185 | double last_animation_time; | ||
| 186 | Tile* world; | ||
| 187 | Pixel* screen; | ||
| 188 | TilePool tiles; | ||
| 189 | PixelPool pixels; | ||
| 190 | SpritePool sprites; | ||
| 191 | SpriteSheetPool sheets; | ||
| 192 | } IsoGfx; | ||
| 193 | |||
| 194 | // ----------------------------------------------------------------------------- | ||
| 195 | // Math and world / tile / screen access. | ||
| 196 | // ----------------------------------------------------------------------------- | ||
| 197 | |||
| 198 | static inline ivec2 ivec2_add(ivec2 a, ivec2 b) { | ||
| 199 | return (ivec2){.x = a.x + b.x, .y = a.y + b.y}; | ||
| 200 | } | ||
| 201 | |||
| 202 | static inline ivec2 ivec2_scale(ivec2 a, int s) { | ||
| 203 | return (ivec2){.x = a.x * s, .y = a.y * s}; | ||
| 204 | } | ||
| 205 | |||
| 206 | static inline ivec2 iso2cart(ivec2 iso, int s, int t, int w) { | ||
| 207 | return (ivec2){ | ||
| 208 | .x = (iso.x - iso.y) * (s / 2) + (w / 2), .y = (iso.x + iso.y) * (t / 2)}; | ||
| 209 | } | ||
| 210 | |||
| 211 | // Method 1. | ||
| 212 | // static inline vec2 cart2iso(vec2 cart, int s, int t, int w) { | ||
| 213 | // const double x = cart.x - (double)(w / 2); | ||
| 214 | // const double xiso = (x * t + cart.y * s) / (double)(s * t); | ||
| 215 | // return (vec2){ | ||
| 216 | // .x = (int)(xiso), .y = (int)((2.0 / (double)t) * cart.y - xiso)}; | ||
| 217 | //} | ||
| 218 | |||
| 219 | // Method 2. | ||
| 220 | static inline vec2 cart2iso(vec2 cart, int s, int t, int w) { | ||
| 221 | const double one_over_s = 1. / (double)s; | ||
| 222 | const double one_over_t = 1. / (double)t; | ||
| 223 | const double x = cart.x - (double)(w / 2); | ||
| 224 | return (vec2){ | ||
| 225 | .x = (one_over_s * x + one_over_t * cart.y), | ||
| 226 | .y = (-one_over_s * x + one_over_t * cart.y)}; | ||
| 227 | } | ||
| 228 | |||
| 229 | static const Pixel* tile_xy_const_ref( | ||
| 230 | const IsoGfx* iso, const TileData* tile, int x, int y) { | ||
| 231 | assert(iso); | ||
| 232 | assert(tile); | ||
| 233 | assert(x >= 0); | ||
| 234 | assert(y >= 0); | ||
| 235 | assert(x < tile->width); | ||
| 236 | assert(y < tile->height); | ||
| 237 | return &mem_get_chunk(&iso->pixels, tile->pixels_handle)[y * tile->width + x]; | ||
| 238 | } | ||
| 239 | |||
| 240 | // static Pixel tile_xy(const IsoGfx* iso, const TileData* tile, int x, int y) { | ||
| 241 | // return *tile_xy_const_ref(iso, tile, x, y); | ||
| 242 | // } | ||
| 243 | |||
| 244 | static Pixel* tile_xy_mut(const IsoGfx* iso, TileData* tile, int x, int y) { | ||
| 245 | return (Pixel*)tile_xy_const_ref(iso, tile, x, y); | ||
| 246 | } | ||
| 247 | |||
| 248 | static inline const Tile* world_xy_const_ref(const IsoGfx* iso, int x, int y) { | ||
| 249 | assert(iso); | ||
| 250 | assert(x >= 0); | ||
| 251 | assert(y >= 0); | ||
| 252 | assert(x < iso->world_width); | ||
| 253 | assert(y < iso->world_height); | ||
| 254 | return &iso->world[y * iso->world_width + x]; | ||
| 255 | } | ||
| 256 | |||
| 257 | static inline Tile world_xy(const IsoGfx* iso, int x, int y) { | ||
| 258 | return *world_xy_const_ref(iso, x, y); | ||
| 259 | } | ||
| 260 | |||
| 261 | static inline Tile* world_xy_mut(IsoGfx* iso, int x, int y) { | ||
| 262 | return (Tile*)world_xy_const_ref(iso, x, y); | ||
| 263 | } | ||
| 264 | |||
| 265 | static inline const Pixel* screen_xy_const_ref( | ||
| 266 | const IsoGfx* iso, int x, int y) { | ||
| 267 | assert(iso); | ||
| 268 | assert(x >= 0); | ||
| 269 | assert(y >= 0); | ||
| 270 | assert(x < iso->screen_width); | ||
| 271 | assert(y < iso->screen_height); | ||
| 272 | return &iso->screen[y * iso->screen_width + x]; | ||
| 273 | } | ||
| 274 | |||
| 275 | static inline Pixel screen_xy(IsoGfx* iso, int x, int y) { | ||
| 276 | return *screen_xy_const_ref(iso, x, y); | ||
| 277 | } | ||
| 278 | |||
| 279 | static inline Pixel* screen_xy_mut(IsoGfx* iso, int x, int y) { | ||
| 280 | return (Pixel*)screen_xy_const_ref(iso, x, y); | ||
| 281 | } | ||
| 282 | |||
| 283 | static int calc_num_tile_blocks( | ||
| 284 | int base_tile_width, int base_tile_height, int tile_width, | ||
| 285 | int tile_height) { | ||
| 286 | const int base_tile_size = base_tile_width * base_tile_height; | ||
| 287 | const int tile_size = tile_width * tile_height; | ||
| 288 | const int num_blocks = tile_size / base_tile_size; | ||
| 289 | return num_blocks; | ||
| 290 | } | ||
| 291 | |||
| 292 | // ----------------------------------------------------------------------------- | ||
| 293 | // Renderer, world and tile management. | ||
| 294 | // ----------------------------------------------------------------------------- | ||
| 295 | |||
| 296 | IsoGfx* isogfx_new(const IsoGfxDesc* desc) { | ||
| 297 | assert(desc->screen_width > 0); | ||
| 298 | assert(desc->screen_height > 0); | ||
| 299 | // Part of our implementation assumes even widths and heights for precision. | ||
| 300 | assert((desc->screen_width & 1) == 0); | ||
| 301 | assert((desc->screen_height & 1) == 0); | ||
| 302 | |||
| 303 | IsoGfx* iso = calloc(1, sizeof(IsoGfx)); | ||
| 304 | if (!iso) { | ||
| 305 | return 0; | ||
| 306 | } | ||
| 307 | |||
| 308 | iso->screen_width = desc->screen_width; | ||
| 309 | iso->screen_height = desc->screen_height; | ||
| 310 | |||
| 311 | iso->last_animation_time = 0.0; | ||
| 312 | |||
| 313 | iso->max_num_sprites = desc->max_num_sprites == 0 ? DEFAULT_MAX_NUM_SPRITES | ||
| 314 | : desc->max_num_sprites; | ||
| 315 | iso->sprite_sheet_pool_size_bytes = desc->sprite_sheet_pool_size_bytes == 0 | ||
| 316 | ? DEFAULT_SPRITE_SHEET_POOL_SIZE_BYTES | ||
| 317 | : desc->sprite_sheet_pool_size_bytes; | ||
| 318 | |||
| 319 | const int screen_size = desc->screen_width * desc->screen_height; | ||
| 320 | if (!(iso->screen = calloc(screen_size, sizeof(Pixel)))) { | ||
| 321 | goto cleanup; | ||
| 322 | } | ||
| 323 | |||
| 324 | return iso; | ||
| 325 | |||
| 326 | cleanup: | ||
| 327 | isogfx_del(&iso); | ||
| 328 | return 0; | ||
| 329 | } | ||
| 330 | |||
| 331 | /// Destroy the world, its tile set, and the underlying pools. | ||
| 332 | static void destroy_world(IsoGfx* iso) { | ||
| 333 | assert(iso); | ||
| 334 | if (iso->world) { | ||
| 335 | free(iso->world); | ||
| 336 | iso->world = 0; | ||
| 337 | } | ||
| 338 | mempool_del(&iso->tiles); | ||
| 339 | mem_del(&iso->pixels); | ||
| 340 | } | ||
| 341 | |||
| 342 | /// Destroy all loaded sprites and the underlying pools. | ||
| 343 | static void destroy_sprites(IsoGfx* iso) { | ||
| 344 | assert(iso); | ||
| 345 | mempool_del(&iso->sprites); | ||
| 346 | mem_del(&iso->sheets); | ||
| 347 | } | ||
| 348 | |||
| 349 | void isogfx_del(IsoGfx** pIso) { | ||
| 350 | assert(pIso); | ||
| 351 | IsoGfx* iso = *pIso; | ||
| 352 | if (iso) { | ||
| 353 | destroy_world(iso); | ||
| 354 | destroy_sprites(iso); | ||
| 355 | if (iso->screen) { | ||
| 356 | free(iso->screen); | ||
| 357 | iso->screen = 0; | ||
| 358 | } | ||
| 359 | free(iso); | ||
| 360 | *pIso = 0; | ||
| 361 | } | ||
| 362 | } | ||
| 363 | |||
| 364 | bool isogfx_make_world(IsoGfx* iso, const WorldDesc* desc) { | ||
| 365 | assert(iso); | ||
| 366 | assert(desc); | ||
| 367 | assert(desc->tile_width > 0); | ||
| 368 | assert(desc->tile_height > 0); | ||
| 369 | // Part of our implementation assumes even widths and heights for greater | ||
| 370 | // precision. | ||
| 371 | assert((desc->tile_width & 1) == 0); | ||
| 372 | assert((desc->tile_height & 1) == 0); | ||
| 373 | |||
| 374 | // Handle recreation by destroying the previous world. | ||
| 375 | destroy_world(iso); | ||
| 376 | |||
| 377 | iso->tile_width = desc->tile_width; | ||
| 378 | iso->tile_height = desc->tile_height; | ||
| 379 | iso->world_width = desc->world_width; | ||
| 380 | iso->world_height = desc->world_height; | ||
| 381 | |||
| 382 | const int world_size = desc->world_width * desc->world_height; | ||
| 383 | const int tile_size = desc->tile_width * desc->tile_height; | ||
| 384 | const int tile_size_bytes = tile_size * (int)sizeof(Pixel); | ||
| 385 | const int tile_pool_size = | ||
| 386 | desc->max_num_tiles > 0 ? desc->max_num_tiles : DEFAULT_MAX_NUM_TILES; | ||
| 387 | |||
| 388 | if (!(iso->world = calloc(world_size, sizeof(Tile)))) { | ||
| 389 | goto cleanup; | ||
| 390 | } | ||
| 391 | if (!mempool_make_dyn(&iso->tiles, world_size, sizeof(TileData))) { | ||
| 392 | goto cleanup; | ||
| 393 | } | ||
| 394 | if (!mem_make_dyn(&iso->pixels, tile_pool_size, tile_size_bytes)) { | ||
| 395 | goto cleanup; | ||
| 396 | } | ||
| 397 | |||
| 398 | return true; | ||
| 399 | |||
| 400 | cleanup: | ||
| 401 | destroy_world(iso); | ||
| 402 | return false; | ||
| 403 | } | ||
| 404 | |||
| 405 | bool isogfx_load_world(IsoGfx* iso, const char* filepath) { | ||
| 406 | assert(iso); | ||
| 407 | assert(filepath); | ||
| 408 | |||
| 409 | bool success = false; | ||
| 410 | |||
| 411 | // Handle recreation by destroying the previous world. | ||
| 412 | destroy_world(iso); | ||
| 413 | |||
| 414 | // Load the map. | ||
| 415 | printf("Load tile map: %s\n", filepath); | ||
| 416 | Tm_Map* map = read_file(filepath); | ||
| 417 | if (!map) { | ||
| 418 | goto cleanup; | ||
| 419 | } | ||
| 420 | |||
| 421 | // Allocate memory for the map and tile sets. | ||
| 422 | const int world_size = map->world_width * map->world_height; | ||
| 423 | const int base_tile_size = map->base_tile_width * map->base_tile_height; | ||
| 424 | const int base_tile_size_bytes = base_tile_size * (int)sizeof(Pixel); | ||
| 425 | // TODO: Need to get the total number of tiles from the map. | ||
| 426 | const int tile_pool_size = DEFAULT_MAX_NUM_TILES; | ||
| 427 | |||
| 428 | if (!(iso->world = calloc(world_size, sizeof(Tile)))) { | ||
| 429 | goto cleanup; | ||
| 430 | } | ||
| 431 | if (!mempool_make_dyn(&iso->tiles, tile_pool_size, sizeof(TileData))) { | ||
| 432 | goto cleanup; | ||
| 433 | } | ||
| 434 | if (!mem_make_dyn(&iso->pixels, tile_pool_size, base_tile_size_bytes)) { | ||
| 435 | goto cleanup; | ||
| 436 | } | ||
| 437 | |||
| 438 | // Load the tile sets. | ||
| 439 | const Tm_Layer* layer = &map->layers[0]; | ||
| 440 | // TODO: Handle num_layers layers. | ||
| 441 | for (int i = 0; i < 1; ++i) { | ||
| 442 | const char* ts_path = layer->tileset_path; | ||
| 443 | |||
| 444 | // Tile set path is relative to the tile map file. Make it relative to the | ||
| 445 | // current working directory before loading. | ||
| 446 | char ts_path_cwd[PATH_MAX] = {0}; | ||
| 447 | if (!path_make_relative(filepath, ts_path, ts_path_cwd, PATH_MAX)) { | ||
| 448 | goto cleanup; | ||
| 449 | } | ||
| 450 | |||
| 451 | Ts_TileSet* tileset = read_file(ts_path_cwd); | ||
| 452 | if (!tileset) { | ||
| 453 | goto cleanup; | ||
| 454 | }; | ||
| 455 | |||
| 456 | // Load tile data. | ||
| 457 | const Ts_Tile* tile = &tileset->tiles[0]; | ||
| 458 | for (uint16_t j = 0; j < tileset->num_tiles; ++j) { | ||
| 459 | // Tile dimensions should be a multiple of the base tile size. | ||
| 460 | assert((tile->width % map->base_tile_width) == 0); | ||
| 461 | assert((tile->height % map->base_tile_height) == 0); | ||
| 462 | |||
| 463 | // Allocate N base tile size blocks for the tile. | ||
| 464 | const uint16_t tile_size = tile->width * tile->height; | ||
| 465 | const int num_blocks = tile_size / base_tile_size; | ||
| 466 | Pixel* pixels = mem_alloc(&iso->pixels, num_blocks); | ||
| 467 | assert(pixels); | ||
| 468 | memcpy(pixels, tile->pixels, tile_size * sizeof(Pixel)); | ||
| 469 | |||
| 470 | // Allocate the tile data. | ||
| 471 | TileData* tile_data = mempool_alloc(&iso->tiles); | ||
| 472 | assert(tile_data); | ||
| 473 | tile_data->width = tile->width; | ||
| 474 | tile_data->height = tile->height; | ||
| 475 | tile_data->pixels_handle = | ||
| 476 | (uint16_t)mem_get_chunk_handle(&iso->pixels, pixels); | ||
| 477 | |||
| 478 | tile = ts_tileset_get_next_tile(tileset, tile); | ||
| 479 | } | ||
| 480 | |||
| 481 | printf("Loaded tile set (%u tiles): %s\n", tileset->num_tiles, ts_path_cwd); | ||
| 482 | |||
| 483 | free(tileset); | ||
| 484 | layer = tm_map_get_next_layer(map, layer); | ||
| 485 | } | ||
| 486 | |||
| 487 | // Load the map into the world. | ||
| 488 | layer = &map->layers[0]; | ||
| 489 | // TODO: Handle num_layers layers. | ||
| 490 | for (int i = 0; i < 1; ++i) { | ||
| 491 | memcpy(iso->world, layer->tiles, world_size * sizeof(Tile)); | ||
| 492 | |||
| 493 | // TODO: We need to handle 'firsgid' in TMX files. | ||
| 494 | for (int j = 0; j < world_size; ++j) { | ||
| 495 | iso->world[j] -= 1; | ||
| 496 | } | ||
| 497 | |||
| 498 | layer = tm_map_get_next_layer(map, layer); | ||
| 499 | } | ||
| 500 | |||
| 501 | iso->world_width = map->world_width; | ||
| 502 | iso->world_height = map->world_height; | ||
| 503 | iso->tile_width = map->base_tile_width; | ||
| 504 | iso->tile_height = map->base_tile_height; | ||
| 505 | |||
| 506 | success = true; | ||
| 507 | |||
| 508 | cleanup: | ||
| 509 | if (map) { | ||
| 510 | free(map); | ||
| 511 | } | ||
| 512 | if (!success) { | ||
| 513 | destroy_world(iso); | ||
| 514 | } | ||
| 515 | return success; | ||
| 516 | } | ||
| 517 | |||
| 518 | int isogfx_world_width(const IsoGfx* iso) { | ||
| 519 | assert(iso); | ||
| 520 | return iso->world_width; | ||
| 521 | } | ||
| 522 | |||
| 523 | int isogfx_world_height(const IsoGfx* iso) { | ||
| 524 | assert(iso); | ||
| 525 | return iso->world_height; | ||
| 526 | } | ||
| 527 | |||
| 528 | /// Create a tile mask procedurally. | ||
| 529 | static void make_tile_from_colour( | ||
| 530 | const IsoGfx* iso, Pixel colour, TileData* tile) { | ||
| 531 | assert(iso); | ||
| 532 | assert(tile); | ||
| 533 | |||
| 534 | const int width = tile->width; | ||
| 535 | const int height = tile->height; | ||
| 536 | const int r = width / height; | ||
| 537 | |||
| 538 | for (int y = 0; y < height / 2; ++y) { | ||
| 539 | const int mask_start = width / 2 - r * y - 1; | ||
| 540 | const int mask_end = width / 2 + r * y + 1; | ||
| 541 | for (int x = 0; x < width; ++x) { | ||
| 542 | const bool mask = (mask_start <= x) && (x <= mask_end); | ||
| 543 | const Pixel val = mask ? colour : (Pixel){.r = 0, .g = 0, .b = 0, .a = 0}; | ||
| 544 | |||
| 545 | // Top half. | ||
| 546 | *tile_xy_mut(iso, tile, x, y) = val; | ||
| 547 | |||
| 548 | // Bottom half reflects the top half. | ||
| 549 | const int y_reflected = height - y - 1; | ||
| 550 | *tile_xy_mut(iso, tile, x, y_reflected) = val; | ||
| 551 | } | ||
| 552 | } | ||
| 553 | } | ||
| 554 | |||
| 555 | Tile isogfx_make_tile(IsoGfx* iso, const TileDesc* desc) { | ||
| 556 | assert(iso); | ||
| 557 | assert(desc); | ||
| 558 | // Client must create world before creating tiles. | ||
| 559 | assert(iso->tile_width > 0); | ||
| 560 | assert(iso->tile_height > 0); | ||
| 561 | |||
| 562 | TileData* tile = mempool_alloc(&iso->tiles); | ||
| 563 | assert(tile); // TODO: Make this a hard assert. | ||
| 564 | |||
| 565 | const int num_blocks = calc_num_tile_blocks( | ||
| 566 | iso->tile_width, iso->tile_height, desc->width, desc->height); | ||
| 567 | |||
| 568 | Pixel* pixels = mem_alloc(&iso->pixels, num_blocks); | ||
| 569 | assert(pixels); // TODO: Make this a hard assert. | ||
| 570 | |||
| 571 | tile->width = desc->width; | ||
| 572 | tile->height = desc->height; | ||
| 573 | tile->pixels_handle = mem_get_chunk_handle(&iso->pixels, pixels); | ||
| 574 | |||
| 575 | switch (desc->type) { | ||
| 576 | case TileFromColour: | ||
| 577 | make_tile_from_colour(iso, desc->colour, tile); | ||
| 578 | break; | ||
| 579 | case TileFromFile: | ||
| 580 | assert(false); // TODO | ||
| 581 | break; | ||
| 582 | case TileFromMemory: | ||
| 583 | assert(false); // TODO | ||
| 584 | break; | ||
| 585 | } | ||
| 586 | |||
| 587 | return (Tile)mempool_get_block_index(&iso->tiles, tile); | ||
| 588 | } | ||
| 589 | |||
| 590 | void isogfx_set_tile(IsoGfx* iso, int x, int y, Tile tile) { | ||
| 591 | assert(iso); | ||
| 592 | *world_xy_mut(iso, x, y) = tile; | ||
| 593 | } | ||
| 594 | |||
| 595 | void isogfx_set_tiles(IsoGfx* iso, int x0, int y0, int x1, int y1, Tile tile) { | ||
| 596 | assert(iso); | ||
| 597 | for (int y = y0; y < y1; ++y) { | ||
| 598 | for (int x = x0; x < x1; ++x) { | ||
| 599 | isogfx_set_tile(iso, x, y, tile); | ||
| 600 | } | ||
| 601 | } | ||
| 602 | } | ||
| 603 | |||
| 604 | bool isogfx_load_sprite_sheet( | ||
| 605 | IsoGfx* iso, const char* filepath, SpriteSheet* p_sheet) { | ||
| 606 | assert(iso); | ||
| 607 | assert(filepath); | ||
| 608 | assert(p_sheet); | ||
| 609 | |||
| 610 | bool success = false; | ||
| 611 | |||
| 612 | // Lazy initialization of sprite pools. | ||
| 613 | if (mempool_capacity(&iso->sprites) == 0) { | ||
| 614 | if (!mempool_make_dyn( | ||
| 615 | &iso->sprites, iso->max_num_sprites, sizeof(SpriteData))) { | ||
| 616 | return false; | ||
| 617 | } | ||
| 618 | } | ||
| 619 | if (mem_capacity(&iso->sheets) == 0) { | ||
| 620 | // Using a block size of 1 byte for sprite sheet data. | ||
| 621 | if (!mem_make_dyn(&iso->sheets, iso->sprite_sheet_pool_size_bytes, 1)) { | ||
| 622 | return false; | ||
| 623 | } | ||
| 624 | } | ||
| 625 | |||
| 626 | // Load sprite sheet file. | ||
| 627 | printf("Load sprite sheet: %s\n", filepath); | ||
| 628 | FILE* file = fopen(filepath, "rb"); | ||
| 629 | if (file == NULL) { | ||
| 630 | goto cleanup; | ||
| 631 | } | ||
| 632 | const size_t sheet_size = get_file_size(file); | ||
| 633 | SpriteSheetData* ss_sheet = mem_alloc(&iso->sheets, sheet_size); | ||
| 634 | if (!ss_sheet) { | ||
| 635 | goto cleanup; | ||
| 636 | } | ||
| 637 | if (fread(ss_sheet, sheet_size, 1, file) != 1) { | ||
| 638 | goto cleanup; | ||
| 639 | } | ||
| 640 | |||
| 641 | *p_sheet = mem_get_chunk_handle(&iso->sheets, ss_sheet); | ||
| 642 | success = true; | ||
| 643 | |||
| 644 | cleanup: | ||
| 645 | // Pools remain initialized since client may attempt to load other sprites. | ||
| 646 | if (file != NULL) { | ||
| 647 | fclose(file); | ||
| 648 | } | ||
| 649 | if (!success) { | ||
| 650 | if (ss_sheet) { | ||
| 651 | mem_free(&iso->sheets, &ss_sheet); | ||
| 652 | } | ||
| 653 | } | ||
| 654 | return success; | ||
| 655 | } | ||
| 656 | |||
| 657 | Sprite isogfx_make_sprite(IsoGfx* iso, SpriteSheet sheet) { | ||
| 658 | assert(iso); | ||
| 659 | |||
| 660 | SpriteData* sprite = mempool_alloc(&iso->sprites); | ||
| 661 | assert(sprite); | ||
| 662 | |||
| 663 | sprite->sheet = sheet; | ||
| 664 | |||
| 665 | return mempool_get_block_index(&iso->sprites, sprite); | ||
| 666 | } | ||
| 667 | |||
| 668 | #define with_sprite(SPRITE, BODY) \ | ||
| 669 | { \ | ||
| 670 | SpriteData* data = mempool_get_block(&iso->sprites, sprite); \ | ||
| 671 | assert(data); \ | ||
| 672 | BODY; \ | ||
| 673 | } | ||
| 674 | |||
| 675 | void isogfx_set_sprite_position(IsoGfx* iso, Sprite sprite, int x, int y) { | ||
| 676 | assert(iso); | ||
| 677 | with_sprite(sprite, { | ||
| 678 | data->position.x = x; | ||
| 679 | data->position.y = y; | ||
| 680 | }); | ||
| 681 | } | ||
| 682 | |||
| 683 | void isogfx_set_sprite_animation(IsoGfx* iso, Sprite sprite, int animation) { | ||
| 684 | assert(iso); | ||
| 685 | with_sprite(sprite, { data->animation = animation; }); | ||
| 686 | } | ||
| 687 | |||
| 688 | void isogfx_update(IsoGfx* iso, double t) { | ||
| 689 | assert(iso); | ||
| 690 | |||
| 691 | // If this is the first time update() is called after initialization, just | ||
| 692 | // record the starting animation time. | ||
| 693 | if (iso->last_animation_time == 0.0) { | ||
| 694 | iso->last_animation_time = t; | ||
| 695 | return; | ||
| 696 | } | ||
| 697 | |||
| 698 | if ((t - iso->last_animation_time) >= ANIMATION_UPDATE_DELTA) { | ||
| 699 | // TODO: Consider linking animated sprites in a list so that we only walk | ||
| 700 | // over those here and not also the static sprites. | ||
| 701 | mempool_foreach(&iso->sprites, sprite, { | ||
| 702 | const SpriteSheetData* sheet = mem_get_chunk(&iso->sheets, sprite->sheet); | ||
| 703 | assert(sheet); // TODO: Make this a hard assert inside the mem/pool. | ||
| 704 | const SpriteSheetRow* row = | ||
| 705 | get_sprite_sheet_row(sheet, sprite->animation); | ||
| 706 | sprite->frame = (sprite->frame + 1) % row->num_cols; | ||
| 707 | }); | ||
| 708 | |||
| 709 | iso->last_animation_time = t; | ||
| 710 | } | ||
| 711 | } | ||
| 712 | |||
| 713 | // ----------------------------------------------------------------------------- | ||
| 714 | // Rendering and picking. | ||
| 715 | // ----------------------------------------------------------------------------- | ||
| 716 | |||
| 717 | typedef struct CoordSystem { | ||
| 718 | ivec2 o; /// Origin. | ||
| 719 | ivec2 x; | ||
| 720 | ivec2 y; | ||
| 721 | } CoordSystem; | ||
| 722 | |||
| 723 | /// Create the basis for the isometric coordinate system with origin and vectors | ||
| 724 | /// expressed in the Cartesian system. | ||
| 725 | static CoordSystem make_iso_coord_system(const IsoGfx* iso) { | ||
| 726 | assert(iso); | ||
| 727 | const ivec2 o = {iso->screen_width / 2, 0}; | ||
| 728 | const ivec2 x = {.x = iso->tile_width / 2, .y = iso->tile_height / 2}; | ||
| 729 | const ivec2 y = {.x = -iso->tile_width / 2, .y = iso->tile_height / 2}; | ||
| 730 | return (CoordSystem){o, x, y}; | ||
| 731 | } | ||
| 732 | |||
| 733 | /// Get the screen position of the top diamond-corner of the tile at world | ||
| 734 | /// (x,y). | ||
| 735 | static ivec2 GetTileScreenOrigin( | ||
| 736 | const CoordSystem iso_space, int world_x, int world_y) { | ||
| 737 | const ivec2 vx_offset = ivec2_scale(iso_space.x, world_x); | ||
| 738 | const ivec2 vy_offset = ivec2_scale(iso_space.y, world_y); | ||
| 739 | const ivec2 screen_origin = | ||
| 740 | ivec2_add(iso_space.o, ivec2_add(vx_offset, vy_offset)); | ||
| 741 | |||
| 742 | return screen_origin; | ||
| 743 | } | ||
| 744 | |||
| 745 | static Pixel alpha_blend(Pixel src, Pixel dst) { | ||
| 746 | if ((src.a == 255) || (dst.a == 0)) { | ||
| 747 | return src; | ||
| 748 | } | ||
| 749 | const uint16_t one_minus_alpha = 255 - src.a; | ||
| 750 | #define blend(s, d) \ | ||
| 751 | (Channel)( \ | ||
| 752 | (double)((uint16_t)s * (uint16_t)src.a + \ | ||
| 753 | (uint16_t)d * one_minus_alpha) / \ | ||
| 754 | 255.0) | ||
| 755 | return (Pixel){ | ||
| 756 | .r = blend(src.r, dst.r), | ||
| 757 | .g = blend(src.g, dst.g), | ||
| 758 | .b = blend(src.b, dst.b), | ||
| 759 | .a = src.a}; | ||
| 760 | } | ||
| 761 | |||
| 762 | /// Draw a rectangle (tile or sprite). | ||
| 763 | /// | ||
| 764 | /// The rectangle's top-left corner is mapped to the screen space position given | ||
| 765 | /// by 'top_left'. | ||
| 766 | /// | ||
| 767 | /// The rectangle's pixels are assumed to be arranged in a linear, row-major | ||
| 768 | /// fashion. | ||
| 769 | /// | ||
| 770 | /// If indices are given, then the image is assumed to be colour-paletted, where | ||
| 771 | /// 'pixels' is the palette and 'indices' the pixel indices. Otherwise, the | ||
| 772 | /// image is assumed to be in plain RGBA format. | ||
| 773 | static void draw_rect( | ||
| 774 | IsoGfx* iso, ivec2 top_left, int rect_width, int rect_height, | ||
| 775 | const Pixel* pixels, const uint8_t* indices) { | ||
| 776 | assert(iso); | ||
| 777 | |||
| 778 | #define rect_pixel(X, Y) \ | ||
| 779 | (indices ? pixels[indices[Y * rect_width + X]] : pixels[Y * rect_width + X]) | ||
| 780 | |||
| 781 | // Rect origin can be outside screen bounds, so we must offset accordingly to | ||
| 782 | // draw only the visible portion. | ||
| 783 | #define max(a, b) (a > b ? a : b) | ||
| 784 | const int px_offset = max(0, -top_left.x); | ||
| 785 | const int py_offset = max(0, -top_left.y); | ||
| 786 | |||
| 787 | // Rect can exceed screen bounds, so clip along Y and X as we draw. | ||
| 788 | for (int py = py_offset; | ||
| 789 | (py < rect_height) && (top_left.y + py < iso->screen_height); ++py) { | ||
| 790 | const int sy = top_left.y + py; | ||
| 791 | for (int px = px_offset; | ||
| 792 | (px < rect_width) && (top_left.x + px < iso->screen_width); ++px) { | ||
| 793 | const Pixel colour = rect_pixel(px, py); | ||
| 794 | if (colour.a > 0) { | ||
| 795 | const int sx = top_left.x + px; | ||
| 796 | const Pixel dst = screen_xy(iso, sx, sy); | ||
| 797 | const Pixel final = alpha_blend(colour, dst); | ||
| 798 | *screen_xy_mut(iso, sx, sy) = final; | ||
| 799 | } | ||
| 800 | } | ||
| 801 | } | ||
| 802 | } | ||
| 803 | |||
| 804 | /// Draw a tile. | ||
| 805 | /// | ||
| 806 | /// 'screen_origin' is the screen coordinates of the top diamond-corner of the | ||
| 807 | /// tile (the base tile for super tiles). | ||
| 808 | /// World (0, 0) -> (screen_width / 2, 0). | ||
| 809 | static void draw_tile(IsoGfx* iso, ivec2 screen_origin, Tile tile) { | ||
| 810 | assert(iso); | ||
| 811 | |||
| 812 | const TileData* tile_data = mempool_get_block(&iso->tiles, tile); | ||
| 813 | assert(tile_data); | ||
| 814 | const Pixel* pixels = tile_xy_const_ref(iso, tile_data, 0, 0); | ||
| 815 | |||
| 816 | // Move from the top diamond-corner to the top-left corner of the tile image. | ||
| 817 | // For regular tiles, tile height == base tile height, so the y offset is 0. | ||
| 818 | // For super tiles, move as high up as the height of the tile. | ||
| 819 | const ivec2 offset = { | ||
| 820 | -(iso->tile_width / 2), tile_data->height - iso->tile_height}; | ||
| 821 | const ivec2 top_left = ivec2_add(screen_origin, offset); | ||
| 822 | |||
| 823 | draw_rect(iso, top_left, tile_data->width, tile_data->height, pixels, 0); | ||
| 824 | } | ||
| 825 | |||
| 826 | static void draw_world(IsoGfx* iso) { | ||
| 827 | assert(iso); | ||
| 828 | |||
| 829 | const int W = iso->screen_width; | ||
| 830 | const int H = iso->screen_height; | ||
| 831 | |||
| 832 | memset(iso->screen, 0, W * H * sizeof(Pixel)); | ||
| 833 | |||
| 834 | const CoordSystem iso_space = make_iso_coord_system(iso); | ||
| 835 | |||
| 836 | // TODO: Culling. | ||
| 837 | // Ex: map the screen corners to tile space to cull. | ||
| 838 | // Ex: walk in screen space and fetch the tile. | ||
| 839 | // The tile-centric approach might be more cache-friendly since the | ||
| 840 | // screen-centric approach would juggle multiple tiles throughout the scan. | ||
| 841 | for (int wy = 0; wy < iso->world_height; ++wy) { | ||
| 842 | for (int wx = 0; wx < iso->world_width; ++wx) { | ||
| 843 | const Tile tile = world_xy(iso, wx, wy); | ||
| 844 | const ivec2 screen_origin = GetTileScreenOrigin(iso_space, wx, wy); | ||
| 845 | draw_tile(iso, screen_origin, tile); | ||
| 846 | } | ||
| 847 | } | ||
| 848 | } | ||
| 849 | |||
| 850 | static void draw_sprite( | ||
| 851 | IsoGfx* iso, ivec2 origin, const SpriteData* sprite, | ||
| 852 | const SpriteSheetData* sheet) { | ||
| 853 | assert(iso); | ||
| 854 | assert(sprite); | ||
| 855 | assert(sheet); | ||
| 856 | assert(sprite->animation >= 0); | ||
| 857 | assert(sprite->animation < sheet->num_rows); | ||
| 858 | assert(sprite->frame >= 0); | ||
| 859 | |||
| 860 | const SpriteSheetRow* row = get_sprite_sheet_row(sheet, sprite->animation); | ||
| 861 | const uint8_t* frame = get_sprite_sheet_sprite(sheet, row, sprite->frame); | ||
| 862 | draw_rect( | ||
| 863 | iso, origin, sheet->sprite_width, sheet->sprite_height, | ||
| 864 | sheet->palette.colours, frame); | ||
| 865 | } | ||
| 866 | |||
| 867 | static void draw_sprites(IsoGfx* iso) { | ||
| 868 | assert(iso); | ||
| 869 | |||
| 870 | const CoordSystem iso_space = make_iso_coord_system(iso); | ||
| 871 | |||
| 872 | mempool_foreach(&iso->sprites, sprite, { | ||
| 873 | const SpriteSheetData* sheet = mem_get_chunk(&iso->sheets, sprite->sheet); | ||
| 874 | assert(sheet); | ||
| 875 | |||
| 876 | const ivec2 screen_origin = | ||
| 877 | GetTileScreenOrigin(iso_space, sprite->position.x, sprite->position.y); | ||
| 878 | draw_sprite(iso, screen_origin, sprite, sheet); | ||
| 879 | }); | ||
| 880 | } | ||
| 881 | |||
| 882 | void isogfx_render(IsoGfx* iso) { | ||
| 883 | assert(iso); | ||
| 884 | draw_world(iso); | ||
| 885 | draw_sprites(iso); | ||
| 886 | } | ||
| 887 | |||
| 888 | void isogfx_draw_tile(IsoGfx* iso, int x, int y, Tile tile) { | ||
| 889 | assert(iso); | ||
| 890 | assert(x >= 0); | ||
| 891 | assert(y >= 0); | ||
| 892 | assert(x < iso->world_width); | ||
| 893 | assert(y < iso->world_height); | ||
| 894 | |||
| 895 | const CoordSystem iso_space = make_iso_coord_system(iso); | ||
| 896 | const ivec2 screen_origin = GetTileScreenOrigin(iso_space, x, y); | ||
| 897 | draw_tile(iso, screen_origin, tile); | ||
| 898 | } | ||
| 899 | |||
| 900 | bool isogfx_resize(IsoGfx* iso, int screen_width, int screen_height) { | ||
| 901 | assert(iso); | ||
| 902 | assert(iso->screen); | ||
| 903 | |||
| 904 | const int current_size = iso->screen_width * iso->screen_height; | ||
| 905 | const int new_size = screen_width * screen_height; | ||
| 906 | |||
| 907 | if (new_size > current_size) { | ||
| 908 | Pixel* new_screen = calloc(new_size, sizeof(Pixel)); | ||
| 909 | if (new_screen) { | ||
| 910 | free(iso->screen); | ||
| 911 | iso->screen = new_screen; | ||
| 912 | } else { | ||
| 913 | return false; | ||
| 914 | } | ||
| 915 | } | ||
| 916 | iso->screen_width = screen_width; | ||
| 917 | iso->screen_height = screen_height; | ||
| 918 | return true; | ||
| 919 | } | ||
| 920 | |||
| 921 | void isogfx_get_screen_size(const IsoGfx* iso, int* width, int* height) { | ||
| 922 | assert(iso); | ||
| 923 | assert(width); | ||
| 924 | assert(height); | ||
| 925 | *width = iso->screen_width; | ||
| 926 | *height = iso->screen_height; | ||
| 927 | } | ||
| 928 | |||
| 929 | const Pixel* isogfx_get_screen_buffer(const IsoGfx* iso) { | ||
| 930 | assert(iso); | ||
| 931 | return iso->screen; | ||
| 932 | } | ||
| 933 | |||
| 934 | void isogfx_pick_tile( | ||
| 935 | const IsoGfx* iso, double xcart, double ycart, int* xiso, int* yiso) { | ||
| 936 | assert(iso); | ||
| 937 | assert(xiso); | ||
| 938 | assert(yiso); | ||
| 939 | |||
| 940 | const vec2 xy_iso = cart2iso( | ||
| 941 | (vec2){.x = xcart, .y = ycart}, iso->tile_width, iso->tile_height, | ||
| 942 | iso->screen_width); | ||
| 943 | |||
| 944 | if ((0 <= xy_iso.x) && (xy_iso.x < iso->world_width) && (0 <= xy_iso.y) && | ||
| 945 | (xy_iso.y < iso->world_height)) { | ||
| 946 | *xiso = (int)xy_iso.x; | ||
| 947 | *yiso = (int)xy_iso.y; | ||
| 948 | } else { | ||
| 949 | *xiso = -1; | ||
| 950 | *yiso = -1; | ||
| 951 | } | ||
| 952 | } | ||
diff --git a/gfx-iso/tools/mkasset.py b/gfx-iso/tools/mkasset.py deleted file mode 100644 index 3ca8a1d..0000000 --- a/gfx-iso/tools/mkasset.py +++ /dev/null | |||
| @@ -1,324 +0,0 @@ | |||
| 1 | # Converts assets to binary formats (.ts, .tm, .ss) for the engine. | ||
| 2 | # | ||
| 3 | # Input file formats: | ||
| 4 | # - Tiled tile set (.tsx) | ||
| 5 | # - Tiled tile map (.tmx) | ||
| 6 | # - Sprite sheets (.jpg, .png, etc), 1 row per animation. | ||
| 7 | # | ||
| 8 | # Output file formats: | ||
| 9 | # - Binary tile set file (.ts) | ||
| 10 | # - Binary tile map file (.tm) | ||
| 11 | # - Binary sprite sheet file (.ss) | ||
| 12 | # | ||
| 13 | import argparse | ||
| 14 | import ctypes | ||
| 15 | import os | ||
| 16 | from PIL import Image | ||
| 17 | import sys | ||
| 18 | from xml.etree import ElementTree | ||
| 19 | |||
| 20 | # Maximum length of path strings in .TS and .TM files. | ||
| 21 | # Must match the engine's value. | ||
| 22 | MAX_PATH_LENGTH = 128 | ||
| 23 | |||
| 24 | |||
| 25 | def drop_extension(filepath): | ||
| 26 | return filepath[:filepath.rfind('.')] | ||
| 27 | |||
| 28 | |||
| 29 | def to_char_array(string, length): | ||
| 30 | """Convert a string to a fixed-length ASCII char array. | ||
| 31 | |||
| 32 | The length of str must be at most length-1 so that the resulting string can | ||
| 33 | be null-terminated. | ||
| 34 | """ | ||
| 35 | assert (len(string) < length) | ||
| 36 | chars = string.encode("ascii") | ||
| 37 | nulls = ("\0" * (length - len(string))).encode("ascii") | ||
| 38 | return chars + nulls | ||
| 39 | |||
| 40 | |||
| 41 | def convert_tsx(input_filepath, output_filepath): | ||
| 42 | """Converts a Tiled .tsx tileset file to a .TS tile set file.""" | ||
| 43 | xml = ElementTree.parse(input_filepath) | ||
| 44 | root = xml.getroot() | ||
| 45 | |||
| 46 | tile_count = int(root.attrib["tilecount"]) | ||
| 47 | max_tile_width = int(root.attrib["tilewidth"]) | ||
| 48 | max_tile_height = int(root.attrib["tileheight"]) | ||
| 49 | |||
| 50 | print(f"Tile count: {tile_count}") | ||
| 51 | print(f"Max width: {max_tile_width}") | ||
| 52 | print(f"Max height: {max_tile_height}") | ||
| 53 | |||
| 54 | with open(output_filepath, 'bw') as output: | ||
| 55 | output.write(ctypes.c_uint16(tile_count)) | ||
| 56 | output.write(ctypes.c_uint16(max_tile_width)) | ||
| 57 | output.write(ctypes.c_uint16(max_tile_height)) | ||
| 58 | |||
| 59 | num_tile = 0 | ||
| 60 | for tile in root: | ||
| 61 | # Skip the "grid" and other non-tile elements. | ||
| 62 | if not tile.tag == "tile": | ||
| 63 | continue | ||
| 64 | |||
| 65 | # Assuming tiles are numbered 0..N. | ||
| 66 | tile_id = int(tile.attrib["id"]) | ||
| 67 | assert (tile_id == num_tile) | ||
| 68 | num_tile += 1 | ||
| 69 | |||
| 70 | image = tile[0] | ||
| 71 | tile_width = int(image.attrib["width"]) | ||
| 72 | tile_height = int(image.attrib["height"]) | ||
| 73 | tile_path = image.attrib["source"] | ||
| 74 | |||
| 75 | output.write(ctypes.c_uint16(tile_width)) | ||
| 76 | output.write(ctypes.c_uint16(tile_height)) | ||
| 77 | |||
| 78 | with Image.open(tile_path) as im: | ||
| 79 | bytes = im.convert('RGBA').tobytes() | ||
| 80 | output.write(bytes) | ||
| 81 | |||
| 82 | |||
| 83 | def convert_tmx(input_filepath, output_filepath): | ||
| 84 | """Converts a Tiled .tmx file to a .TM tile map file.""" | ||
| 85 | xml = ElementTree.parse(input_filepath) | ||
| 86 | root = xml.getroot() | ||
| 87 | |||
| 88 | map_width = int(root.attrib["width"]) | ||
| 89 | map_height = int(root.attrib["height"]) | ||
| 90 | base_tile_width = int(root.attrib["tilewidth"]) | ||
| 91 | base_tile_height = int(root.attrib["tileheight"]) | ||
| 92 | num_layers = 1 | ||
| 93 | |||
| 94 | print(f"Map width: {map_width}") | ||
| 95 | print(f"Map height: {map_height}") | ||
| 96 | print(f"Tile width: {base_tile_width}") | ||
| 97 | print(f"Tile height: {base_tile_height}") | ||
| 98 | |||
| 99 | with open(output_filepath, 'bw') as output: | ||
| 100 | output.write(ctypes.c_uint16(map_width)) | ||
| 101 | output.write(ctypes.c_uint16(map_height)) | ||
| 102 | output.write(ctypes.c_uint16(base_tile_width)) | ||
| 103 | output.write(ctypes.c_uint16(base_tile_height)) | ||
| 104 | output.write(ctypes.c_uint16(num_layers)) | ||
| 105 | |||
| 106 | tileset_path = None | ||
| 107 | |||
| 108 | for child in root: | ||
| 109 | if child.tag == "tileset": | ||
| 110 | tileset = child | ||
| 111 | tileset_path = tileset.attrib["source"] | ||
| 112 | |||
| 113 | print(f"Tile set: {tileset_path}") | ||
| 114 | |||
| 115 | tileset_path = tileset_path.replace("tsx", "ts") | ||
| 116 | elif child.tag == "layer": | ||
| 117 | layer = child | ||
| 118 | layer_id = int(layer.attrib["id"]) | ||
| 119 | layer_width = int(layer.attrib["width"]) | ||
| 120 | layer_height = int(layer.attrib["height"]) | ||
| 121 | |||
| 122 | print(f"Layer: {layer_id}") | ||
| 123 | print(f"Width: {layer_width}") | ||
| 124 | print(f"Height: {layer_height}") | ||
| 125 | |||
| 126 | assert (tileset_path) | ||
| 127 | output.write(to_char_array(tileset_path, MAX_PATH_LENGTH)) | ||
| 128 | |||
| 129 | # Assume the layer's dimensions matches the map's. | ||
| 130 | assert (layer_width == map_width) | ||
| 131 | assert (layer_height == map_height) | ||
| 132 | |||
| 133 | data = layer[0] | ||
| 134 | # Handle other encodings later. | ||
| 135 | assert (data.attrib["encoding"] == "csv") | ||
| 136 | |||
| 137 | csv = data.text.strip() | ||
| 138 | rows = csv.split('\n') | ||
| 139 | for row in rows: | ||
| 140 | tile_ids = [x.strip() for x in row.split(',') if x] | ||
| 141 | for tile_id in tile_ids: | ||
| 142 | output.write(ctypes.c_uint16(int(tile_id))) | ||
| 143 | |||
| 144 | |||
| 145 | def get_num_cols(image, sprite_width): | ||
| 146 | """Return the number of non-empty columns in the image. | ||
| 147 | |||
| 148 | Assumes no gaps in the columns. | ||
| 149 | """ | ||
| 150 | assert (image.width % sprite_width == 0) | ||
| 151 | num_cols = image.width // sprite_width | ||
| 152 | |||
| 153 | # Start the search from right to left. | ||
| 154 | for col in reversed(range(1, num_cols)): | ||
| 155 | left = (col - 1) * sprite_width | ||
| 156 | right = col * sprite_width | ||
| 157 | rect = image.crop((left, 0, right, image.height)) | ||
| 158 | min_max = rect.getextrema() | ||
| 159 | for (channel_min, channel_max) in min_max: | ||
| 160 | if channel_min != 0 or channel_max != 0: | ||
| 161 | # 'col' is the rightmost non-empty column. | ||
| 162 | # Assuming no gaps, col+1 is the number of non-empty columns. | ||
| 163 | return col + 1 | ||
| 164 | |||
| 165 | return 0 | ||
| 166 | |||
| 167 | |||
| 168 | def get_sprite_sheet_rows(im, sprite_width, sprite_height): | ||
| 169 | """Gets the individual rows of a sprite sheet. | ||
| 170 | |||
| 171 | The input sprite sheet can have any number of rows. | ||
| 172 | |||
| 173 | Returns a list of lists [[sprite]], one inner list for the columns in each | ||
| 174 | row. | ||
| 175 | """ | ||
| 176 | # Sprite sheet's width and height must be integer multiples of the | ||
| 177 | # sprite's width and height. | ||
| 178 | assert (im.width % sprite_width == 0) | ||
| 179 | assert (im.height % sprite_height == 0) | ||
| 180 | |||
| 181 | num_rows = im.height // sprite_height | ||
| 182 | |||
| 183 | rows = [] | ||
| 184 | for row in range(num_rows): | ||
| 185 | # Get the number of columns. | ||
| 186 | upper = row * sprite_height | ||
| 187 | lower = (row + 1) * sprite_height | ||
| 188 | whole_row = im.crop((0, upper, im.width, lower)) | ||
| 189 | num_cols = get_num_cols(whole_row, sprite_width) | ||
| 190 | assert (num_cols > 0) | ||
| 191 | |||
| 192 | # Crop the row into N columns. | ||
| 193 | cols = [] | ||
| 194 | for i in range(num_cols): | ||
| 195 | left = i * sprite_width | ||
| 196 | right = (i + 1) * sprite_width | ||
| 197 | sprite = im.crop((left, upper, right, lower)) | ||
| 198 | cols.append(sprite) | ||
| 199 | |||
| 200 | assert (len(cols) == num_cols) | ||
| 201 | rows.append(cols) | ||
| 202 | |||
| 203 | return rows | ||
| 204 | |||
| 205 | |||
| 206 | def make_image_from_rows(rows, sprite_width, sprite_height): | ||
| 207 | """Concatenate the rows into a single RGBA image.""" | ||
| 208 | im_width = sprite_width * max(len(row) for row in rows) | ||
| 209 | im_height = len(rows) * sprite_height | ||
| 210 | im = Image.new('RGBA', (im_width, im_height)) | ||
| 211 | y = 0 | ||
| 212 | for row in rows: | ||
| 213 | x = 0 | ||
| 214 | for sprite in row: | ||
| 215 | im.paste(sprite.convert('RGBA'), (x, y)) | ||
| 216 | x += sprite_width | ||
| 217 | y += sprite_height | ||
| 218 | return im | ||
| 219 | |||
| 220 | |||
| 221 | def convert_sprite_sheet(input_file_paths, sprite_width, sprite_height, | ||
| 222 | output_filepath): | ||
| 223 | """Converts a set of sprite sheet images into a binary sprite sheet file | ||
| 224 | (.ss). | ||
| 225 | |||
| 226 | The input sprite sheets can have any number of rows, one row per animation. | ||
| 227 | All rows from all sprite sheets are concatenated in the output file. | ||
| 228 | |||
| 229 | The sprite's width and height is assumed constant throughout the input | ||
| 230 | sprite sheets. | ||
| 231 | """ | ||
| 232 | rows = [] | ||
| 233 | for input_filepath in input_file_paths: | ||
| 234 | with Image.open(input_filepath) as sprite_sheet: | ||
| 235 | rows.extend( | ||
| 236 | get_sprite_sheet_rows(sprite_sheet, sprite_width, | ||
| 237 | sprite_height)) | ||
| 238 | |||
| 239 | im = make_image_from_rows(rows, sprite_width, sprite_height) | ||
| 240 | im = im.convert(mode="P", palette=Image.ADAPTIVE, colors=256) | ||
| 241 | |||
| 242 | # The sprite data in 'rows' is no longer needed. | ||
| 243 | # Keep just the number of columns per row. | ||
| 244 | rows = [len(row) for row in rows] | ||
| 245 | |||
| 246 | with open(output_filepath, 'bw') as output: | ||
| 247 | output.write(ctypes.c_uint16(sprite_width)) | ||
| 248 | output.write(ctypes.c_uint16(sprite_height)) | ||
| 249 | output.write(ctypes.c_uint16(len(rows))) | ||
| 250 | |||
| 251 | # Write palette. | ||
| 252 | # getpalette() returns 256 colors, but the palette might use less than | ||
| 253 | # that. getcolors() returns the number of unique colors. | ||
| 254 | # getpalette() also returns a flattened list, which is why we must *4. | ||
| 255 | num_colours = len(im.getcolors()) | ||
| 256 | colours = im.getpalette(rawmode="RGBA")[:4 * num_colours] | ||
| 257 | palette = [] | ||
| 258 | for i in range(0, 4 * num_colours, 4): | ||
| 259 | palette.append((colours[i], colours[i + 1], colours[i + 2], | ||
| 260 | colours[i + 3])) | ||
| 261 | |||
| 262 | output.write(ctypes.c_uint16(len(palette))) | ||
| 263 | output.write(bytearray(colours)) | ||
| 264 | |||
| 265 | print(f"Sprite width: {sprite_width}") | ||
| 266 | print(f"Sprite height: {sprite_height}") | ||
| 267 | print(f"Rows: {len(rows)}") | ||
| 268 | print(f"Colours: {len(palette)}") | ||
| 269 | |||
| 270 | # print("Palette") | ||
| 271 | # for i, colour in enumerate(palette): | ||
| 272 | # print(f"{i}: {colour}") | ||
| 273 | |||
| 274 | for row, num_columns in enumerate(rows): | ||
| 275 | output.write(ctypes.c_uint16(num_columns)) | ||
| 276 | upper = row * sprite_height | ||
| 277 | lower = (row + 1) * sprite_height | ||
| 278 | for col in range(num_columns): | ||
| 279 | left = col * sprite_width | ||
| 280 | right = (col + 1) * sprite_width | ||
| 281 | sprite = im.crop((left, upper, right, lower)) | ||
| 282 | sprite_bytes = sprite.tobytes() | ||
| 283 | |||
| 284 | assert (len(sprite_bytes) == sprite_width * sprite_height) | ||
| 285 | output.write(sprite_bytes) | ||
| 286 | |||
| 287 | # if (row == 0) and (col == 0): | ||
| 288 | # print(f"Sprite: ({len(sprite_bytes)})") | ||
| 289 | # print(list(sprite_bytes)) | ||
| 290 | # sprite.save("out.png") | ||
| 291 | |||
| 292 | |||
| 293 | def main(): | ||
| 294 | parser = argparse.ArgumentParser() | ||
| 295 | parser.add_argument("input", | ||
| 296 | nargs="+", | ||
| 297 | help="Input file (.tsx, .tmx) or path regex (sprite sheets)") | ||
| 298 | parser.add_argument("--width", type=int, help="Sprite width in pixels") | ||
| 299 | parser.add_argument("--height", type=int, help="Sprite height in pixels") | ||
| 300 | parser.add_argument("--out", help="Output file (sprite sheets)") | ||
| 301 | args = parser.parse_args() | ||
| 302 | |||
| 303 | if ".tsx" in args.input: | ||
| 304 | output_filepath_no_ext = drop_extension(args.input) | ||
| 305 | output_filepath = output_filepath_no_ext + ".ts" | ||
| 306 | convert_tsx(args.input, output_filepath) | ||
| 307 | elif ".tmx" in args.input: | ||
| 308 | output_filepath_no_ext = drop_extension(args.input) | ||
| 309 | output_filepath = output_filepath_no_ext + ".tm" | ||
| 310 | convert_tmx(args.input, output_filepath) | ||
| 311 | else: | ||
| 312 | # Sprite sheets. | ||
| 313 | if not args.width or not args.height: | ||
| 314 | print("Sprite width and height must be given") | ||
| 315 | return 1 | ||
| 316 | output_filepath = args.out if args.out else "out.ss" | ||
| 317 | convert_sprite_sheet(args.input, args.width, args.height, | ||
| 318 | output_filepath) | ||
| 319 | |||
| 320 | return 0 | ||
| 321 | |||
| 322 | |||
| 323 | if __name__ == '__main__': | ||
| 324 | sys.exit(main()) | ||
diff --git a/gfx/CMakeLists.txt b/gfx/CMakeLists.txt deleted file mode 100644 index 7d629dc..0000000 --- a/gfx/CMakeLists.txt +++ /dev/null | |||
| @@ -1,89 +0,0 @@ | |||
| 1 | cmake_minimum_required(VERSION 3.0) | ||
| 2 | |||
| 3 | include(cmake/shader.txt) | ||
| 4 | |||
| 5 | add_subdirectory(contrib/cgltf) | ||
| 6 | add_subdirectory(contrib/cgltf-tangents) | ||
| 7 | add_subdirectory(contrib/stb) | ||
| 8 | |||
| 9 | project(gfx) | ||
| 10 | |||
| 11 | add_shader_library(shaders | ||
| 12 | shaders/brdf_integration_map.frag | ||
| 13 | shaders/cook_torrance.frag | ||
| 14 | shaders/cook_torrance.vert | ||
| 15 | shaders/cubemap_filtering.vert | ||
| 16 | shaders/debug3d.frag | ||
| 17 | shaders/debug3d.vert | ||
| 18 | shaders/immediate_mode.frag | ||
| 19 | shaders/immediate_mode.vert | ||
| 20 | shaders/irradiance_map.frag | ||
| 21 | shaders/prefiltered_environment_map.frag | ||
| 22 | shaders/quad.vert | ||
| 23 | shaders/skyquad.frag | ||
| 24 | shaders/skyquad.vert | ||
| 25 | shaders/view_normal_mapped_normals.frag | ||
| 26 | shaders/view_normal_mapped_normals.vert | ||
| 27 | shaders/view_normals.frag | ||
| 28 | shaders/view_normals.vert | ||
| 29 | shaders/view_tangents.frag | ||
| 30 | shaders/view_tangents.vert | ||
| 31 | shaders/view_texture.frag | ||
| 32 | shaders/view_texture.vert) | ||
| 33 | |||
| 34 | add_library(gfx SHARED | ||
| 35 | src/asset/asset_cache.c | ||
| 36 | src/asset/model.c | ||
| 37 | src/asset/texture.c | ||
| 38 | src/core/buffer.c | ||
| 39 | src/core/core.c | ||
| 40 | src/core/framebuffer.c | ||
| 41 | src/core/geometry.c | ||
| 42 | src/core/renderbuffer.c | ||
| 43 | src/core/shader_program.c | ||
| 44 | src/core/shader.c | ||
| 45 | src/core/texture.c | ||
| 46 | src/renderer/imm_renderer.c | ||
| 47 | src/renderer/renderer.c | ||
| 48 | src/scene/animation.c | ||
| 49 | src/scene/camera.c | ||
| 50 | src/scene/light.c | ||
| 51 | src/scene/material.c | ||
| 52 | src/scene/mesh.c | ||
| 53 | src/scene/model.c | ||
| 54 | src/scene/node.c | ||
| 55 | src/scene/object.c | ||
| 56 | src/scene/scene.c | ||
| 57 | src/scene/scene_memory.c | ||
| 58 | src/gfx.c | ||
| 59 | src/util/geometry.c | ||
| 60 | src/util/ibl.c | ||
| 61 | src/util/shader.c | ||
| 62 | src/util/skyquad.c) | ||
| 63 | |||
| 64 | target_include_directories(gfx PUBLIC | ||
| 65 | include) | ||
| 66 | |||
| 67 | target_include_directories(gfx PRIVATE | ||
| 68 | src) | ||
| 69 | |||
| 70 | target_compile_options(gfx PRIVATE -std=gnu11 -Wall -Wextra -Wpedantic) | ||
| 71 | |||
| 72 | target_link_libraries(gfx PUBLIC | ||
| 73 | cstring | ||
| 74 | math) | ||
| 75 | |||
| 76 | target_link_libraries(gfx PRIVATE | ||
| 77 | cassert | ||
| 78 | cgltf | ||
| 79 | cgltf-tangents | ||
| 80 | error | ||
| 81 | gfx-app | ||
| 82 | log | ||
| 83 | mempool | ||
| 84 | shaders | ||
| 85 | stb | ||
| 86 | # System libraries. | ||
| 87 | GL | ||
| 88 | # Required to initialize GLAD. | ||
| 89 | -ldl) | ||
diff --git a/gfx/include/gfx/asset.h b/include/gfx/asset.h index caf40c1..caf40c1 100644 --- a/gfx/include/gfx/asset.h +++ b/include/gfx/asset.h | |||
diff --git a/gfx/include/gfx/core.h b/include/gfx/core.h index 44509c9..44509c9 100644 --- a/gfx/include/gfx/core.h +++ b/include/gfx/core.h | |||
diff --git a/gfx/include/gfx/gfx.h b/include/gfx/gfx.h index 7c670a5..7c670a5 100644 --- a/gfx/include/gfx/gfx.h +++ b/include/gfx/gfx.h | |||
diff --git a/gfx/include/gfx/renderer.h b/include/gfx/renderer.h index 2a4ada1..2a4ada1 100644 --- a/gfx/include/gfx/renderer.h +++ b/include/gfx/renderer.h | |||
diff --git a/gfx/include/gfx/scene.h b/include/gfx/scene.h index abcaa70..abcaa70 100644 --- a/gfx/include/gfx/scene.h +++ b/include/gfx/scene.h | |||
diff --git a/gfx/include/gfx/scene/animation.h b/include/gfx/scene/animation.h index d95b895..d95b895 100644 --- a/gfx/include/gfx/scene/animation.h +++ b/include/gfx/scene/animation.h | |||
diff --git a/gfx/include/gfx/scene/camera.h b/include/gfx/scene/camera.h index 99d83fe..99d83fe 100644 --- a/gfx/include/gfx/scene/camera.h +++ b/include/gfx/scene/camera.h | |||
diff --git a/gfx/include/gfx/scene/light.h b/include/gfx/scene/light.h index 132e344..132e344 100644 --- a/gfx/include/gfx/scene/light.h +++ b/include/gfx/scene/light.h | |||
diff --git a/gfx/include/gfx/scene/material.h b/include/gfx/scene/material.h index bca664e..bca664e 100644 --- a/gfx/include/gfx/scene/material.h +++ b/include/gfx/scene/material.h | |||
diff --git a/gfx/include/gfx/scene/mesh.h b/include/gfx/scene/mesh.h index 0d3b4d4..0d3b4d4 100644 --- a/gfx/include/gfx/scene/mesh.h +++ b/include/gfx/scene/mesh.h | |||
diff --git a/gfx/include/gfx/scene/model.h b/include/gfx/scene/model.h index 42f85d4..42f85d4 100644 --- a/gfx/include/gfx/scene/model.h +++ b/include/gfx/scene/model.h | |||
diff --git a/gfx/include/gfx/scene/node.h b/include/gfx/scene/node.h index a2c2836..a2c2836 100644 --- a/gfx/include/gfx/scene/node.h +++ b/include/gfx/scene/node.h | |||
diff --git a/gfx/include/gfx/scene/object.h b/include/gfx/scene/object.h index 7579d29..7579d29 100644 --- a/gfx/include/gfx/scene/object.h +++ b/include/gfx/scene/object.h | |||
diff --git a/gfx/include/gfx/scene/scene.h b/include/gfx/scene/scene.h index 0d96210..0d96210 100644 --- a/gfx/include/gfx/scene/scene.h +++ b/include/gfx/scene/scene.h | |||
diff --git a/gfx/include/gfx/sizes.h b/include/gfx/sizes.h index 076113c..076113c 100644 --- a/gfx/include/gfx/sizes.h +++ b/include/gfx/sizes.h | |||
diff --git a/gfx/include/gfx/util/geometry.h b/include/gfx/util/geometry.h index a962291..a962291 100644 --- a/gfx/include/gfx/util/geometry.h +++ b/include/gfx/util/geometry.h | |||
diff --git a/gfx/include/gfx/util/ibl.h b/include/gfx/util/ibl.h index 6e39180..6e39180 100644 --- a/gfx/include/gfx/util/ibl.h +++ b/include/gfx/util/ibl.h | |||
diff --git a/gfx/include/gfx/util/shader.h b/include/gfx/util/shader.h index bd058f4..bd058f4 100644 --- a/gfx/include/gfx/util/shader.h +++ b/include/gfx/util/shader.h | |||
diff --git a/gfx/include/gfx/util/skyquad.h b/include/gfx/util/skyquad.h index 2b3fe17..2b3fe17 100644 --- a/gfx/include/gfx/util/skyquad.h +++ b/include/gfx/util/skyquad.h | |||
diff --git a/gfx/shaders/brdf_integration_map.frag b/shaders/brdf_integration_map.frag index bb2cebd..bb2cebd 100644 --- a/gfx/shaders/brdf_integration_map.frag +++ b/shaders/brdf_integration_map.frag | |||
diff --git a/gfx/shaders/cook_torrance.frag b/shaders/cook_torrance.frag index 1975491..1975491 100644 --- a/gfx/shaders/cook_torrance.frag +++ b/shaders/cook_torrance.frag | |||
diff --git a/gfx/shaders/cook_torrance.vert b/shaders/cook_torrance.vert index 5f126c0..5f126c0 100644 --- a/gfx/shaders/cook_torrance.vert +++ b/shaders/cook_torrance.vert | |||
diff --git a/gfx/shaders/cubemap_filtering.vert b/shaders/cubemap_filtering.vert index d0cf73f..d0cf73f 100644 --- a/gfx/shaders/cubemap_filtering.vert +++ b/shaders/cubemap_filtering.vert | |||
diff --git a/gfx/shaders/debug3d.frag b/shaders/debug3d.frag index 54568d4..54568d4 100644 --- a/gfx/shaders/debug3d.frag +++ b/shaders/debug3d.frag | |||
diff --git a/gfx/shaders/debug3d.vert b/shaders/debug3d.vert index d51684f..d51684f 100644 --- a/gfx/shaders/debug3d.vert +++ b/shaders/debug3d.vert | |||
diff --git a/gfx/shaders/immediate_mode.frag b/shaders/immediate_mode.frag index ac23b5c..ac23b5c 100644 --- a/gfx/shaders/immediate_mode.frag +++ b/shaders/immediate_mode.frag | |||
diff --git a/gfx/shaders/immediate_mode.vert b/shaders/immediate_mode.vert index 65070bb..65070bb 100644 --- a/gfx/shaders/immediate_mode.vert +++ b/shaders/immediate_mode.vert | |||
diff --git a/gfx/shaders/irradiance_map.frag b/shaders/irradiance_map.frag index 8200e73..8200e73 100644 --- a/gfx/shaders/irradiance_map.frag +++ b/shaders/irradiance_map.frag | |||
diff --git a/gfx/shaders/prefiltered_environment_map.frag b/shaders/prefiltered_environment_map.frag index 8327950..8327950 100644 --- a/gfx/shaders/prefiltered_environment_map.frag +++ b/shaders/prefiltered_environment_map.frag | |||
diff --git a/gfx/shaders/quad.vert b/shaders/quad.vert index ef1834c..ef1834c 100644 --- a/gfx/shaders/quad.vert +++ b/shaders/quad.vert | |||
diff --git a/gfx/shaders/skyquad.frag b/shaders/skyquad.frag index 9b44bfd..9b44bfd 100644 --- a/gfx/shaders/skyquad.frag +++ b/shaders/skyquad.frag | |||
diff --git a/gfx/shaders/skyquad.vert b/shaders/skyquad.vert index c0c46e6..c0c46e6 100644 --- a/gfx/shaders/skyquad.vert +++ b/shaders/skyquad.vert | |||
diff --git a/gfx/shaders/view_normal_mapped_normals.frag b/shaders/view_normal_mapped_normals.frag index a372c02..a372c02 100644 --- a/gfx/shaders/view_normal_mapped_normals.frag +++ b/shaders/view_normal_mapped_normals.frag | |||
diff --git a/gfx/shaders/view_normal_mapped_normals.vert b/shaders/view_normal_mapped_normals.vert index 004ed9a..004ed9a 100644 --- a/gfx/shaders/view_normal_mapped_normals.vert +++ b/shaders/view_normal_mapped_normals.vert | |||
diff --git a/gfx/shaders/view_normals.frag b/shaders/view_normals.frag index e90189c..e90189c 100644 --- a/gfx/shaders/view_normals.frag +++ b/shaders/view_normals.frag | |||
diff --git a/gfx/shaders/view_normals.vert b/shaders/view_normals.vert index d51684f..d51684f 100644 --- a/gfx/shaders/view_normals.vert +++ b/shaders/view_normals.vert | |||
diff --git a/gfx/shaders/view_tangents.frag b/shaders/view_tangents.frag index 11d1455..11d1455 100644 --- a/gfx/shaders/view_tangents.frag +++ b/shaders/view_tangents.frag | |||
diff --git a/gfx/shaders/view_tangents.vert b/shaders/view_tangents.vert index 561ad22..561ad22 100644 --- a/gfx/shaders/view_tangents.vert +++ b/shaders/view_tangents.vert | |||
diff --git a/gfx/shaders/view_texture.frag b/shaders/view_texture.frag index 12fa367..12fa367 100644 --- a/gfx/shaders/view_texture.frag +++ b/shaders/view_texture.frag | |||
diff --git a/gfx/shaders/view_texture.vert b/shaders/view_texture.vert index 4e3c7d7..4e3c7d7 100644 --- a/gfx/shaders/view_texture.vert +++ b/shaders/view_texture.vert | |||
diff --git a/gfx/src/asset/asset_cache.c b/src/asset/asset_cache.c index 16c4d5c..16c4d5c 100644 --- a/gfx/src/asset/asset_cache.c +++ b/src/asset/asset_cache.c | |||
diff --git a/gfx/src/asset/asset_cache.h b/src/asset/asset_cache.h index b2a35ed..b2a35ed 100644 --- a/gfx/src/asset/asset_cache.h +++ b/src/asset/asset_cache.h | |||
diff --git a/gfx/src/asset/model.c b/src/asset/model.c index 25f2780..25f2780 100644 --- a/gfx/src/asset/model.c +++ b/src/asset/model.c | |||
diff --git a/gfx/src/asset/model.h b/src/asset/model.h index d6399b1..d6399b1 100644 --- a/gfx/src/asset/model.h +++ b/src/asset/model.h | |||
diff --git a/gfx/src/asset/texture.c b/src/asset/texture.c index c790394..c790394 100644 --- a/gfx/src/asset/texture.c +++ b/src/asset/texture.c | |||
diff --git a/gfx/src/asset/texture.h b/src/asset/texture.h index 0d38bd9..0d38bd9 100644 --- a/gfx/src/asset/texture.h +++ b/src/asset/texture.h | |||
diff --git a/gfx/src/core/buffer.c b/src/core/buffer.c index 3b7e4bc..3b7e4bc 100644 --- a/gfx/src/core/buffer.c +++ b/src/core/buffer.c | |||
diff --git a/gfx/src/core/buffer.h b/src/core/buffer.h index b9080f0..b9080f0 100644 --- a/gfx/src/core/buffer.h +++ b/src/core/buffer.h | |||
diff --git a/gfx/src/core/constants.h b/src/core/constants.h index a6a3b94..a6a3b94 100644 --- a/gfx/src/core/constants.h +++ b/src/core/constants.h | |||
diff --git a/gfx/src/core/core.c b/src/core/core.c index 90038c6..90038c6 100644 --- a/gfx/src/core/core.c +++ b/src/core/core.c | |||
diff --git a/gfx/src/core/core_impl.h b/src/core/core_impl.h index eefdfbe..eefdfbe 100644 --- a/gfx/src/core/core_impl.h +++ b/src/core/core_impl.h | |||
diff --git a/gfx/src/core/framebuffer.c b/src/core/framebuffer.c index 76d9002..76d9002 100644 --- a/gfx/src/core/framebuffer.c +++ b/src/core/framebuffer.c | |||
diff --git a/gfx/src/core/framebuffer.h b/src/core/framebuffer.h index 1a3439c..1a3439c 100644 --- a/gfx/src/core/framebuffer.h +++ b/src/core/framebuffer.h | |||
diff --git a/gfx/src/core/geometry.c b/src/core/geometry.c index cfc749f..cfc749f 100644 --- a/gfx/src/core/geometry.c +++ b/src/core/geometry.c | |||
diff --git a/gfx/src/core/geometry.h b/src/core/geometry.h index c37a76f..c37a76f 100644 --- a/gfx/src/core/geometry.h +++ b/src/core/geometry.h | |||
diff --git a/gfx/src/core/gl_util.h b/src/core/gl_util.h index d2d6e22..d2d6e22 100644 --- a/gfx/src/core/gl_util.h +++ b/src/core/gl_util.h | |||
diff --git a/gfx/src/core/renderbuffer.c b/src/core/renderbuffer.c index 2753f3b..2753f3b 100644 --- a/gfx/src/core/renderbuffer.c +++ b/src/core/renderbuffer.c | |||
diff --git a/gfx/src/core/renderbuffer.h b/src/core/renderbuffer.h index ea11610..ea11610 100644 --- a/gfx/src/core/renderbuffer.h +++ b/src/core/renderbuffer.h | |||
diff --git a/gfx/src/core/shader.c b/src/core/shader.c index dded084..dded084 100644 --- a/gfx/src/core/shader.c +++ b/src/core/shader.c | |||
diff --git a/gfx/src/core/shader.h b/src/core/shader.h index b9f5679..b9f5679 100644 --- a/gfx/src/core/shader.h +++ b/src/core/shader.h | |||
diff --git a/gfx/src/core/shader_program.c b/src/core/shader_program.c index 3cbe48d..3cbe48d 100644 --- a/gfx/src/core/shader_program.c +++ b/src/core/shader_program.c | |||
diff --git a/gfx/src/core/shader_program.h b/src/core/shader_program.h index 1443663..1443663 100644 --- a/gfx/src/core/shader_program.h +++ b/src/core/shader_program.h | |||
diff --git a/gfx/src/core/texture.c b/src/core/texture.c index 89f7ec0..89f7ec0 100644 --- a/gfx/src/core/texture.c +++ b/src/core/texture.c | |||
diff --git a/gfx/src/core/texture.h b/src/core/texture.h index 4af41e9..4af41e9 100644 --- a/gfx/src/core/texture.h +++ b/src/core/texture.h | |||
diff --git a/gfx/src/gfx.c b/src/gfx.c index cd2ac90..cd2ac90 100644 --- a/gfx/src/gfx.c +++ b/src/gfx.c | |||
diff --git a/gfx/src/gfx_assert.h b/src/gfx_assert.h index f4b3aa5..f4b3aa5 100644 --- a/gfx/src/gfx_assert.h +++ b/src/gfx_assert.h | |||
diff --git a/gfx/src/renderer/imm_renderer.c b/src/renderer/imm_renderer.c index 8cf3a10..8cf3a10 100644 --- a/gfx/src/renderer/imm_renderer.c +++ b/src/renderer/imm_renderer.c | |||
diff --git a/gfx/src/renderer/imm_renderer_impl.h b/src/renderer/imm_renderer_impl.h index 5ece354..5ece354 100644 --- a/gfx/src/renderer/imm_renderer_impl.h +++ b/src/renderer/imm_renderer_impl.h | |||
diff --git a/gfx/src/renderer/renderer.c b/src/renderer/renderer.c index c2a7dda..c2a7dda 100644 --- a/gfx/src/renderer/renderer.c +++ b/src/renderer/renderer.c | |||
diff --git a/gfx/src/renderer/renderer_impl.h b/src/renderer/renderer_impl.h index fc14dcb..fc14dcb 100644 --- a/gfx/src/renderer/renderer_impl.h +++ b/src/renderer/renderer_impl.h | |||
diff --git a/gfx/src/scene/animation.c b/src/scene/animation.c index 08d02ce..08d02ce 100644 --- a/gfx/src/scene/animation.c +++ b/src/scene/animation.c | |||
diff --git a/gfx/src/scene/animation_impl.h b/src/scene/animation_impl.h index 4408158..4408158 100644 --- a/gfx/src/scene/animation_impl.h +++ b/src/scene/animation_impl.h | |||
diff --git a/gfx/src/scene/camera.c b/src/scene/camera.c index be7d806..be7d806 100644 --- a/gfx/src/scene/camera.c +++ b/src/scene/camera.c | |||
diff --git a/gfx/src/scene/camera_impl.h b/src/scene/camera_impl.h index 20c3890..20c3890 100644 --- a/gfx/src/scene/camera_impl.h +++ b/src/scene/camera_impl.h | |||
diff --git a/gfx/src/scene/light.c b/src/scene/light.c index adbec8d..adbec8d 100644 --- a/gfx/src/scene/light.c +++ b/src/scene/light.c | |||
diff --git a/gfx/src/scene/light_impl.h b/src/scene/light_impl.h index 1aa0bb4..1aa0bb4 100644 --- a/gfx/src/scene/light_impl.h +++ b/src/scene/light_impl.h | |||
diff --git a/gfx/src/scene/material.c b/src/scene/material.c index 3248243..3248243 100644 --- a/gfx/src/scene/material.c +++ b/src/scene/material.c | |||
diff --git a/gfx/src/scene/material_impl.h b/src/scene/material_impl.h index a6aa95b..a6aa95b 100644 --- a/gfx/src/scene/material_impl.h +++ b/src/scene/material_impl.h | |||
diff --git a/gfx/src/scene/mesh.c b/src/scene/mesh.c index 1a93bed..1a93bed 100644 --- a/gfx/src/scene/mesh.c +++ b/src/scene/mesh.c | |||
diff --git a/gfx/src/scene/mesh_impl.h b/src/scene/mesh_impl.h index 560b77e..560b77e 100644 --- a/gfx/src/scene/mesh_impl.h +++ b/src/scene/mesh_impl.h | |||
diff --git a/gfx/src/scene/model.c b/src/scene/model.c index cc41a9a..cc41a9a 100644 --- a/gfx/src/scene/model.c +++ b/src/scene/model.c | |||
diff --git a/gfx/src/scene/model_impl.h b/src/scene/model_impl.h index a99d32c..a99d32c 100644 --- a/gfx/src/scene/model_impl.h +++ b/src/scene/model_impl.h | |||
diff --git a/gfx/src/scene/node.c b/src/scene/node.c index 67ce93c..67ce93c 100644 --- a/gfx/src/scene/node.c +++ b/src/scene/node.c | |||
diff --git a/gfx/src/scene/node_impl.h b/src/scene/node_impl.h index c79f252..c79f252 100644 --- a/gfx/src/scene/node_impl.h +++ b/src/scene/node_impl.h | |||
diff --git a/gfx/src/scene/object.c b/src/scene/object.c index e8e3ee6..e8e3ee6 100644 --- a/gfx/src/scene/object.c +++ b/src/scene/object.c | |||
diff --git a/gfx/src/scene/object_impl.h b/src/scene/object_impl.h index 88f8e31..88f8e31 100644 --- a/gfx/src/scene/object_impl.h +++ b/src/scene/object_impl.h | |||
diff --git a/gfx/src/scene/scene.c b/src/scene/scene.c index 54452dd..54452dd 100644 --- a/gfx/src/scene/scene.c +++ b/src/scene/scene.c | |||
diff --git a/gfx/src/scene/scene_graph.h b/src/scene/scene_graph.h index a26f828..a26f828 100644 --- a/gfx/src/scene/scene_graph.h +++ b/src/scene/scene_graph.h | |||
diff --git a/gfx/src/scene/scene_impl.h b/src/scene/scene_impl.h index 992f620..992f620 100644 --- a/gfx/src/scene/scene_impl.h +++ b/src/scene/scene_impl.h | |||
diff --git a/gfx/src/scene/scene_memory.c b/src/scene/scene_memory.c index 85c27e7..85c27e7 100644 --- a/gfx/src/scene/scene_memory.c +++ b/src/scene/scene_memory.c | |||
diff --git a/gfx/src/scene/scene_memory.h b/src/scene/scene_memory.h index d175cba..d175cba 100644 --- a/gfx/src/scene/scene_memory.h +++ b/src/scene/scene_memory.h | |||
diff --git a/gfx/src/scene/types.h b/src/scene/types.h index d0ffc41..d0ffc41 100644 --- a/gfx/src/scene/types.h +++ b/src/scene/types.h | |||
diff --git a/gfx/src/util/geometry.c b/src/util/geometry.c index afe0109..afe0109 100644 --- a/gfx/src/util/geometry.c +++ b/src/util/geometry.c | |||
diff --git a/gfx/src/util/ibl.c b/src/util/ibl.c index 5a79990..5a79990 100644 --- a/gfx/src/util/ibl.c +++ b/src/util/ibl.c | |||
diff --git a/gfx/src/util/shader.c b/src/util/shader.c index f5c22cc..f5c22cc 100644 --- a/gfx/src/util/shader.c +++ b/src/util/shader.c | |||
diff --git a/gfx/src/util/skyquad.c b/src/util/skyquad.c index 08fa044..08fa044 100644 --- a/gfx/src/util/skyquad.c +++ b/src/util/skyquad.c | |||
