aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorXander Swan <email>2025-12-03 09:52:13 -0500
committerXander Swan <email>2025-12-03 09:52:13 -0500
commitb6cf1d104da53ec9c30dc45c35d9de48812f0afc (patch)
tree49421206d8d866e82a8a743cba5ced494cbfc785 /src
Initial commit
Diffstat (limited to 'src')
-rw-r--r--src/draw/animation.odin84
-rw-r--r--src/draw/default.glsl38
-rw-r--r--src/draw/default_shader.odin538
-rw-r--r--src/draw/draw.odin284
-rw-r--r--src/draw/framebuffer.odin94
-rw-r--r--src/draw/sprite.odin88
-rw-r--r--src/entity_list.odin81
-rw-r--r--src/input.odin60
-rw-r--r--src/main.odin80
-rw-r--r--src/player.odin68
10 files changed, 1415 insertions, 0 deletions
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<float4> 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 <metal_stdlib>
+ #include <simd/simd.h>
+
+ 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 <metal_stdlib>
+ #include <simd/simd.h>
+
+ 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<float> 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,
+ )
+}