From b6cf1d104da53ec9c30dc45c35d9de48812f0afc Mon Sep 17 00:00:00 2001 From: Xander Swan Date: Wed, 3 Dec 2025 09:52:13 -0500 Subject: Initial commit --- README | 1 + res/happy.qoi | Bin 0 -> 121 bytes res/robot2.json | 306 ++++++++++++++++++++++++ res/robot2.qoi | Bin 0 -> 5755 bytes run.sh | 2 + run_release.sh | 2 + src/draw/animation.odin | 84 +++++++ src/draw/default.glsl | 38 +++ src/draw/default_shader.odin | 538 +++++++++++++++++++++++++++++++++++++++++++ src/draw/draw.odin | 284 +++++++++++++++++++++++ src/draw/framebuffer.odin | 94 ++++++++ src/draw/sprite.odin | 88 +++++++ src/entity_list.odin | 81 +++++++ src/input.odin | 60 +++++ src/main.odin | 80 +++++++ src/player.odin | 68 ++++++ 16 files changed, 1726 insertions(+) create mode 100644 README create mode 100644 res/happy.qoi create mode 100644 res/robot2.json create mode 100644 res/robot2.qoi create mode 100755 run.sh create mode 100755 run_release.sh create mode 100644 src/draw/animation.odin create mode 100644 src/draw/default.glsl create mode 100644 src/draw/default_shader.odin create mode 100644 src/draw/draw.odin create mode 100644 src/draw/framebuffer.odin create mode 100644 src/draw/sprite.odin create mode 100644 src/entity_list.odin create mode 100644 src/input.odin create mode 100644 src/main.odin create mode 100644 src/player.odin diff --git a/README b/README new file mode 100644 index 0000000..3d5e6a5 --- /dev/null +++ b/README @@ -0,0 +1 @@ +Will need sokol. Place it inside the shared directory given by Odin. diff --git a/res/happy.qoi b/res/happy.qoi new file mode 100644 index 0000000..efc653d Binary files /dev/null and b/res/happy.qoi differ diff --git a/res/robot2.json b/res/robot2.json new file mode 100644 index 0000000..a383b94 --- /dev/null +++ b/res/robot2.json @@ -0,0 +1,306 @@ +{ "frames": [ + { + "filename": "0", + "frame": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 200 + }, + { + "filename": "1", + "frame": { "x": 16, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 100 + }, + { + "filename": "2", + "frame": { "x": 32, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 100 + }, + { + "filename": "3", + "frame": { "x": 48, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 100 + }, + { + "filename": "4", + "frame": { "x": 64, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 100 + }, + { + "filename": "5", + "frame": { "x": 80, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 100 + }, + { + "filename": "6", + "frame": { "x": 96, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 200 + }, + { + "filename": "7", + "frame": { "x": 112, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 100 + }, + { + "filename": "8", + "frame": { "x": 128, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 100 + }, + { + "filename": "9", + "frame": { "x": 144, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 100 + }, + { + "filename": "10", + "frame": { "x": 160, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 100 + }, + { + "filename": "11", + "frame": { "x": 176, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 100 + }, + { + "filename": "12", + "frame": { "x": 192, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 75 + }, + { + "filename": "13", + "frame": { "x": 208, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 75 + }, + { + "filename": "14", + "frame": { "x": 224, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 75 + }, + { + "filename": "15", + "frame": { "x": 240, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 75 + }, + { + "filename": "16", + "frame": { "x": 256, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 75 + }, + { + "filename": "17", + "frame": { "x": 272, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 75 + }, + { + "filename": "18", + "frame": { "x": 288, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 75 + }, + { + "filename": "19", + "frame": { "x": 304, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 75 + }, + { + "filename": "20", + "frame": { "x": 320, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 75 + }, + { + "filename": "21", + "frame": { "x": 336, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 75 + }, + { + "filename": "22", + "frame": { "x": 352, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 75 + }, + { + "filename": "23", + "frame": { "x": 368, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 75 + }, + { + "filename": "24", + "frame": { "x": 384, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 75 + }, + { + "filename": "25", + "frame": { "x": 400, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 75 + }, + { + "filename": "26", + "frame": { "x": 416, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 75 + }, + { + "filename": "27", + "frame": { "x": 432, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 75 + }, + { + "filename": "28", + "frame": { "x": 448, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 100 + }, + { + "filename": "29", + "frame": { "x": 464, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 100 + }, + { + "filename": "30", + "frame": { "x": 480, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 100 + }, + { + "filename": "31", + "frame": { "x": 496, "y": 0, "w": 16, "h": 17 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 17 }, + "sourceSize": { "w": 16, "h": 17 }, + "duration": 100 + } + ], + "meta": { + "app": "http://www.aseprite.org/", + "version": "1.x-dev", + "image": "robot2.qoi", + "format": "RGBA8888", + "size": { "w": 512, "h": 17 }, + "scale": "1", + "frameTags": [ + { "name": "down_idle", "from": 0, "to": 5, "direction": "forward", "color": "#fe5b59ff" }, + { "name": "up_idle", "from": 6, "to": 11, "direction": "forward", "color": "#fe5b59ff" }, + { "name": "down_run", "from": 12, "to": 19, "direction": "forward", "color": "#f7a547ff" }, + { "name": "up_run", "from": 20, "to": 27, "direction": "forward", "color": "#f7a547ff" }, + { "name": "sleep", "from": 28, "to": 31, "direction": "forward", "color": "#57b9f2ff" } + ] + } +} diff --git a/res/robot2.qoi b/res/robot2.qoi new file mode 100644 index 0000000..f5956a6 Binary files /dev/null and b/res/robot2.qoi differ diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..0c786f7 --- /dev/null +++ b/run.sh @@ -0,0 +1,2 @@ +sokol-shdc -i src/draw/default.glsl -o src/draw/default_shader.odin -l glsl430:metal_macos:hlsl5 -f sokol_odin +odin run src -disallow-do -debug -sanitize:address -show-timings diff --git a/run_release.sh b/run_release.sh new file mode 100755 index 0000000..9036768 --- /dev/null +++ b/run_release.sh @@ -0,0 +1,2 @@ +sokol-shdc -i default.glsl -o default_shader.odin -l glsl430:metal_macos:hlsl5 -f sokol_odin +odin run . -vet -disallow-do -o:speed diff --git a/src/draw/animation.odin b/src/draw/animation.odin new file mode 100644 index 0000000..ac947fb --- /dev/null +++ b/src/draw/animation.odin @@ -0,0 +1,84 @@ +package draw + +import "core:encoding/json" +import "core:fmt" +import "core:os" +import "core:path/filepath" +import "core:strings" + +FrameRect :: struct { + x: i32 `json:"x"`, + y: i32 `json:"y"`, + w: i32 `json:"w"`, + h: i32 `json:"h"`, +} + +Frame :: struct { + rect: FrameRect `json:"frame"`, + duration: i32 `json:"duration"`, +} + +Tag :: struct { + name: string `json:"name"`, + from: i32 `json:"from"`, + to: i32 `json:"to"`, + direction: string `json:"direction"`, +} + +AnimationMeta :: struct { + image_path: string `json:"image"`, + frame_tags: []Tag `json:"frameTags"`, + frame_tags_indices: map[string]u32, +} + +Animation :: struct { + frames: []Frame `json:"frames"`, + using meta: AnimationMeta `json:"meta"`, +} + +@(require_results) +init_anim_data :: proc(anim: ^Animation, path: string) -> bool { + data, ok := os.read_entire_file(path) + if !ok { + return false + } + defer delete(data) + + json_err := json.unmarshal(data, anim) + if json_err != nil { + fmt.println("could not unmarshal data") + return false + } + + for tag, i in anim.frame_tags { + anim.frame_tags_indices[tag.name] = u32(i) + } + + partial_img_path := anim.image_path + defer delete(partial_img_path) + anim_dir := filepath.dir(path) + defer delete(anim_dir) + + anim.image_path = strings.concatenate({anim_dir, "/", partial_img_path}) + + return true +} + +delete_anim_data :: proc(anim: Animation) { + delete(anim.frames) + + for tag in anim.frame_tags { + delete(tag.name) + delete(tag.direction) + } + + // sg.destroy_image(anim.image) + + delete(anim.frame_tags) + delete(anim.frame_tags_indices) + delete(anim.image_path) +} + +get_anim_tag :: proc(anim: Animation, tag_name: string) -> Tag { + return anim.frame_tags[anim.frame_tags_indices[tag_name]] +} diff --git a/src/draw/default.glsl b/src/draw/default.glsl new file mode 100644 index 0000000..b45a1c9 --- /dev/null +++ b/src/draw/default.glsl @@ -0,0 +1,38 @@ +@header package draw +@header import sg "shared:sokol/gfx" + +@vs vs +in vec2 vposition; +in vec2 vuv; +in vec4 vcolor; + +out vec4 fcolor; +out vec2 fuv; + +layout (binding = 0) uniform default_vs_params { + mat4 projection; +}; + +void main() { + gl_Position = projection * vec4(vposition, 0.0, 1.0); + fcolor = vcolor; + fuv = vuv; +} +@end + +@fs fs +in vec4 fcolor; +in vec2 fuv; + +out vec4 out_color; + +layout (binding = 0) uniform texture2D tex; +layout (binding = 0) uniform sampler tex_samp; +#define tex sampler2D(tex, tex_samp) + +void main() { + out_color = texture(tex, fuv) * fcolor; +} +@end + +@program default vs fs diff --git a/src/draw/default_shader.odin b/src/draw/default_shader.odin new file mode 100644 index 0000000..eca5c62 --- /dev/null +++ b/src/draw/default_shader.odin @@ -0,0 +1,538 @@ +package draw +import sg "shared:sokol/gfx" +/* + #version:1# (machine generated, don't edit!) + + Generated by sokol-shdc (https://github.com/floooh/sokol-tools) + + Cmdline: + sokol-shdc -i src/draw/default.glsl -o src/draw/default_shader.odin -l glsl430:metal_macos:hlsl5 -f sokol_odin + + Overview: + ========= + Shader program: 'default': + Get shader desc: default_shader_desc(sg.query_backend()) + Vertex Shader: vs + Fragment Shader: fs + Attributes: + ATTR_default_vposition => 0 + ATTR_default_vuv => 1 + ATTR_default_vcolor => 2 + Bindings: + Uniform block 'default_vs_params': + Odin struct: Default_Vs_Params + Bind slot: UB_default_vs_params => 0 + Texture 'tex': + Image type: ._2D + Sample type: .FLOAT + Multisampled: false + Bind slot: VIEW_tex => 0 + Sampler 'tex_samp': + Type: .FILTERING + Bind slot: SMP_tex_samp => 0 +*/ +ATTR_default_vposition :: 0 +ATTR_default_vuv :: 1 +ATTR_default_vcolor :: 2 +UB_default_vs_params :: 0 +VIEW_tex :: 0 +SMP_tex_samp :: 0 +Default_Vs_Params :: struct #align(16) { + using _: struct #packed { + projection: [16]f32, + }, +} +/* + #version 430 + + uniform vec4 default_vs_params[4]; + layout(location = 0) in vec2 vposition; + layout(location = 0) out vec4 fcolor; + layout(location = 2) in vec4 vcolor; + layout(location = 1) out vec2 fuv; + layout(location = 1) in vec2 vuv; + + void main() + { + gl_Position = mat4(default_vs_params[0], default_vs_params[1], default_vs_params[2], default_vs_params[3]) * vec4(vposition, 0.0, 1.0); + fcolor = vcolor; + fuv = vuv; + } + +*/ +@(private="file") +vs_source_glsl430 := [428]u8 { + 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x34,0x33,0x30,0x0a,0x0a,0x75,0x6e, + 0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x64,0x65,0x66,0x61,0x75, + 0x6c,0x74,0x5f,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x34,0x5d,0x3b, + 0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, + 0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x76,0x70, + 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28, + 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75, + 0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x66,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c, + 0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d, + 0x20,0x32,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x63,0x6f,0x6c, + 0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74, + 0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x6f,0x75,0x74,0x20,0x76,0x65,0x63, + 0x32,0x20,0x66,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f, + 0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76, + 0x65,0x63,0x32,0x20,0x76,0x75,0x76,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d, + 0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f,0x50, + 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x6d,0x61,0x74,0x34,0x28,0x64, + 0x65,0x66,0x61,0x75,0x6c,0x74,0x5f,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73, + 0x5b,0x30,0x5d,0x2c,0x20,0x64,0x65,0x66,0x61,0x75,0x6c,0x74,0x5f,0x76,0x73,0x5f, + 0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x2c,0x20,0x64,0x65,0x66,0x61,0x75, + 0x6c,0x74,0x5f,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x32,0x5d,0x2c, + 0x20,0x64,0x65,0x66,0x61,0x75,0x6c,0x74,0x5f,0x76,0x73,0x5f,0x70,0x61,0x72,0x61, + 0x6d,0x73,0x5b,0x33,0x5d,0x29,0x20,0x2a,0x20,0x76,0x65,0x63,0x34,0x28,0x76,0x70, + 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x31,0x2e, + 0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d, + 0x20,0x76,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x75,0x76, + 0x20,0x3d,0x20,0x76,0x75,0x76,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, +} +/* + #version 430 + + layout(binding = 0) uniform sampler2D tex_tex_samp; + + layout(location = 0) out vec4 out_color; + layout(location = 1) in vec2 fuv; + layout(location = 0) in vec4 fcolor; + + void main() + { + out_color = texture(tex_tex_samp, fuv) * fcolor; + } + +*/ +@(private="file") +fs_source_glsl430 := [251]u8 { + 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x34,0x33,0x30,0x0a,0x0a,0x6c,0x61, + 0x79,0x6f,0x75,0x74,0x28,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x20,0x3d,0x20,0x30, + 0x29,0x20,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65, + 0x72,0x32,0x44,0x20,0x74,0x65,0x78,0x5f,0x74,0x65,0x78,0x5f,0x73,0x61,0x6d,0x70, + 0x3b,0x0a,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69, + 0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34, + 0x20,0x6f,0x75,0x74,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f, + 0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29, + 0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x66,0x75,0x76,0x3b,0x0a,0x6c,0x61, + 0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20, + 0x30,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x66,0x63,0x6f,0x6c,0x6f, + 0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a, + 0x7b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20, + 0x3d,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x74,0x65,0x78,0x5f,0x74,0x65, + 0x78,0x5f,0x73,0x61,0x6d,0x70,0x2c,0x20,0x66,0x75,0x76,0x29,0x20,0x2a,0x20,0x66, + 0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, +} +/* + cbuffer default_vs_params : register(b0) + { + row_major float4x4 _19_projection : packoffset(c0); + }; + + + static float4 gl_Position; + static float2 vposition; + static float4 fcolor; + static float4 vcolor; + static float2 fuv; + static float2 vuv; + + struct SPIRV_Cross_Input + { + float2 vposition : TEXCOORD0; + float2 vuv : TEXCOORD1; + float4 vcolor : TEXCOORD2; + }; + + struct SPIRV_Cross_Output + { + float4 fcolor : TEXCOORD0; + float2 fuv : TEXCOORD1; + float4 gl_Position : SV_Position; + }; + + void vert_main() + { + gl_Position = mul(float4(vposition, 0.0f, 1.0f), _19_projection); + fcolor = vcolor; + fuv = vuv; + } + + SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) + { + vposition = stage_input.vposition; + vcolor = stage_input.vcolor; + vuv = stage_input.vuv; + vert_main(); + SPIRV_Cross_Output stage_output; + stage_output.gl_Position = gl_Position; + stage_output.fcolor = fcolor; + stage_output.fuv = fuv; + return stage_output; + } +*/ +@(private="file") +vs_source_hlsl5 := [964]u8 { + 0x63,0x62,0x75,0x66,0x66,0x65,0x72,0x20,0x64,0x65,0x66,0x61,0x75,0x6c,0x74,0x5f, + 0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x20,0x3a,0x20,0x72,0x65,0x67,0x69, + 0x73,0x74,0x65,0x72,0x28,0x62,0x30,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x72, + 0x6f,0x77,0x5f,0x6d,0x61,0x6a,0x6f,0x72,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x78, + 0x34,0x20,0x5f,0x31,0x39,0x5f,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x69,0x6f,0x6e, + 0x20,0x3a,0x20,0x70,0x61,0x63,0x6b,0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x63,0x30, + 0x29,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x66, + 0x6c,0x6f,0x61,0x74,0x34,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f, + 0x6e,0x3b,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32, + 0x20,0x76,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x73,0x74,0x61,0x74, + 0x69,0x63,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x66,0x63,0x6f,0x6c,0x6f,0x72, + 0x3b,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20, + 0x76,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x66, + 0x6c,0x6f,0x61,0x74,0x32,0x20,0x66,0x75,0x76,0x3b,0x0a,0x73,0x74,0x61,0x74,0x69, + 0x63,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x76,0x75,0x76,0x3b,0x0a,0x0a,0x73, + 0x74,0x72,0x75,0x63,0x74,0x20,0x53,0x50,0x49,0x52,0x56,0x5f,0x43,0x72,0x6f,0x73, + 0x73,0x5f,0x49,0x6e,0x70,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c, + 0x6f,0x61,0x74,0x32,0x20,0x76,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3a, + 0x20,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44,0x30,0x3b,0x0a,0x20,0x20,0x20,0x20, + 0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x76,0x75,0x76,0x20,0x3a,0x20,0x54,0x45,0x58, + 0x43,0x4f,0x4f,0x52,0x44,0x31,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61, + 0x74,0x34,0x20,0x76,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x54,0x45,0x58,0x43, + 0x4f,0x4f,0x52,0x44,0x32,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63, + 0x74,0x20,0x53,0x50,0x49,0x52,0x56,0x5f,0x43,0x72,0x6f,0x73,0x73,0x5f,0x4f,0x75, + 0x74,0x70,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74, + 0x34,0x20,0x66,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x54,0x45,0x58,0x43,0x4f, + 0x4f,0x52,0x44,0x30,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32, + 0x20,0x66,0x75,0x76,0x20,0x3a,0x20,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44,0x31, + 0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x67,0x6c,0x5f, + 0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3a,0x20,0x53,0x56,0x5f,0x50,0x6f, + 0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64, + 0x20,0x76,0x65,0x72,0x74,0x5f,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20, + 0x20,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d, + 0x20,0x6d,0x75,0x6c,0x28,0x66,0x6c,0x6f,0x61,0x74,0x34,0x28,0x76,0x70,0x6f,0x73, + 0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x30,0x2e,0x30,0x66,0x2c,0x20,0x31,0x2e,0x30, + 0x66,0x29,0x2c,0x20,0x5f,0x31,0x39,0x5f,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x69, + 0x6f,0x6e,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x63,0x6f,0x6c,0x6f,0x72,0x20, + 0x3d,0x20,0x76,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x75, + 0x76,0x20,0x3d,0x20,0x76,0x75,0x76,0x3b,0x0a,0x7d,0x0a,0x0a,0x53,0x50,0x49,0x52, + 0x56,0x5f,0x43,0x72,0x6f,0x73,0x73,0x5f,0x4f,0x75,0x74,0x70,0x75,0x74,0x20,0x6d, + 0x61,0x69,0x6e,0x28,0x53,0x50,0x49,0x52,0x56,0x5f,0x43,0x72,0x6f,0x73,0x73,0x5f, + 0x49,0x6e,0x70,0x75,0x74,0x20,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x70,0x75, + 0x74,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x76,0x70,0x6f,0x73,0x69,0x74,0x69, + 0x6f,0x6e,0x20,0x3d,0x20,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x70,0x75,0x74, + 0x2e,0x76,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x20,0x20,0x20,0x20, + 0x76,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x73,0x74,0x61,0x67,0x65,0x5f,0x69, + 0x6e,0x70,0x75,0x74,0x2e,0x76,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x20, + 0x20,0x76,0x75,0x76,0x20,0x3d,0x20,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x70, + 0x75,0x74,0x2e,0x76,0x75,0x76,0x3b,0x0a,0x20,0x20,0x20,0x20,0x76,0x65,0x72,0x74, + 0x5f,0x6d,0x61,0x69,0x6e,0x28,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x53,0x50,0x49, + 0x52,0x56,0x5f,0x43,0x72,0x6f,0x73,0x73,0x5f,0x4f,0x75,0x74,0x70,0x75,0x74,0x20, + 0x73,0x74,0x61,0x67,0x65,0x5f,0x6f,0x75,0x74,0x70,0x75,0x74,0x3b,0x0a,0x20,0x20, + 0x20,0x20,0x73,0x74,0x61,0x67,0x65,0x5f,0x6f,0x75,0x74,0x70,0x75,0x74,0x2e,0x67, + 0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x67,0x6c,0x5f, + 0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x20,0x20,0x20,0x20,0x73,0x74, + 0x61,0x67,0x65,0x5f,0x6f,0x75,0x74,0x70,0x75,0x74,0x2e,0x66,0x63,0x6f,0x6c,0x6f, + 0x72,0x20,0x3d,0x20,0x66,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x20,0x20, + 0x73,0x74,0x61,0x67,0x65,0x5f,0x6f,0x75,0x74,0x70,0x75,0x74,0x2e,0x66,0x75,0x76, + 0x20,0x3d,0x20,0x66,0x75,0x76,0x3b,0x0a,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75, + 0x72,0x6e,0x20,0x73,0x74,0x61,0x67,0x65,0x5f,0x6f,0x75,0x74,0x70,0x75,0x74,0x3b, + 0x0a,0x7d,0x0a,0x00, +} +/* + Texture2D tex : register(t0); + SamplerState tex_samp : register(s0); + + static float4 out_color; + static float2 fuv; + static float4 fcolor; + + struct SPIRV_Cross_Input + { + float4 fcolor : TEXCOORD0; + float2 fuv : TEXCOORD1; + }; + + struct SPIRV_Cross_Output + { + float4 out_color : SV_Target0; + }; + + void frag_main() + { + out_color = tex.Sample(tex_samp, fuv) * fcolor; + } + + SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) + { + fuv = stage_input.fuv; + fcolor = stage_input.fcolor; + frag_main(); + SPIRV_Cross_Output stage_output; + stage_output.out_color = out_color; + return stage_output; + } +*/ +@(private="file") +fs_source_hlsl5 := [614]u8 { + 0x54,0x65,0x78,0x74,0x75,0x72,0x65,0x32,0x44,0x3c,0x66,0x6c,0x6f,0x61,0x74,0x34, + 0x3e,0x20,0x74,0x65,0x78,0x20,0x3a,0x20,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72, + 0x28,0x74,0x30,0x29,0x3b,0x0a,0x53,0x61,0x6d,0x70,0x6c,0x65,0x72,0x53,0x74,0x61, + 0x74,0x65,0x20,0x74,0x65,0x78,0x5f,0x73,0x61,0x6d,0x70,0x20,0x3a,0x20,0x72,0x65, + 0x67,0x69,0x73,0x74,0x65,0x72,0x28,0x73,0x30,0x29,0x3b,0x0a,0x0a,0x73,0x74,0x61, + 0x74,0x69,0x63,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x6f,0x75,0x74,0x5f,0x63, + 0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x66,0x6c,0x6f, + 0x61,0x74,0x32,0x20,0x66,0x75,0x76,0x3b,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20, + 0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x66,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a, + 0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x53,0x50,0x49,0x52,0x56,0x5f,0x43,0x72,0x6f, + 0x73,0x73,0x5f,0x49,0x6e,0x70,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, + 0x6c,0x6f,0x61,0x74,0x34,0x20,0x66,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x54, + 0x45,0x58,0x43,0x4f,0x4f,0x52,0x44,0x30,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c, + 0x6f,0x61,0x74,0x32,0x20,0x66,0x75,0x76,0x20,0x3a,0x20,0x54,0x45,0x58,0x43,0x4f, + 0x4f,0x52,0x44,0x31,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74, + 0x20,0x53,0x50,0x49,0x52,0x56,0x5f,0x43,0x72,0x6f,0x73,0x73,0x5f,0x4f,0x75,0x74, + 0x70,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34, + 0x20,0x6f,0x75,0x74,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x53,0x56,0x5f, + 0x54,0x61,0x72,0x67,0x65,0x74,0x30,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x76,0x6f,0x69, + 0x64,0x20,0x66,0x72,0x61,0x67,0x5f,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a, + 0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20, + 0x74,0x65,0x78,0x2e,0x53,0x61,0x6d,0x70,0x6c,0x65,0x28,0x74,0x65,0x78,0x5f,0x73, + 0x61,0x6d,0x70,0x2c,0x20,0x66,0x75,0x76,0x29,0x20,0x2a,0x20,0x66,0x63,0x6f,0x6c, + 0x6f,0x72,0x3b,0x0a,0x7d,0x0a,0x0a,0x53,0x50,0x49,0x52,0x56,0x5f,0x43,0x72,0x6f, + 0x73,0x73,0x5f,0x4f,0x75,0x74,0x70,0x75,0x74,0x20,0x6d,0x61,0x69,0x6e,0x28,0x53, + 0x50,0x49,0x52,0x56,0x5f,0x43,0x72,0x6f,0x73,0x73,0x5f,0x49,0x6e,0x70,0x75,0x74, + 0x20,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x70,0x75,0x74,0x29,0x0a,0x7b,0x0a, + 0x20,0x20,0x20,0x20,0x66,0x75,0x76,0x20,0x3d,0x20,0x73,0x74,0x61,0x67,0x65,0x5f, + 0x69,0x6e,0x70,0x75,0x74,0x2e,0x66,0x75,0x76,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66, + 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e, + 0x70,0x75,0x74,0x2e,0x66,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x20,0x20, + 0x66,0x72,0x61,0x67,0x5f,0x6d,0x61,0x69,0x6e,0x28,0x29,0x3b,0x0a,0x20,0x20,0x20, + 0x20,0x53,0x50,0x49,0x52,0x56,0x5f,0x43,0x72,0x6f,0x73,0x73,0x5f,0x4f,0x75,0x74, + 0x70,0x75,0x74,0x20,0x73,0x74,0x61,0x67,0x65,0x5f,0x6f,0x75,0x74,0x70,0x75,0x74, + 0x3b,0x0a,0x20,0x20,0x20,0x20,0x73,0x74,0x61,0x67,0x65,0x5f,0x6f,0x75,0x74,0x70, + 0x75,0x74,0x2e,0x6f,0x75,0x74,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x6f, + 0x75,0x74,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x20,0x20,0x72,0x65, + 0x74,0x75,0x72,0x6e,0x20,0x73,0x74,0x61,0x67,0x65,0x5f,0x6f,0x75,0x74,0x70,0x75, + 0x74,0x3b,0x0a,0x7d,0x0a,0x00, +} +/* + #include + #include + + using namespace metal; + + struct default_vs_params + { + float4x4 projection; + }; + + struct main0_out + { + float4 fcolor [[user(locn0)]]; + float2 fuv [[user(locn1)]]; + float4 gl_Position [[position]]; + }; + + struct main0_in + { + float2 vposition [[attribute(0)]]; + float2 vuv [[attribute(1)]]; + float4 vcolor [[attribute(2)]]; + }; + + vertex main0_out main0(main0_in in [[stage_in]], constant default_vs_params& _19 [[buffer(0)]]) + { + main0_out out = {}; + out.gl_Position = _19.projection * float4(in.vposition, 0.0, 1.0); + out.fcolor = in.vcolor; + out.fuv = in.vuv; + return out; + } + +*/ +@(private="file") +vs_source_metal_macos := [648]u8 { + 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, + 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, + 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, + 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, + 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x64, + 0x65,0x66,0x61,0x75,0x6c,0x74,0x5f,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73, + 0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x78,0x34,0x20, + 0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a, + 0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74, + 0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x66,0x63, + 0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e, + 0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32, + 0x20,0x66,0x75,0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e, + 0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34, + 0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x5b,0x5b,0x70, + 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x73, + 0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x0a,0x7b, + 0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x76,0x70,0x6f,0x73, + 0x69,0x74,0x69,0x6f,0x6e,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74, + 0x65,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61, + 0x74,0x32,0x20,0x76,0x75,0x76,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75, + 0x74,0x65,0x28,0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f, + 0x61,0x74,0x34,0x20,0x76,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x61,0x74,0x74, + 0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x32,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a, + 0x0a,0x76,0x65,0x72,0x74,0x65,0x78,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75, + 0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e, + 0x20,0x69,0x6e,0x20,0x5b,0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d, + 0x2c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x64,0x65,0x66,0x61,0x75, + 0x6c,0x74,0x5f,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x26,0x20,0x5f,0x31, + 0x39,0x20,0x5b,0x5b,0x62,0x75,0x66,0x66,0x65,0x72,0x28,0x30,0x29,0x5d,0x5d,0x29, + 0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74, + 0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f, + 0x75,0x74,0x2e,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d, + 0x20,0x5f,0x31,0x39,0x2e,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x69,0x6f,0x6e,0x20, + 0x2a,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x28,0x69,0x6e,0x2e,0x76,0x70,0x6f,0x73, + 0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x29, + 0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x66,0x63,0x6f,0x6c,0x6f,0x72, + 0x20,0x3d,0x20,0x69,0x6e,0x2e,0x76,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20, + 0x20,0x20,0x6f,0x75,0x74,0x2e,0x66,0x75,0x76,0x20,0x3d,0x20,0x69,0x6e,0x2e,0x76, + 0x75,0x76,0x3b,0x0a,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f, + 0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, +} +/* + #include + #include + + using namespace metal; + + struct main0_out + { + float4 out_color [[color(0)]]; + }; + + struct main0_in + { + float4 fcolor [[user(locn0)]]; + float2 fuv [[user(locn1)]]; + }; + + fragment main0_out main0(main0_in in [[stage_in]], texture2d tex [[texture(0)]], sampler tex_samp [[sampler(0)]]) + { + main0_out out = {}; + out.out_color = tex.sample(tex_samp, in.fuv) * in.fcolor; + return out; + } + +*/ +@(private="file") +fs_source_metal_macos := [448]u8 { + 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, + 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, + 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, + 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, + 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d, + 0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, + 0x6c,0x6f,0x61,0x74,0x34,0x20,0x6f,0x75,0x74,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20, + 0x5b,0x5b,0x63,0x6f,0x6c,0x6f,0x72,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b, + 0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69, + 0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x66, + 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63, + 0x6e,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74, + 0x32,0x20,0x66,0x75,0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63, + 0x6e,0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x66,0x72,0x61,0x67,0x6d, + 0x65,0x6e,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61, + 0x69,0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20, + 0x5b,0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c,0x20,0x74,0x65, + 0x78,0x74,0x75,0x72,0x65,0x32,0x64,0x3c,0x66,0x6c,0x6f,0x61,0x74,0x3e,0x20,0x74, + 0x65,0x78,0x20,0x5b,0x5b,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x30,0x29,0x5d, + 0x5d,0x2c,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x20,0x74,0x65,0x78,0x5f,0x73, + 0x61,0x6d,0x70,0x20,0x5b,0x5b,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x28,0x30,0x29, + 0x5d,0x5d,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f, + 0x6f,0x75,0x74,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20, + 0x20,0x20,0x6f,0x75,0x74,0x2e,0x6f,0x75,0x74,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20, + 0x3d,0x20,0x74,0x65,0x78,0x2e,0x73,0x61,0x6d,0x70,0x6c,0x65,0x28,0x74,0x65,0x78, + 0x5f,0x73,0x61,0x6d,0x70,0x2c,0x20,0x69,0x6e,0x2e,0x66,0x75,0x76,0x29,0x20,0x2a, + 0x20,0x69,0x6e,0x2e,0x66,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x20,0x20, + 0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, + +} +default_shader_desc :: proc (backend: sg.Backend) -> sg.Shader_Desc { + desc: sg.Shader_Desc + desc.label = "default_shader" + #partial switch backend { + case .GLCORE: + desc.vertex_func.source = transmute(cstring)&vs_source_glsl430 + desc.vertex_func.entry = "main" + desc.fragment_func.source = transmute(cstring)&fs_source_glsl430 + desc.fragment_func.entry = "main" + desc.attrs[0].base_type = .FLOAT + desc.attrs[0].glsl_name = "vposition" + desc.attrs[1].base_type = .FLOAT + desc.attrs[1].glsl_name = "vuv" + desc.attrs[2].base_type = .FLOAT + desc.attrs[2].glsl_name = "vcolor" + desc.uniform_blocks[0].stage = .VERTEX + desc.uniform_blocks[0].layout = .STD140 + desc.uniform_blocks[0].size = 64 + desc.uniform_blocks[0].glsl_uniforms[0].type = .FLOAT4 + desc.uniform_blocks[0].glsl_uniforms[0].array_count = 4 + desc.uniform_blocks[0].glsl_uniforms[0].glsl_name = "default_vs_params" + desc.views[0].texture.stage = .FRAGMENT + desc.views[0].texture.image_type = ._2D + desc.views[0].texture.sample_type = .FLOAT + desc.views[0].texture.multisampled = false + desc.samplers[0].stage = .FRAGMENT + desc.samplers[0].sampler_type = .FILTERING + desc.texture_sampler_pairs[0].stage = .FRAGMENT + desc.texture_sampler_pairs[0].view_slot = 0 + desc.texture_sampler_pairs[0].sampler_slot = 0 + desc.texture_sampler_pairs[0].glsl_name = "tex_tex_samp" + case .D3D11: + desc.vertex_func.source = transmute(cstring)&vs_source_hlsl5 + desc.vertex_func.d3d11_target = "vs_5_0" + desc.vertex_func.entry = "main" + desc.fragment_func.source = transmute(cstring)&fs_source_hlsl5 + desc.fragment_func.d3d11_target = "ps_5_0" + desc.fragment_func.entry = "main" + desc.attrs[0].base_type = .FLOAT + desc.attrs[0].hlsl_sem_name = "TEXCOORD" + desc.attrs[0].hlsl_sem_index = 0 + desc.attrs[1].base_type = .FLOAT + desc.attrs[1].hlsl_sem_name = "TEXCOORD" + desc.attrs[1].hlsl_sem_index = 1 + desc.attrs[2].base_type = .FLOAT + desc.attrs[2].hlsl_sem_name = "TEXCOORD" + desc.attrs[2].hlsl_sem_index = 2 + desc.uniform_blocks[0].stage = .VERTEX + desc.uniform_blocks[0].layout = .STD140 + desc.uniform_blocks[0].size = 64 + desc.uniform_blocks[0].hlsl_register_b_n = 0 + desc.views[0].texture.stage = .FRAGMENT + desc.views[0].texture.image_type = ._2D + desc.views[0].texture.sample_type = .FLOAT + desc.views[0].texture.multisampled = false + desc.views[0].texture.hlsl_register_t_n = 0 + desc.samplers[0].stage = .FRAGMENT + desc.samplers[0].sampler_type = .FILTERING + desc.samplers[0].hlsl_register_s_n = 0 + desc.texture_sampler_pairs[0].stage = .FRAGMENT + desc.texture_sampler_pairs[0].view_slot = 0 + desc.texture_sampler_pairs[0].sampler_slot = 0 + case .METAL_MACOS: + desc.vertex_func.source = transmute(cstring)&vs_source_metal_macos + desc.vertex_func.entry = "main0" + desc.fragment_func.source = transmute(cstring)&fs_source_metal_macos + desc.fragment_func.entry = "main0" + desc.attrs[0].base_type = .FLOAT + desc.attrs[1].base_type = .FLOAT + desc.attrs[2].base_type = .FLOAT + desc.uniform_blocks[0].stage = .VERTEX + desc.uniform_blocks[0].layout = .STD140 + desc.uniform_blocks[0].size = 64 + desc.uniform_blocks[0].msl_buffer_n = 0 + desc.views[0].texture.stage = .FRAGMENT + desc.views[0].texture.image_type = ._2D + desc.views[0].texture.sample_type = .FLOAT + desc.views[0].texture.multisampled = false + desc.views[0].texture.msl_texture_n = 0 + desc.samplers[0].stage = .FRAGMENT + desc.samplers[0].sampler_type = .FILTERING + desc.samplers[0].msl_sampler_n = 0 + desc.texture_sampler_pairs[0].stage = .FRAGMENT + desc.texture_sampler_pairs[0].view_slot = 0 + desc.texture_sampler_pairs[0].sampler_slot = 0 + } + return desc +} diff --git a/src/draw/draw.odin b/src/draw/draw.odin new file mode 100644 index 0000000..2e7eaaf --- /dev/null +++ b/src/draw/draw.odin @@ -0,0 +1,284 @@ +package draw + +import "core:fmt" +import "core:math/linalg" +import "core:math" + +import sg "shared:sokol/gfx" +import sapp "shared:sokol/app" +import sglue "shared:sokol/glue" + +Vec2 :: [2]f32 +Vec3 :: [3]f32 +Mat4 :: matrix[4, 4]f32 + +Rect :: struct { + start: Vec2, + size: Vec2, +} + +Color :: [4]f32 + +SCREEN_WIDTH :: 256 +SCREEN_HEIGHT :: 256 + +Renderer :: struct { + screen: struct { + framebuffer: Framebuffer, + vertex_buffer: sg.Buffer, + }, + display: struct { + pass_action: sg.Pass_Action, + pipe: sg.Pipeline, + binds: sg.Bindings, + }, + + view: sg.View, + sampler: sg.Sampler, + + projection: Mat4, + current_batch: Batch, + + tint: Color, +} + +Vertex :: struct { + pos: Vec2, + uv: Vec2, + color: Color, +} + +Batch :: struct { + img: sg.Image, + vertices: [dynamic]Vertex, +} + +init :: proc(r: ^Renderer) { + r.display.pipe = sg.make_pipeline({ + shader = sg.make_shader(default_shader_desc(sg.query_backend())), + layout = { + attrs = { + ATTR_default_vposition = {format = .FLOAT2}, + ATTR_default_vuv = {format = .FLOAT2}, + ATTR_default_vcolor = {format = .FLOAT4}, + }, + }, + }) + + r.display.pass_action = { + colors = { + 0 = {load_action = .CLEAR, clear_value = {0, 0, 0, 1}}, + }, + } + + init_framebuffer( + &r.screen.framebuffer, + SCREEN_WIDTH, SCREEN_HEIGHT, + Color{0.2, 0.2, 0.2, 1.0}, + ) + + r.screen.vertex_buffer = sg.make_buffer({ + size = size_of(Vertex) * 6, + usage = { + vertex_buffer = true, + immutable = false, + stream_update = true, + }, + }) + + r.view = sg.alloc_view() + r.sampler = sg.make_sampler({}) + + r.display.binds.vertex_buffers[0] = r.screen.vertex_buffer + r.display.binds.views[VIEW_tex] = r.screen.framebuffer.view + r.display.binds.samplers[SMP_tex_samp] = r.sampler + + r.tint = {1, 1, 1, 1} +} + +deinit :: proc(r: ^Renderer) { + delete_batch(&r.current_batch) + + sg.destroy_pipeline(r.screen.framebuffer.pipe) + sg.destroy_pipeline(r.display.pipe) + + sg.destroy_view(r.view) + sg.destroy_sampler(r.sampler) + + sg.destroy_buffer(r.screen.vertex_buffer) + destroy_framebuffer(&r.screen.framebuffer) +} + +new_frame :: proc(r: ^Renderer) { + framebuffer_draw_start(r.screen.framebuffer) + r.projection = linalg.matrix_ortho3d( + 0, f32(SCREEN_WIDTH), + f32(SCREEN_HEIGHT), 0, + 0.0, 1.0, + ) +} + +end_frame :: proc(r: ^Renderer) { + flush_current_batch(r) + clear(&r.current_batch.vertices) + + framebuffer_draw_end(r.screen.framebuffer) + + r.projection = linalg.matrix_ortho3d( + 0, f32(sapp.width()), + 0, f32(sapp.height()), + 0.0, 1.0, + ) + + sg.begin_pass({action=r.display.pass_action, swapchain=sglue.swapchain()}) + sg.apply_pipeline(r.display.pipe) + + scale := math.min( + f32(sapp.height()) / f32(SCREEN_HEIGHT) , + f32(sapp.width()) / f32(SCREEN_WIDTH), + ) + screen_start := Vec2{ + (f32(sapp.width()) - (SCREEN_WIDTH * scale)) / 2, + (f32(sapp.height()) - (SCREEN_HEIGHT * scale)) / 2, + } + + draw_texture( + r, + r.screen.framebuffer.img, + screen_start, + scale = Vec2{scale, scale}, + ) + + flush_current_batch(r) + clear(&r.current_batch.vertices) + + sg.end_pass() + + sg.commit() +} + +@(private) +delete_batch :: proc(batch: ^Batch) { + delete(batch.vertices) +} + +flush_current_batch :: proc(r: ^Renderer) { + batch := r.current_batch + + if len(batch.vertices) == 0 { + return + } + + buffer := sg.make_buffer({ + data = { + ptr = &r.current_batch.vertices[0], + size = size_of(Vertex) * len(r.current_batch.vertices), + }, + }) + + sg.init_view(r.view, { + texture = { + image = r.current_batch.img, + }, + }) + + binds: sg.Bindings + + binds.vertex_buffers[0] = buffer + binds.views[VIEW_tex] = r.view + binds.samplers[SMP_tex_samp] = r.sampler + + uniforms := Default_Vs_Params { + projection = transmute([16]f32)r.projection, + } + + sg.apply_bindings(binds) + sg.apply_uniforms(UB_default_vs_params, {ptr=&uniforms, size=size_of(uniforms)}) + + sg.draw(0, len(r.current_batch.vertices), 1) + + sg.uninit_view(r.view) + + sg.destroy_buffer(buffer) +} + +@(private) +new_batch :: proc(batch: ^Batch, img: sg.Image) { + clear(&batch.vertices) + batch.img = img +} + +request_batch :: proc(r: ^Renderer, img: sg.Image) -> ^Batch { + if len(r.current_batch.vertices) == 0 { + new_batch(&r.current_batch, img) + } else if img != r.current_batch.img { + flush_current_batch(r) + new_batch(&r.current_batch, img) + } + + return &r.current_batch +} + +@(private) +batch_vertices :: proc( + b: ^Batch, + vertices: []Vertex, +) { + append(&b.vertices, ..vertices) +} + +draw_texture :: proc{ + draw_texture_full, + draw_texture_quad, +} + +draw_texture_quad :: proc( + r: ^Renderer, + img: sg.Image, + quad: Rect, + pos: Vec2, + offset := Vec2{0, 0}, + scale := Vec2{1, 1}, +) { + assert(quad.size.x > 0 && quad.size.y > 0) + + batch := request_batch(r, img) + + top_left := pos - (offset * scale) + bot_rght := top_left + quad.size * scale + + size := Vec2{ + f32(sg.query_image_width(img)), + f32(sg.query_image_height(img)), + } + + uv_start := quad.start / size + uv_end := (quad.start + quad.size) / size + + // |/| + vertices := [?]Vertex{ + {top_left, uv_start, r.tint}, + {{bot_rght.x, top_left.y}, {uv_end.x, uv_start.y}, r.tint}, + {{top_left.x, bot_rght.y}, {uv_start.x, uv_end.y }, r.tint}, + + {{bot_rght.x, top_left.y}, {uv_end.x, uv_start.y}, r.tint}, + {{top_left.x, bot_rght.y}, {uv_start.x, uv_end.y }, r.tint}, + {bot_rght, uv_end, r.tint}, + } + + batch_vertices(batch, vertices[:]) +} + +draw_texture_full :: proc( + r: ^Renderer, + img: sg.Image, + pos: Vec2, + offset := Vec2{0, 0}, + scale := Vec2{1, 1}, +) { + size := Vec2{ + f32(sg.query_image_width(img)), + f32(sg.query_image_height(img)), + } + draw_texture_quad(r, img, Rect{Vec2{0, 0}, size}, pos, offset, scale) +} diff --git a/src/draw/framebuffer.odin b/src/draw/framebuffer.odin new file mode 100644 index 0000000..cd7848b --- /dev/null +++ b/src/draw/framebuffer.odin @@ -0,0 +1,94 @@ +package draw + +import sg "shared:sokol/gfx" + +Framebuffer :: struct { + img: sg.Image, + view: sg.View, + pipe: sg.Pipeline, + pass: sg.Pass, +} + +init_framebuffer :: proc( + fb: ^Framebuffer, + width: i32, + height: i32, + clear_color := Color{0, 0, 0, 0}, +) { + fb.pipe = sg.make_pipeline({ + shader = sg.make_shader(default_shader_desc(sg.query_backend())), + layout = { + attrs = { + ATTR_default_vposition = {format = .FLOAT2}, + ATTR_default_vuv = {format = .FLOAT2}, + ATTR_default_vcolor = {format = .FLOAT4}, + }, + }, + depth = { + pixel_format = .NONE, + }, + sample_count = 1, + colors = { + 0 = { + pixel_format = .RGBA8, + blend = { + enabled = true, + src_factor_rgb = .SRC_ALPHA, + dst_factor_rgb = .ONE_MINUS_SRC_ALPHA, + src_factor_alpha = .ONE, + dst_factor_alpha = .ZERO, + }, + }, + }, + }) + + fb.img = sg.make_image({ + usage = { + color_attachment = true, + }, + + width = width, + height = height, + + pixel_format = .RGBA8, + sample_count = 1, + }) + + fb.view = sg.make_view({ + texture = { + image = fb.img, + }, + }) + + fb.pass = { + attachments = { + colors = { + 0 = sg.make_view({ + color_attachment = { + image = fb.img, + }, + }), + }, + }, + action = { + colors = { + 0 = {load_action = .CLEAR, clear_value = transmute(sg.Color)clear_color}, + }, + }, + } +} + +destroy_framebuffer :: proc(fb: ^Framebuffer) { + sg.destroy_pipeline(fb.pipe) + sg.destroy_view(fb.view) + sg.destroy_image(fb.img) +} + +framebuffer_draw_start :: proc(fb: Framebuffer) { + sg.begin_pass(fb.pass) + sg.apply_pipeline(fb.pipe) +} + +framebuffer_draw_end :: proc(fb: Framebuffer) { + sg.end_pass() +} diff --git a/src/draw/sprite.odin b/src/draw/sprite.odin new file mode 100644 index 0000000..e62f650 --- /dev/null +++ b/src/draw/sprite.odin @@ -0,0 +1,88 @@ +package draw + +import "core:fmt" +import "core:image" +import "core:image/qoi" + +import sg "shared:sokol/gfx" + +Sprite :: struct { + image: sg.Image, + anim: Animation, + active_anim: u32, + frame_time: f32, + current_frame: i32, +} + +init_sprite :: proc( + sprite: ^Sprite, + path: string, + anim: Animation = {}, +) -> bool { + fmt.println(path) + img, img_err := qoi.load_from_file(path) + if img_err != nil { + fmt.println("could not load image") + return false + } + defer image.destroy(img) + + sprite.image = sg.make_image({ + width = i32(img.width), + height = i32(img.height), + data = { + mip_levels = { + 0 = {ptr=&img.pixels.buf[0], size=len(img.pixels.buf)}, + }, + }, + }) + sprite.anim = anim + + return true +} + +set_sprite_active_tag :: proc(sprite: ^Sprite, tag_name: string) { + sprite.active_anim = sprite.anim.frame_tags_indices[tag_name] +} + +update_sprite :: proc(sprite: ^Sprite, dt: f32) { + sprite.frame_time += dt + + tag := sprite.anim.frame_tags[sprite.active_anim] + frame := sprite.anim.frames[sprite.current_frame] + duration := f32(frame.duration) / 1000 + + if sprite.frame_time > duration { + sprite.frame_time -= duration + sprite.current_frame += 1 + } + + if sprite.current_frame < tag.from { + sprite.current_frame = tag.to + } + if sprite.current_frame > tag.to { + sprite.current_frame = tag.from + } +} + +draw_sprite :: proc( + r: ^Renderer, + sprite: Sprite, + pos: Vec2, + offset := Vec2{0, 0}, + scale := Vec2{1, 1}, +) { + frame := sprite.anim.frames[sprite.current_frame] + + draw_texture( + r, + sprite.image, + Rect { + Vec2{f32(frame.rect.x), f32(frame.rect.y)}, + Vec2{f32(frame.rect.w), f32(frame.rect.h)}, + }, + pos, + offset, + scale, + ) +} diff --git a/src/entity_list.odin b/src/entity_list.odin new file mode 100644 index 0000000..4890d2c --- /dev/null +++ b/src/entity_list.odin @@ -0,0 +1,81 @@ +package demonchime + +// import "core:math" + +Entity_Handle :: struct { + idx: u32, + uses: u32, +} + +Entity_List :: struct($T: typeid) { + items: [dynamic]T, + holes: [dynamic]Entity_Handle, +} + +delete_entity_list :: proc(list: Entity_List($T)) { + delete(list.items) + delete(list.holes) +} + +make_entity :: proc(list: ^Entity_List($T), ent: T) -> (Entity_Handle, ^T) { + handle: Entity_Handle + + if len(list.holes) > 0 { + handle = pop(&list.holes) + handle.uses += 1 + } else { + // because index 0 in a handle is considered a null handle + resize(&list.items, math.max(2, len(list.items) + 1)) + handle.idx = u32(len(list.items) - 1) + handle.uses = 1 + } + + list.items[handle.idx] = ent + list.items[handle.idx].handle = handle + return handle, &list.items[handle.idx] +} + +delete_entity :: proc(list: ^Entity_List($T), handle: Entity_Handle) { + if handle.idx <= 0 || int(handle.idx) >= len(list.items) { + return + } + if list.items[handle.idx].handle != handle { + return + } + + append(&list.holes, handle) + list.items[handle.idx] = {} +} + +get_entity :: proc(list: Entity_List($T), h: Entity_Handle) -> ^T { + if h.idx < 1 || h.idx >= len(list.items) || list.items[h.idx].handle == h { + return nil + } + return &list.items[h.idx] +} + +active_entity_count :: proc(list: Entity_List($T)) -> int { + // - 1 because there's an empty slot at the beginning + return len(list.items) - len(list.holes) - 1 +} + +Entity_List_Iter :: struct($T: typeid) { + list: Entity_List(T), + idx: int, +} + +iter_entity_list :: proc(list: Entity_List($T)) -> Entity_List_Iter(T) { + return Entity_List_Iter(T) { list = list } +} + +entity_list_iter :: proc(it: ^Entity_List_Iter($T)) -> (^T, bool) { + for it.idx < len(it.list.items) { + if it.list.items[it.idx].handle.idx > 0 { + entity := &it.list.items[it.idx] + it.idx += 1 + return entity, true + } + it.idx += 1 + } + return nil, false +} diff --git a/src/input.odin b/src/input.odin new file mode 100644 index 0000000..0dad408 --- /dev/null +++ b/src/input.odin @@ -0,0 +1,60 @@ +package demonchime + +import sapp "shared:sokol/app" + +KeybindInput :: union { + sapp.Keycode, + sapp.Mousebutton, +} + +Keybind :: struct { + input: KeybindInput, + pressed: bool, + just_pressed: bool, +} + +Input :: struct { + move_up: Keybind, + move_left: Keybind, + move_down: Keybind, + move_right: Keybind, + + key_down: [sapp.MAX_KEYCODES]bool, + key_just_down: [sapp.MAX_KEYCODES]bool, + mouse_down: [sapp.MAX_MOUSEBUTTONS]bool, + mouse_just_down: [sapp.MAX_MOUSEBUTTONS]bool, +} + +init_keybinds :: proc(input: ^Input) { + input.move_up.input = sapp.Keycode.W + input.move_left.input = sapp.Keycode.A + input.move_down.input = sapp.Keycode.S + input.move_right.input = sapp.Keycode.D +} + +input_event :: proc(event: ^sapp.Event, input: ^Input) { + #partial switch event.type { + case .KEY_DOWN: + input.key_down[event.key_code] = true + input.key_just_down[event.key_code] = true + case .KEY_UP: + input.key_down[event.key_code] = false + case .MOUSE_DOWN: + input.mouse_down[event.key_code] = true + input.mouse_just_down[event.key_code] = true + case .MOUSE_UP: + input.mouse_down[event.key_code] = false + } +} + +is_keybind_down :: proc(input: Input, keybind: Keybind) -> bool { + switch val in keybind.input { + case sapp.Keycode: + return input.key_down[val] + case sapp.Mousebutton: + return input.mouse_down[val] + } + + assert(false) + return false +} diff --git a/src/main.odin b/src/main.odin new file mode 100644 index 0000000..41af6e3 --- /dev/null +++ b/src/main.odin @@ -0,0 +1,80 @@ +package demonchime + +// import "core:math" +// import "core:math/rand" +// import "core:time" + +import "base:runtime" + +import sg "shared:sokol/gfx" +import sapp "shared:sokol/app" +import sglue "shared:sokol/glue" +import slog "shared:sokol/log" + +import "draw" + +Vec2 :: [2]f32 + +state: struct { + player: Player, + + renderer: draw.Renderer, + + input: Input, +} + +init :: proc "c" () { + context = runtime.default_context() + + sg.setup({ + environment = sglue.environment(), + logger = {func=slog.func}, + }) + + init_keybinds(&state.input) + + draw.init(&state.renderer) + + init_player(&state.player) +} + +frame :: proc "c" () { + context = runtime.default_context() + + update_player(&state.player, f32(sapp.frame_duration())) + + draw.new_frame(&state.renderer) + + draw_player(state.player) + + draw.end_frame(&state.renderer) +} + +event :: proc "c" (event: ^sapp.Event) { + context = runtime.default_context() + + if event.type == .KEY_DOWN && event.key_code == .ESCAPE { + sapp.quit() + } + + input_event(event, &state.input) +} + +cleanup :: proc "c" () { + context = runtime.default_context() + sg.shutdown() +} + +main :: proc() { + sapp.run({ + init_cb = init, + frame_cb = frame, + event_cb = event, + cleanup_cb = cleanup, + width = 800, + height = 600, + window_title = "Demonchime", + icon = {sokol_default = true}, + logger = {func=slog.func}, + }) +} diff --git a/src/player.odin b/src/player.odin new file mode 100644 index 0000000..01bc02b --- /dev/null +++ b/src/player.odin @@ -0,0 +1,68 @@ +package demonchime + +import "core:fmt" +import "core:math" +import "core:math/linalg" + +import sapp "shared:sokol/app" + +import "draw" + +Player :: struct { + pos: Vec2, + anim: draw.Animation, + sprite: draw.Sprite, +} + +init_player :: proc(player: ^Player) { + anim_ok := draw.init_anim_data(&player.anim, "res/robot2.json") + if !anim_ok { + fmt.println("coult not load animation") + sapp.quit() + return + } + + draw.init_sprite(&player.sprite, player.anim.image_path, player.anim) +} + +deinit_player :: proc(player: ^Player) { + draw.delete_anim_data(player.anim) +} + +update_player :: proc(player: ^Player, dt: f32) { + SPEED :: 100 + + input: Vec2 + + if is_keybind_down(state.input, state.input.move_up) { + input.y -= 1 + } + if is_keybind_down(state.input, state.input.move_left) { + input.x -= 1 + } + if is_keybind_down(state.input, state.input.move_down) { + input.y += 1 + } + if is_keybind_down(state.input, state.input.move_right) { + input.x += 1 + } + + if linalg.length2(input) > 0 { + input = linalg.normalize(input) + draw.set_sprite_active_tag(&player.sprite, "down_run") + } else { + draw.set_sprite_active_tag(&player.sprite, "down_idle") + } + + player.pos += input * SPEED * dt + + draw.update_sprite(&player.sprite, dt) +} + +draw_player :: proc(player: Player) { + draw.draw_sprite( + &state.renderer, + player.sprite, + player.pos, + ) +} -- cgit v1.3-2-g0d8e