From 3d1d31538d30a7f161f9f2b6d5e075ec69d3b860 Mon Sep 17 00:00:00 2001 From: iamcheeseman <[hidden email]> Date: Tue, 3 Feb 2026 22:25:00 -0500 Subject: ditch raylib (icky, and for loser BEGINNERS) --- src.bin | Bin 0 -> 841400 bytes src/assets.odin | 12 +- src/draw.odin | 151 ------------------- src/fw/fw.odin | 114 ++++++++++++++ src/fw/input.odin | 76 ++++++++++ src/fw/keys.odin | 140 +++++++++++++++++ src/fw/opengl.odin | 363 ++++++++++++++++++++++++++++++++++++++++++++ src/fw/renderer.odin | 390 ++++++++++++++++++++++++++++++++++++++++++++++++ src/fw/shader.frag | 16 ++ src/fw/shader.vert | 18 +++ src/input.odin | 72 ++------- src/main.odin | 207 ++++++++++++------------- src/math.odin | 4 +- src/phys/world.odin | 4 +- src/platform.odin | 10 +- src/player.odin | 28 ++-- src/prop.odin | 41 +++-- src/resources.odin | 26 ++-- src/rope.odin | 14 +- src/sprite.odin | 20 +-- src/tail.odin | 17 ++- src/upgrade_pickup.odin | 5 +- src/verlet.odin | 4 +- src/world.odin | 22 +-- 24 files changed, 1323 insertions(+), 431 deletions(-) create mode 100755 src.bin delete mode 100644 src/draw.odin create mode 100644 src/fw/fw.odin create mode 100644 src/fw/input.odin create mode 100644 src/fw/keys.odin create mode 100644 src/fw/opengl.odin create mode 100644 src/fw/renderer.odin create mode 100644 src/fw/shader.frag create mode 100644 src/fw/shader.vert diff --git a/src.bin b/src.bin new file mode 100755 index 0000000..6503854 Binary files /dev/null and b/src.bin differ diff --git a/src/assets.odin b/src/assets.odin index ada8a36..dd506a3 100644 --- a/src/assets.odin +++ b/src/assets.odin @@ -71,15 +71,15 @@ images: [Image_Id]Image_Resource = { animations: [Animation_Id]Animation_Resource = { .None = {frame_count=1, frame_durations={100}, tags={}}, - .Player = {frame_count = 23, frame_durations = {100, 100, 100, 100, 100, 100, 75, 75, 75, 75, 75, 75, 75, 75, 100, 100, 100, 100, 100, 100, 100, 100, 100}, tags = {"jump_up"={from = 14, to = 15}, "jump_down"={from = 17, to = 18}, "jump_trans"={from = 16, to = 16}, "sleep"={from = 19, to = 22}, "run"={from = 6, to = 13}, "idle"={from = 0, to = 5}}}, + .Player = {frame_count = 23, frame_durations = {100, 100, 100, 100, 100, 100, 75, 75, 75, 75, 75, 75, 75, 75, 100, 100, 100, 100, 100, 100, 100, 100, 100}, tags = {"jump_trans"={from = 16, to = 16}, "jump_down"={from = 17, to = 18}, "idle"={from = 0, to = 5}, "sleep"={from = 19, to = 22}, "jump_up"={from = 14, to = 15}, "run"={from = 6, to = 13}}}, } rooms: [Room_Id]Room_Resource = { - .Carrabassett0 = {width=40, height=20, tile_width=16, tile_height=16, layers={{40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 27, 31, 31, 19, 19, 28, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 21, 31, 31, 31, 11, 0, 0, 0, 0, 16, 19, 31, 28, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 27, 31, 19, 31, 19, 19, 19, 31, 19, 31, 19, 19, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 28, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 21, 31, 31, 31, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 40, 40, 21, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 31, 31, 31, 19, 19, 31, 40, 40, 21, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 20, 20, 18, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 19, 31, 19, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 21, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 18, 9, 9, 20, 9, 9, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 41, 9, 20, 20, 20, 18, 20, 20, 9, 20, 9, 20, 9, 20, 20, 9, 9, 18, 6, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 27, 17, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 32, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 17, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 43, 9, 9, 20, 20, 9, 39, 40, 40, 40, 40, 40, 40, 0, 0, 0, 0, 0, 5, 20, 20, 18, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 20, 9, 20, 18, 20, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40}}, objects={{type = .Prop, tile_id = 53, pos = {194, 200}, size = {26, 55}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {352, 200}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {412, 200}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {364, 200}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {172, 200}, size = {32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 46, pos = {224, 200}, size = {29, 14}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {220, 92}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {296, 92}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {340, 76}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {416, 60}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {492, 76}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {432, 76}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {352, 92}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {236, 108}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {80, 124}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {528, 100}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {472, 88}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {512, 96}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {60, 124}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {44, 148}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {24, 180}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {148, 96}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {260, 92}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {164, 88}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {128, 100}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {20, 280}, size = {32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {304, 200}, size = {32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {260, 200}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {284, 200}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {132, 248}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {96, 248}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {64, 280}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 52, pos = {116, 248}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 52, pos = {300, 200}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 52, pos = {448, 232}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {540, 152}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {612, 152}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {576, 152}, size = {32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {556, 124}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {572, 136}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {588, 124}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {580, 132}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {504, 80}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {424, 68}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {248, 100}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 53, pos = {484, 232}, size = {-26, 55}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {400, 172}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {412, 156}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {436, 172}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Rope, tile_id = nil, pos = {487, 185}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=6, "image"="res/img/windchimes_0.png", "node_length"=2}}, {type = .Rope, tile_id = nil, pos = {217, 153}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=6, "image"="res/img/small_lamp.png", "node_length"=2}}, {type = .Rope, tile_id = nil, pos = {515, 110}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=20, "image"="res/img/windchimes_0.png", "node_length"=5}}, {type = .Player_Spawn, tile_id = nil, pos = {240, 200}, size = {0, 0}, parallax = {0, 0}, properties = {}}, {type = .Collision, tile_id = nil, pos = {0, 0}, size = {48, 48}, parallax = {0, 0}, properties = {}}, }, background_color=Color{0, 0, 0, 1}, background_images={} }, - .Carrabassett1 = {width=20, height=20, tile_width=16, tile_height=16, layers={{40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 21, 31, 31, 31, 28, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 27, 31, 31, 17, 0, 0, 0, 16, 19, 28, 40, 40, 40, 40, 40, 40, 40, 27, 31, 31, 17, 0, 0, 0, 0, 0, 0, 0, 0, 16, 28, 40, 40, 40, 40, 40, 27, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 28, 40, 40, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 28, 40, 40, 40, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 21, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 38, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 28, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 40, 40, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 43, 9, 9, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 18, 20, 20, 40, 40, 40, 40, 40, 43, 9, 9, 9, 9, 9, 9, 18, 9, 18, 18, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40}}, objects={{type = .Prop, tile_id = 49, pos = {92, 296}, size = {32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 46, pos = {144, 296}, size = {29, 14}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 53, pos = {180, 296}, size = {-26, 55}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 53, pos = {116, 296}, size = {26, 55}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {127, 296}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {181, 296}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {224, 296}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {252, 296}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {292, 280}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {48, 280}, size = {32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {80, 104}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {88, 100}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {100, 96}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {108, 88}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {116, 88}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {96, 96}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {192, 76}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {272, 128}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {244, 100}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {228, 72}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {264, 104}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {284, 128}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {40, 108}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {56, 92}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {68, 108}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {24, 172}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 52, pos = {272, 280}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {24, 200}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Rope, tile_id = nil, pos = {139, 249}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=6, "image"="res/img/windchimes_1.png", "node_length"=2}}, {type = .Rope, tile_id = nil, pos = {183, 249}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=6, "image"="res/img/windchimes_1.png", "node_length"=2}}, {type = .Rope, tile_id = nil, pos = {134, 48}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=15, "image"="res/img/windchimes_0.png", "node_length"=7}}, {type = .Rope, tile_id = nil, pos = {232, 47}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=15, "image"="res/img/windchimes_0.png", "node_length"=5}}, {type = .Rope, tile_id = nil, pos = {70, 59}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=15, "image"="res/img/windchimes_1.png", "node_length"=10}}, {type = .Rope, tile_id = nil, pos = {174, 32}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=15, "image"="res/img/windchimes_1.png", "node_length"=10}}, {type = .Rope, tile_id = nil, pos = {269, 72}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=15, "image"="res/img/windchimes_1.png", "node_length"=10}}, {type = .Rope, tile_id = nil, pos = {206, 30}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=15, "image"="res/img/windchimes_0.png", "node_length"=8}}, {type = .Rope, tile_id = nil, pos = {115, 45}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=15, "image"="res/img/small_lamp.png", "node_length"=5}}, {type = .Rope, tile_id = nil, pos = {91, 61}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=15, "image"="res/img/small_lamp.png", "node_length"=5}}, {type = .Rope, tile_id = nil, pos = {191, 31}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=15, "image"="res/img/small_lamp.png", "node_length"=5}}, {type = .Rope, tile_id = nil, pos = {286, 86}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=15, "image"="res/img/small_lamp.png", "node_length"=5}}, {type = .Upgrade, tile_id = nil, pos = {160, 240}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/dash_pickup.qoi", "type"=0}}, }, background_color=Color{0, 0, 0, 1}, background_images={} }, - .Carrabassett2 = {width=20, height=20, tile_width=16, tile_height=16, layers={{40, 40, 40, 8, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 8, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 8, 0, 0, 10, 31, 31, 28, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 38, 20, 42, 0, 0, 0, 10, 19, 19, 28, 40, 40, 40, 40, 40, 40, 40, 40, 27, 31, 19, 28, 38, 18, 6, 0, 0, 0, 0, 10, 19, 28, 40, 40, 40, 40, 40, 27, 17, 0, 0, 10, 28, 40, 38, 20, 42, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 17, 0, 0, 0, 0, 16, 19, 31, 19, 17, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 39, 40, 40, 40, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 18, 9, 9, 39, 40, 40, 40, 40, 40, 40, 20, 9, 18, 9, 9, 9, 20, 20, 9, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40}}, objects={{type = .Prop, tile_id = 45, pos = {4, 124}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {32, 104}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {128, 72}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {212, 104}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {104, 124}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {116, 140}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {180, 136}, size = {32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 53, pos = {36, 152}, size = {26, 55}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 52, pos = {84, 152}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {88, 72}, size = {32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {120, 88}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {56, 56}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {128, 152}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {20, 152}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {40, 152}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {52, 152}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Rope, tile_id = nil, pos = {58, 105}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=6, "image"="res/img/windchimes_1.png", "node_length"=2}}, }, background_color=Color{0, 0, 0, 1}, background_images={} }, - .Carrabassett3 = {width=20, height=40, tile_width=16, tile_height=16, layers={{40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 27, 19, 31, 19, 19, 31, 28, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 21, 19, 31, 17, 0, 0, 0, 0, 0, 16, 19, 28, 40, 40, 40, 40, 40, 40, 40, 21, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 19, 28, 40, 40, 40, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 27, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 21, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 28, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 20, 9, 39, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 18, 9, 18, 39, 40, 40, 40, 40, 40, 32, 0, 0, 0, 0, 41, 20, 20, 18, 18, 39, 40, 40, 40, 40, 40, 21, 28, 40, 40, 32, 0, 0, 0, 0, 10, 31, 31, 19, 19, 28, 40, 40, 40, 40, 27, 17, 7, 40, 40, 43, 42, 0, 0, 0, 0, 0, 0, 0, 0, 10, 19, 19, 19, 31, 17, 0, 7, 40, 40, 40, 38, 18, 18, 20, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 38, 20, 20, 18, 6, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 38, 6, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 43, 6, 0, 0, 0, 0, 0, 7, 40, 40, 21, 28, 40, 21, 31, 28, 40, 40, 40, 40, 40, 32, 0, 0, 0, 0, 0, 7, 40, 40, 32, 16, 19, 17, 0, 16, 19, 19, 31, 28, 40, 38, 9, 20, 6, 0, 0, 7, 40, 40, 8, 0, 0, 0, 0, 0, 0, 0, 0, 16, 19, 31, 19, 19, 17, 0, 0, 7, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 20, 18, 9, 9, 18, 20, 39, 40, 40, 43, 6, 0, 0, 0, 0, 0, 41, 20, 20, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 38, 42, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 38, 20, 20, 42, 0, 10, 19, 28, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 27, 19, 19, 28, 40, 8, 0, 0, 0, 10, 31, 19, 31, 28, 40, 40, 40, 40, 40, 40, 32, 0, 0, 10, 19, 17, 0, 0, 0, 0, 0, 0, 0, 16, 31, 31, 31, 19, 31, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 38, 9, 9, 9, 20, 20, 18, 18, 9, 9, 42, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 8, 0, 0, 5, 20, 20, 9, 9, 18, 40, 40, 40, 21, 31, 31, 19, 31, 31, 19, 19, 17, 0, 5, 39, 40, 40, 40, 40, 40, 40, 40, 21, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 28, 40, 40, 40, 40, 40, 40, 27, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 41, 20, 18, 20, 39, 40, 40, 40, 40, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 38, 6, 0, 0, 0, 0, 41, 9, 9, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 43, 6, 0, 0, 41, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40}}, objects={{type = .Prop, tile_id = 49, pos = {132, 616}, size = {32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {32, 488}, size = {32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {204, 328}, size = {32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {260, 168}, size = {-32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {228, 184}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {108, 200}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {160, 200}, size = {-16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {108, 264}, size = {-16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {168, 280}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {284, 376}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {216, 376}, size = {-16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {184, 376}, size = {-16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {140, 392}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 52, pos = {232, 376}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 52, pos = {156, 392}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 46, pos = {128, 200}, size = {29, 14}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 52, pos = {44, 248}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 52, pos = {252, 504}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {284, 504}, size = {-32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {236, 504}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {24, 472}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {84, 348}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {176, 252}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {280, 236}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {236, 264}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {28, 144}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {132, 56}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {84, 72}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {224, 68}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {252, 88}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {156, 60}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {132, 80}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {108, 364}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {100, 380}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {36, 356}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {92, 356}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {180, 476}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {72, 552}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {36, 576}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {48, 548}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {56, 556}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {68, 552}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {88, 540}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {132, 540}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {108, 556}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {208, 460}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {136, 344}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {56, 344}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {20, 332}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {204, 364}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {188, 248}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {148, 232}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {136, 228}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {120, 44}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {144, 60}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {168, 52}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {180, 44}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {52, 76}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Rope, tile_id = nil, pos = {104, 520}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=6, "image"="res/img/small_lamp.png", "node_length"=5}}, {type = .Rope, tile_id = nil, pos = {200, 440}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=6, "image"="res/img/small_lamp.png", "node_length"=5}}, {type = .Rope, tile_id = nil, pos = {108, 40}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=9, "image"="res/img/windchimes_1.png", "node_length"=5}}, {type = .Rope, tile_id = nil, pos = {176, 24}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=15, "image"="res/img/windchimes_0.png", "node_length"=5}}, {type = .Rope, tile_id = nil, pos = {244, 40}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=8, "image"="res/img/windchimes_1.png", "node_length"=5}}, {type = .Rope, tile_id = nil, pos = {68, 48}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=6, "image"="res/img/windchimes_0.png", "node_length"=5}}, {type = .Rope, tile_id = nil, pos = {144, 24}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=12, "image"="res/img/windchimes_0.png", "node_length"=5}}, }, background_color=Color{0, 0, 0, 1}, background_images={} }, - .Carrabassett4 = {width=20, height=20, tile_width=16, tile_height=16, layers={{40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 21, 31, 28, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 21, 31, 19, 19, 17, 0, 10, 31, 19, 31, 28, 40, 40, 40, 40, 40, 40, 40, 21, 31, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 19, 31, 19, 28, 40, 40, 40, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 21, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 27, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 39, 40, 0, 0, 0, 0, 0, 0, 0, 0, 5, 18, 9, 20, 9, 20, 20, 9, 9, 39, 40, 40, 18, 9, 20, 18, 20, 9, 9, 9, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40}}, objects={{type = .Prop, tile_id = 45, pos = {52, 184}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {68, 172}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {156, 160}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {192, 167}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {264, 184}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {200, 188}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {228, 196}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {108, 168}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {60, 176}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {124, 152}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {88, 156}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {164, 160}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {208, 184}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {220, 188}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {240, 184}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {252, 172}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 46, pos = {148, 280}, size = {29, 14}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {244, 280}, size = {32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {28, 296}, size = {-32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {280, 268}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {208, 280}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {80, 296}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {112, 296}, size = {-16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 53, pos = {184, 280}, size = {-26, 55}, parallax = {0, 0}, properties = {}}, {type = .Rope, tile_id = nil, pos = {84, 136}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=10, "image"="res/img/windchimes_0.png", "node_length"=5}}, {type = .Rope, tile_id = nil, pos = {151, 120}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=10, "image"="res/img/windchimes_0.png", "node_length"=5}}, {type = .Rope, tile_id = nil, pos = {113, 133}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=6, "image"="res/img/windchimes_1.png", "node_length"=5}}, {type = .Rope, tile_id = nil, pos = {201, 136}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=6, "image"="res/img/windchimes_0.png", "node_length"=5}}, {type = .Rope, tile_id = nil, pos = {233, 144}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=12, "image"="res/img/windchimes_1.png", "node_length"=5}}, {type = .Rope, tile_id = nil, pos = {188, 233}, size = {0, 0}, parallax = {0, 0}, properties = {"length"=6, "image"="res/img/windchimes_0.png", "node_length"=2}}, {type = .Prop, tile_id = 52, pos = {228, 280}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 52, pos = {64, 296}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Upgrade, tile_id = nil, pos = {160, 241}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/double_jump_pickup.qoi", "type"=1}}, }, background_color=Color{0, 0, 0, 1}, background_images={} }, + .Carrabassett0 = {width=40, height=20, tile_width=16, tile_height=16, layers={{40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 27, 31, 31, 19, 19, 28, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 21, 31, 31, 31, 11, 0, 0, 0, 0, 16, 19, 31, 28, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 27, 31, 19, 31, 19, 19, 19, 31, 19, 31, 19, 19, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 28, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 21, 31, 31, 31, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 40, 40, 21, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 31, 31, 31, 19, 19, 31, 40, 40, 21, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 20, 20, 18, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 19, 31, 19, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 21, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 18, 9, 9, 20, 9, 9, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 41, 9, 20, 20, 20, 18, 20, 20, 9, 20, 9, 20, 9, 20, 20, 9, 9, 18, 6, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 27, 17, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 32, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 17, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 43, 9, 9, 20, 20, 9, 39, 40, 40, 40, 40, 40, 40, 0, 0, 0, 0, 0, 5, 20, 20, 18, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 20, 9, 20, 18, 20, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40}}, objects={{type = .Prop, tile_id = 53, pos = {194, 200}, size = {26, 55}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {352, 200}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {412, 200}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {364, 200}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {172, 200}, size = {32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 46, pos = {224, 200}, size = {29, 14}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {220, 92}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {296, 92}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {340, 76}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {416, 60}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {492, 76}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {432, 76}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {352, 92}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {236, 108}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {80, 124}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {528, 100}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {472, 88}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {512, 96}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {60, 124}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {44, 148}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {24, 180}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {148, 96}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {260, 92}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {164, 88}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {128, 100}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {20, 280}, size = {32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {304, 200}, size = {32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {260, 200}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {284, 200}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {132, 248}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {96, 248}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {64, 280}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 52, pos = {116, 248}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 52, pos = {300, 200}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 52, pos = {448, 232}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {540, 152}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {612, 152}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {576, 152}, size = {32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {556, 124}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {572, 136}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {588, 124}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {580, 132}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {504, 80}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {424, 68}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {248, 100}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 53, pos = {484, 232}, size = {-26, 55}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {400, 172}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {412, 156}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {436, 172}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Rope, tile_id = nil, pos = {487, 185}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/windchimes_0.png", "node_length"=2, "length"=6}}, {type = .Rope, tile_id = nil, pos = {217, 153}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/small_lamp.png", "node_length"=2, "length"=6}}, {type = .Rope, tile_id = nil, pos = {515, 110}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/windchimes_0.png", "node_length"=5, "length"=20}}, {type = .Player_Spawn, tile_id = nil, pos = {240, 200}, size = {0, 0}, parallax = {0, 0}, properties = {}}, {type = .Collision, tile_id = nil, pos = {0, 0}, size = {48, 48}, parallax = {0, 0}, properties = {}}, }, background_color=Color{0, 0, 0, 1}, background_images={} }, + .Carrabassett1 = {width=20, height=20, tile_width=16, tile_height=16, layers={{40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 21, 31, 31, 31, 28, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 27, 31, 31, 17, 0, 0, 0, 16, 19, 28, 40, 40, 40, 40, 40, 40, 40, 27, 31, 31, 17, 0, 0, 0, 0, 0, 0, 0, 0, 16, 28, 40, 40, 40, 40, 40, 27, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 28, 40, 40, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 28, 40, 40, 40, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 21, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 38, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 28, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 40, 40, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 43, 9, 9, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 18, 20, 20, 40, 40, 40, 40, 40, 43, 9, 9, 9, 9, 9, 9, 18, 9, 18, 18, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40}}, objects={{type = .Prop, tile_id = 49, pos = {92, 296}, size = {32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 46, pos = {144, 296}, size = {29, 14}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 53, pos = {180, 296}, size = {-26, 55}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 53, pos = {116, 296}, size = {26, 55}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {127, 296}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {181, 296}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {224, 296}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {252, 296}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {292, 280}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {48, 280}, size = {32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {80, 104}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {88, 100}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {100, 96}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {108, 88}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {116, 88}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {96, 96}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {192, 76}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {272, 128}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {244, 100}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {228, 72}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {264, 104}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {284, 128}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {40, 108}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {56, 92}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {68, 108}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {24, 172}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 52, pos = {272, 280}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {24, 200}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Rope, tile_id = nil, pos = {139, 249}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/windchimes_1.png", "node_length"=2, "length"=6}}, {type = .Rope, tile_id = nil, pos = {183, 249}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/windchimes_1.png", "node_length"=2, "length"=6}}, {type = .Rope, tile_id = nil, pos = {134, 48}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/windchimes_0.png", "node_length"=7, "length"=15}}, {type = .Rope, tile_id = nil, pos = {232, 47}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/windchimes_0.png", "node_length"=5, "length"=15}}, {type = .Rope, tile_id = nil, pos = {70, 59}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/windchimes_1.png", "node_length"=10, "length"=15}}, {type = .Rope, tile_id = nil, pos = {174, 32}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/windchimes_1.png", "node_length"=10, "length"=15}}, {type = .Rope, tile_id = nil, pos = {269, 72}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/windchimes_1.png", "node_length"=10, "length"=15}}, {type = .Rope, tile_id = nil, pos = {206, 30}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/windchimes_0.png", "node_length"=8, "length"=15}}, {type = .Rope, tile_id = nil, pos = {115, 45}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/small_lamp.png", "node_length"=5, "length"=15}}, {type = .Rope, tile_id = nil, pos = {91, 61}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/small_lamp.png", "node_length"=5, "length"=15}}, {type = .Rope, tile_id = nil, pos = {191, 31}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/small_lamp.png", "node_length"=5, "length"=15}}, {type = .Rope, tile_id = nil, pos = {286, 86}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/small_lamp.png", "node_length"=5, "length"=15}}, {type = .Upgrade, tile_id = nil, pos = {160, 240}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/dash_pickup.qoi", "type"=0}}, }, background_color=Color{0, 0, 0, 1}, background_images={} }, + .Carrabassett2 = {width=20, height=20, tile_width=16, tile_height=16, layers={{40, 40, 40, 8, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 8, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 8, 0, 0, 10, 31, 31, 28, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 38, 20, 42, 0, 0, 0, 10, 19, 19, 28, 40, 40, 40, 40, 40, 40, 40, 40, 27, 31, 19, 28, 38, 18, 6, 0, 0, 0, 0, 10, 19, 28, 40, 40, 40, 40, 40, 27, 17, 0, 0, 10, 28, 40, 38, 20, 42, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 17, 0, 0, 0, 0, 16, 19, 31, 19, 17, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 39, 40, 40, 40, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 18, 9, 9, 39, 40, 40, 40, 40, 40, 40, 20, 9, 18, 9, 9, 9, 20, 20, 9, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40}}, objects={{type = .Prop, tile_id = 45, pos = {4, 124}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {32, 104}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {128, 72}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {212, 104}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {104, 124}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {116, 140}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {180, 136}, size = {32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 53, pos = {36, 152}, size = {26, 55}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 52, pos = {84, 152}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {88, 72}, size = {32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {120, 88}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {56, 56}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {128, 152}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {20, 152}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {40, 152}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {52, 152}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Rope, tile_id = nil, pos = {58, 105}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/windchimes_1.png", "node_length"=2, "length"=6}}, }, background_color=Color{0, 0, 0, 1}, background_images={} }, + .Carrabassett3 = {width=20, height=40, tile_width=16, tile_height=16, layers={{40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 27, 19, 31, 19, 19, 31, 28, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 21, 19, 31, 17, 0, 0, 0, 0, 0, 16, 19, 28, 40, 40, 40, 40, 40, 40, 40, 21, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 19, 28, 40, 40, 40, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 27, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 21, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 28, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 20, 9, 39, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 18, 9, 18, 39, 40, 40, 40, 40, 40, 32, 0, 0, 0, 0, 41, 20, 20, 18, 18, 39, 40, 40, 40, 40, 40, 21, 28, 40, 40, 32, 0, 0, 0, 0, 10, 31, 31, 19, 19, 28, 40, 40, 40, 40, 27, 17, 7, 40, 40, 43, 42, 0, 0, 0, 0, 0, 0, 0, 0, 10, 19, 19, 19, 31, 17, 0, 7, 40, 40, 40, 38, 18, 18, 20, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 38, 20, 20, 18, 6, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 38, 6, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 43, 6, 0, 0, 0, 0, 0, 7, 40, 40, 21, 28, 40, 21, 31, 28, 40, 40, 40, 40, 40, 32, 0, 0, 0, 0, 0, 7, 40, 40, 32, 16, 19, 17, 0, 16, 19, 19, 31, 28, 40, 38, 9, 20, 6, 0, 0, 7, 40, 40, 8, 0, 0, 0, 0, 0, 0, 0, 0, 16, 19, 31, 19, 19, 17, 0, 0, 7, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 20, 18, 9, 9, 18, 20, 39, 40, 40, 43, 6, 0, 0, 0, 0, 0, 41, 20, 20, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 38, 42, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 38, 20, 20, 42, 0, 10, 19, 28, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 27, 19, 19, 28, 40, 8, 0, 0, 0, 10, 31, 19, 31, 28, 40, 40, 40, 40, 40, 40, 32, 0, 0, 10, 19, 17, 0, 0, 0, 0, 0, 0, 0, 16, 31, 31, 31, 19, 31, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 38, 9, 9, 9, 20, 20, 18, 18, 9, 9, 42, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 8, 0, 0, 5, 20, 20, 9, 9, 18, 40, 40, 40, 21, 31, 31, 19, 31, 31, 19, 19, 17, 0, 5, 39, 40, 40, 40, 40, 40, 40, 40, 21, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 28, 40, 40, 40, 40, 40, 40, 27, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 41, 20, 18, 20, 39, 40, 40, 40, 40, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 38, 6, 0, 0, 0, 0, 41, 9, 9, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 43, 6, 0, 0, 41, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40}}, objects={{type = .Prop, tile_id = 49, pos = {132, 616}, size = {32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {32, 488}, size = {32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {204, 328}, size = {32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {260, 168}, size = {-32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {228, 184}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {108, 200}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {160, 200}, size = {-16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {108, 264}, size = {-16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {168, 280}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {284, 376}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {216, 376}, size = {-16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {184, 376}, size = {-16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {140, 392}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 52, pos = {232, 376}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 52, pos = {156, 392}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 46, pos = {128, 200}, size = {29, 14}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 52, pos = {44, 248}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 52, pos = {252, 504}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {284, 504}, size = {-32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {236, 504}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {24, 472}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {84, 348}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {176, 252}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {280, 236}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {236, 264}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {28, 144}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {132, 56}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {84, 72}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {224, 68}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {252, 88}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {156, 60}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {132, 80}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {108, 364}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {100, 380}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {36, 356}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {92, 356}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {180, 476}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {72, 552}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {36, 576}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {48, 548}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {56, 556}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {68, 552}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {88, 540}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {132, 540}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {108, 556}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {208, 460}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {136, 344}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {56, 344}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {20, 332}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {204, 364}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {188, 248}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {148, 232}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {136, 228}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {120, 44}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {144, 60}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {168, 52}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {180, 44}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {52, 76}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Rope, tile_id = nil, pos = {104, 520}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/small_lamp.png", "node_length"=5, "length"=6}}, {type = .Rope, tile_id = nil, pos = {200, 440}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/small_lamp.png", "node_length"=5, "length"=6}}, {type = .Rope, tile_id = nil, pos = {108, 40}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/windchimes_1.png", "node_length"=5, "length"=9}}, {type = .Rope, tile_id = nil, pos = {176, 24}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/windchimes_0.png", "node_length"=5, "length"=15}}, {type = .Rope, tile_id = nil, pos = {244, 40}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/windchimes_1.png", "node_length"=5, "length"=8}}, {type = .Rope, tile_id = nil, pos = {68, 48}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/windchimes_0.png", "node_length"=5, "length"=6}}, {type = .Rope, tile_id = nil, pos = {144, 24}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/windchimes_0.png", "node_length"=5, "length"=12}}, }, background_color=Color{0, 0, 0, 1}, background_images={} }, + .Carrabassett4 = {width=20, height=20, tile_width=16, tile_height=16, layers={{40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 21, 31, 28, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 21, 31, 19, 19, 17, 0, 10, 31, 19, 31, 28, 40, 40, 40, 40, 40, 40, 40, 21, 31, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 19, 31, 19, 28, 40, 40, 40, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 21, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 27, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 39, 40, 0, 0, 0, 0, 0, 0, 0, 0, 5, 18, 9, 20, 9, 20, 20, 9, 9, 39, 40, 40, 18, 9, 20, 18, 20, 9, 9, 9, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40}}, objects={{type = .Prop, tile_id = 45, pos = {52, 184}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {68, 172}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {156, 160}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {192, 167}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {264, 184}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {200, 188}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {228, 196}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 45, pos = {108, 168}, size = {14, 38}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {60, 176}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {124, 152}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {88, 156}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {164, 160}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {208, 184}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {220, 188}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {240, 184}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 47, pos = {252, 172}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 46, pos = {148, 280}, size = {29, 14}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {244, 280}, size = {32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 49, pos = {28, 296}, size = {-32, 19}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {280, 268}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {208, 280}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {80, 296}, size = {16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 51, pos = {112, 296}, size = {-16, 18}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 53, pos = {184, 280}, size = {-26, 55}, parallax = {0, 0}, properties = {}}, {type = .Rope, tile_id = nil, pos = {84, 136}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/windchimes_0.png", "node_length"=5, "length"=10}}, {type = .Rope, tile_id = nil, pos = {151, 120}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/windchimes_0.png", "node_length"=5, "length"=10}}, {type = .Rope, tile_id = nil, pos = {113, 133}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/windchimes_1.png", "node_length"=5, "length"=6}}, {type = .Rope, tile_id = nil, pos = {201, 136}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/windchimes_0.png", "node_length"=5, "length"=6}}, {type = .Rope, tile_id = nil, pos = {233, 144}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/windchimes_1.png", "node_length"=5, "length"=12}}, {type = .Rope, tile_id = nil, pos = {188, 233}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/windchimes_0.png", "node_length"=2, "length"=6}}, {type = .Prop, tile_id = 52, pos = {228, 280}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Prop, tile_id = 52, pos = {64, 296}, size = {14, 22}, parallax = {0, 0}, properties = {}}, {type = .Upgrade, tile_id = nil, pos = {160, 241}, size = {0, 0}, parallax = {0, 0}, properties = {"image"="res/img/double_jump_pickup.qoi", "type"=1}}, }, background_color=Color{0, 0, 0, 1}, background_images={} }, } tiles: []Tile_Resource = { diff --git a/src/draw.odin b/src/draw.odin deleted file mode 100644 index 0c21c80..0000000 --- a/src/draw.odin +++ /dev/null @@ -1,151 +0,0 @@ -package demonchime - -import "core:c" -import "core:math" -import "core:math/linalg" - -import rl "vendor:raylib" -import rlgl "vendor:raylib/rlgl" - -Color :: [4]f32 - -SCREEN_WIDTH :: 320 -SCREEN_HEIGHT :: 320 -SCREEN_SIZE :: Vec2{SCREEN_WIDTH, SCREEN_HEIGHT} - -// @(default_calling_convention = "c") -// foreign lib { -// DrawTexturePoly :: proc(texture: rl.Texture2D, center: rl.Vector2, points: [^]rl.Vector2, textcoords: [^]rl.Vector2, point_count: c.int, color: Color) --- // Draw a regular polygon (Vector version) -// } - -renderer: struct { - screen: rl.RenderTexture2D, - tint: Color, -} - -@(private = "file") -_color_to_rl :: proc(col: Color) -> rl.Color { - return rl.Color { - u8(col.r * 255), - u8(col.g * 255), - u8(col.b * 255), - u8(col.a * 255), - } -} - -init_draw :: proc() { - renderer.screen = rl.LoadRenderTexture(SCREEN_WIDTH, SCREEN_HEIGHT) - renderer.tint = Color{1, 1, 1, 1} -} - -deinit_draw :: proc() { - rl.UnloadRenderTexture(renderer.screen) -} - -draw_new_frame :: proc() { - rl.BeginTextureMode(renderer.screen) - rl.ClearBackground(rl.BLACK) - // rl.ClearBackground(rl.GRAY) -} - -draw_end_frame :: proc() { - rl.EndTextureMode() - - rl.BeginDrawing() - { - rl.ClearBackground(_color_to_rl(Color{0, 0, 0, 1})) - scale := math.min( - f32(rl.GetScreenWidth()) / f32(SCREEN_WIDTH), - f32(rl.GetScreenHeight()) / f32(SCREEN_HEIGHT), - ) - screen_start := Vec2 { - (f32(rl.GetScreenWidth()) - (SCREEN_WIDTH * scale)) / 2, - (f32(rl.GetScreenHeight()) - (SCREEN_HEIGHT * scale)) / 2, - } - - draw_texture( - renderer.screen.texture, - screen_start, - scale = Vec2{scale, -scale}, - ) - } - rl.EndDrawing() -} - -draw_circle :: proc(pos: Vec2, rad: f32) { - rl.DrawCircle(i32(pos.x), i32(pos.y), rad, _color_to_rl(renderer.tint)) -} - -draw_rect :: proc(rect: Rect) { - assert(rect.size.x > 0 && rect.size.y > 0) - - rl.DrawRectangle( - c.int(rect.start.x), - c.int(rect.start.y), - c.int(rect.size.x), - c.int(rect.size.y), - _color_to_rl(renderer.tint), - ) -} - -draw_linerect :: proc(rect: Rect) { - assert(rect.size.x > 0 && rect.size.y > 0) - - rl.DrawRectangleLines( - c.int(rect.start.x), - c.int(rect.start.y), - c.int(rect.size.x), - c.int(rect.size.y), - _color_to_rl(renderer.tint), - ) -} - -draw_texture :: proc { - draw_texture_full, - draw_texture_quad, -} - -draw_texture_quad :: proc( - img: rl.Texture2D, - quad: Rect, - position: Vec2, - offset := Vec2{0, 0}, - rotation: f32 = 0, - scale := Vec2{1, 1}, -) { - quad := quad - if scale.x < 0 { - quad.size.x *= -1 - } - if scale.y < 0 { - quad.size.y *= -1 - } - - position := linalg.round(position) - - rl.DrawTexturePro( - img, - transmute(rl.Rectangle)quad, - rl.Rectangle { - position.x, - position.y, - quad.size.x * scale.x, - quad.size.y * scale.y, - }, - offset, - math.round(rotation / 5) * 5, - _color_to_rl(renderer.tint), - ) -} - -draw_texture_full :: proc( - img: rl.Texture2D, - position: Vec2, - offset := Vec2{0, 0}, - rotation: f32 = 0, - scale := Vec2{1, 1}, -) { - size := Vec2{f32(img.width), f32(img.height)} - - draw_texture_quad(img, Rect{Vec2{0, 0}, size}, position, offset, rotation, scale) -} diff --git a/src/fw/fw.odin b/src/fw/fw.odin new file mode 100644 index 0000000..86a3e3a --- /dev/null +++ b/src/fw/fw.odin @@ -0,0 +1,114 @@ +package fw + +import "core:log" + +import "vendor:glfw" + +Vec2 :: [2]f32 +Vec2i :: [2]i32 +Vec3 :: [3]f32 +Vec4 :: [4]f32 +Color :: [4]f32 +Mat4 :: matrix[4, 4]f32 + +Rect :: struct { + start: Vec2, + size: Vec2, +} + +Config :: struct { + win_name: cstring, + win_size: Vec2i, + screen_size: Vec2i, + renderer_backend: Renderer_Backend, +} + +@(private) window: glfw.WindowHandle +@(private) last_frame: f64 +@(private) dt: f64 + +rgba8 :: proc(r: u8, g: u8, b: u8, a: u8 = 255) -> Color { + return Color{ + f32(r) / 255, + f32(g) / 255, + f32(b) / 255, + f32(a) / 255, + } +} + +init :: proc(config: Config) { + if !glfw.Init() { + panic("could not init glfw window") + } + + glfw.WindowHint(glfw.CONTEXT_VERSION_MAJOR, 3) + glfw.WindowHint(glfw.CONTEXT_VERSION_MINOR, 3) + glfw.WindowHint(glfw.RESIZABLE, false) + glfw.WindowHint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE) + + window = glfw.CreateWindow( + config.win_size.x, + config.win_size.y, + config.win_name, + nil, + nil, + ) + + if window == nil { + panic("could not create glfw window") + } + + glfw.SwapInterval(1) + + _renderer_init(config) +} + +deinit :: proc() { + _renderer_deinit() + + glfw.DestroyWindow(window) + glfw.Terminate() +} + +next_frame :: proc() -> bool { + // End the previous frame + if can_flush() { + flush_batch(&renderer.draw_call) + new_batch(renderer.white_1x1.handle, .None, false) + } + + renderer.vt.end_frame() + new_batch(renderer.white_1x1.handle, .None, false) + + renderer.draw_calls_count = renderer._draw_call_counter + renderer._draw_call_counter = 0 + + glfw.SwapBuffers(window) + glfw.PollEvents() + _update_input() + + // log.debugf("Draw calls: %v", renderer.draw_calls_count) + + // Begin next frame + + time := get_time() + dt = time - last_frame + last_frame = time + + renderer.vt.clear({0, 0, 0, 1}) + + renderer.vt.start_frame() + renderer.vt.clear(renderer.bg_col) + + return !bool(glfw.WindowShouldClose(window)) +} + +@(require_results) +get_time :: #force_inline proc() -> f64 { + return glfw.GetTime() +} + +@(require_results) +get_delta_time :: #force_inline proc() -> f64 { + return dt +} diff --git a/src/fw/input.odin b/src/fw/input.odin new file mode 100644 index 0000000..a3cbe25 --- /dev/null +++ b/src/fw/input.odin @@ -0,0 +1,76 @@ +package fw + +import "core:c" +import "vendor:glfw" + +Keyboard_Input :: union { + Key, + Mouse_Button, +} + +Controller_Input :: union { +} + +Keybind :: struct { + input: Keyboard_Input, + pressed: bool, + just_pressed: bool, +} + +key_down_last_frame: #sparse [Key]bool +key_just_down: #sparse [Key]bool + +mouse_down_last_frame: #sparse [Mouse_Button]bool +mouse_just_down: #sparse [Mouse_Button]bool + +@(private) +_update_input :: proc() { + for key in Key { + status := glfw.GetKey(window, c.int(key)) + key_pressed := status == glfw.PRESS + key_just_down[key] = key_pressed && !key_down_last_frame[key] + + key_down_last_frame[key] = key_pressed + } + + for mb in Mouse_Button { + status := glfw.GetMouseButton(window, c.int(mb)) + mouse_pressed := status == glfw.PRESS + mouse_just_down[mb] = mouse_pressed && !mouse_down_last_frame[mb] + + mouse_down_last_frame[mb] = mouse_pressed + } +} + +is_keybind_down :: proc(keybind: Keybind) -> bool { + switch val in keybind.input { + case Key: + return glfw.GetKey(window, c.int(val)) == glfw.PRESS + case Mouse_Button: + return glfw.GetMouseButton(window, c.int(val)) == glfw.PRESS + } + + assert(false) + return false +} + +is_keybind_just_down :: proc(keybind: Keybind) -> bool { + switch val in keybind.input { + case Key: return key_just_down[val] + case Mouse_Button: return mouse_just_down[val] + } + + assert(false) + return false +} + +get_mouse_pos :: proc() -> (mouse_pos: Vec2) { + w_width, w_height := glfw.GetWindowSize(window) + mx, my := glfw.GetCursorPos(window) + + mouse_pos = Vec2{f32(mx), f32(mx)} + mouse_pos /= Vec2{f32(w_width), f32(w_height)} + mouse_pos *= Vec2{f32(framebuf.color.size.x), f32(framebuf.color.size.y)} + // mouse_pos += state.camera.target + return +} diff --git a/src/fw/keys.odin b/src/fw/keys.odin new file mode 100644 index 0000000..180cb4b --- /dev/null +++ b/src/fw/keys.odin @@ -0,0 +1,140 @@ +package fw + +Mouse_Button :: enum { + B1 = 0, + B2 = 1, + B3 = 2, + B4 = 3, + B5 = 4, + B6 = 5, + B7 = 6, + B8 = 7, + Last = B8, + Left = B1, + Right = B2, + Middle = B3, +} + +Key :: enum { + Space = 32, + Apostrophe = 39, + Comma = 44, + Minus = 45, + Period = 46, + Slash = 47, + Semicolon = 59, + Equal = 61, + Left_Bracket = 91, + Backslash = 92, + Right_Bracket = 93, + Grave_Accent = 96, + World_1 = 161, + World_2 = 162, + N0 = 48, + N1 = 49, + N2 = 50, + N3 = 51, + N4 = 52, + N5 = 53, + N6 = 54, + N7 = 55, + N8 = 56, + N9 = 57, + A = 65, + B = 66, + C = 67, + D = 68, + E = 69, + F = 70, + G = 71, + H = 72, + I = 73, + J = 74, + K = 75, + L = 76, + M = 77, + N = 78, + O = 79, + P = 80, + Q = 81, + R = 82, + S = 83, + T = 84, + U = 85, + V = 86, + W = 87, + X = 88, + Y = 89, + Z = 90, + Escape = 256, + Enter = 257, + Tab = 258, + Backspace = 259, + Insert = 260, + Delete = 261, + Right = 262, + Left = 263, + Down = 264, + Up = 265, + Page_Up = 266, + Page_Down = 267, + Home = 268, + End = 269, + Caps_Lock = 280, + Scroll_Lock = 281, + Num_Lock = 282, + Print_Screen = 283, + Pause = 284, + F1 = 290, + F2 = 291, + F3 = 292, + F4 = 293, + F5 = 294, + F6 = 295, + F7 = 296, + F8 = 297, + F9 = 298, + F10 = 299, + F11 = 300, + F12 = 301, + F13 = 302, + F14 = 303, + F15 = 304, + F16 = 305, + F17 = 306, + F18 = 307, + F19 = 308, + F20 = 309, + F21 = 310, + F22 = 311, + F23 = 312, + F24 = 313, + F25 = 314, + Kp_0 = 320, + Kp_1 = 321, + Kp_2 = 322, + Kp_3 = 323, + Kp_4 = 324, + Kp_5 = 325, + Kp_6 = 326, + Kp_7 = 327, + Kp_8 = 328, + Kp_9 = 329, + Kp_Decimal = 330, + Kp_Divide = 331, + Kp_Multiply = 332, + Kp_Subtract = 333, + Kp_Add = 334, + Kp_Enter = 335, + Kp_Equal = 336, + Left_Shift = 340, + Left_Control = 341, + Left_Alt = 342, + Left_Super = 343, + Right_Shift = 344, + Right_Control = 345, + Right_Alt = 346, + Right_Super = 347, + Menu = 348, + Last = Menu, +} diff --git a/src/fw/opengl.odin b/src/fw/opengl.odin new file mode 100644 index 0000000..ab2bb81 --- /dev/null +++ b/src/fw/opengl.odin @@ -0,0 +1,363 @@ +package fw + +import "base:runtime" + +import "core:log" +import "core:fmt" +import "core:math/linalg" +import "core:os" + +import "vendor:glfw" +import gl "vendor:OpenGL" + +@(private) +enum_conv: map[All_Enums]u32 + +vert_shader_src := string(#load("shader.vert")) +frag_shader_src := string(#load("shader.frag")) + +vao: u32 +vbo: u32 +ebo: u32 + +framebuf: struct { + handle: u32, + color: Texture, // so we can reuse pre-existing draw procs + depth: u32, +} +shader_program: u32 + +projection_loc: i32 +view_loc: i32 +tex0_loc: i32 + +// @(private) +// _gl_debug_message :: proc "c" ( +// source: u32, +// type: u32, +// id: u32, +// severity: u32, +// length: i32, +// message: cstring, +// userParam: rawptr, +// ) { +// context = runtime.default_context() +// switch severity { +// case gl.DEBUG_SEVERITY_HIGH: fmt.print("[HIGH]") +// case gl.DEBUG_SEVERITY_MEDIUM: fmt.print("[MEDIUM]") +// case gl.DEBUG_SEVERITY_LOW: fmt.print("[LOW]") +// case gl.DEBUG_SEVERITY_NOTIFICATION: fmt.print("[NOTIF]") +// } +// fmt.printfln(" OpenGL %v: %v", id, message) +// } + +@(private) +_init_vertex_buffer_and_array :: proc(vao: u32, vbo: u32, ebo: u32) { + gl.BindVertexArray(vao) + + gl.BindBuffer(gl.ARRAY_BUFFER, vbo) + gl.BufferData(gl.ARRAY_BUFFER, 0, nil, gl.DYNAMIC_DRAW) + + gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebo) + gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, 0, nil, gl.DYNAMIC_DRAW) + + stride := i32(size_of(Vertex)) + + gl.EnableVertexAttribArray(0) + gl.VertexAttribPointer(0, 3, gl.FLOAT, false, stride, offset_of(Vertex, pos)) + + gl.EnableVertexAttribArray(1) + gl.VertexAttribPointer(1, 2, gl.FLOAT, false, stride, offset_of(Vertex, uv)) + + gl.EnableVertexAttribArray(2) + gl.VertexAttribPointer( + 2, + 4, + gl.FLOAT, + false, + stride, + offset_of(Vertex, color), + ) +} + +@(private) +_gl_load_shader :: proc(src: string, type: u32) -> u32 { + shader := gl.CreateShader(type) + csrc := cstring(raw_data(src)) + src_len := i32(len(src)) + gl.ShaderSource(shader, 1, &csrc, &src_len) + gl.CompileShader(shader) + + status: i32 + gl.GetShaderiv(shader, gl.COMPILE_STATUS, &status) + if status == 0 { + gl.DeleteShader(shader) + return 0 + } + + return shader +} + +@(private) +_gl_load_shader_program :: proc(vert_src: string, frag_src: string) -> u32 { + vert_shader := _gl_load_shader(vert_src, gl.VERTEX_SHADER) + defer gl.DeleteShader(vert_shader) + frag_shader := _gl_load_shader(frag_src, gl.FRAGMENT_SHADER) + defer gl.DeleteShader(frag_shader) + + program := gl.CreateProgram() + gl.AttachShader(program, vert_shader) + gl.AttachShader(program, frag_shader) + gl.LinkProgram(program) + + status: i32 + gl.GetProgramiv(program, gl.LINK_STATUS, &status) + if status == 0 { + gl.DeleteProgram(program) + return 0 + } + + return program +} + +gl_init :: proc() { + glfw.MakeContextCurrent(window) + + gl.load_up_to(3, 3, glfw.gl_set_proc_address) + + gl.Enable(gl.DEPTH_TEST) + gl.DepthFunc(gl.LEQUAL) + + // gl.Enable(gl.BLEND); + // gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); + + renderer.vt.start_frame = gl_start_frame + renderer.vt.end_frame = gl_end_frame + renderer.vt.draw = gl_draw + renderer.vt.clear = gl_clear + renderer.vt.init_texture = gl_init_texture + renderer.vt.destroy_texture = gl_destroy_texture + renderer.vt.init_screen = gl_init_screen + + enum_conv[Vertex_Mode.None] = gl.TRIANGLES + enum_conv[Vertex_Mode.Triangles] = gl.TRIANGLES + enum_conv[Vertex_Mode.Triangle_Fan] = gl.TRIANGLE_FAN + enum_conv[Vertex_Mode.Triangle_Strip] = gl.TRIANGLE_STRIP + enum_conv[Vertex_Mode.Lines] = gl.LINES + enum_conv[Vertex_Mode.Line_Strip] = gl.LINE_STRIP + enum_conv[Vertex_Mode.Line_Loop] = gl.LINE_LOOP + enum_conv[Vertex_Mode.Points] = gl.POINTS + + gl.PixelStorei(gl.UNPACK_ALIGNMENT, 1); + + gl.GenBuffers(1, &vbo) + gl.GenBuffers(1, &ebo) + gl.GenVertexArrays(1, &vao) + _init_vertex_buffer_and_array(vao, vbo, ebo) + + shader_program = _gl_load_shader_program(vert_shader_src, frag_shader_src) + projection_loc = gl.GetUniformLocation(shader_program, "projection") + view_loc = gl.GetUniformLocation(shader_program, "view") + tex0_loc = gl.GetUniformLocation(shader_program, "tex0") +} + +gl_deinit :: proc() { + delete(enum_conv) + + destroy_texture(framebuf.color) + gl.DeleteRenderbuffers(1, &framebuf.depth) + gl.DeleteFramebuffers(1, &framebuf.handle) + + gl.DeleteProgram(shader_program) + + gl.DeleteBuffers(1, &vbo) + gl.DeleteVertexArrays(1, &vao) +} + +gl_start_frame :: proc() { + gl.BindFramebuffer(gl.FRAMEBUFFER, framebuf.handle) + gl.Viewport(0, 0, framebuf.color.size.x, framebuf.color.size.y) + renderer.projection = linalg.matrix_ortho3d( + f32(0), f32(framebuf.color.size.x), + f32(framebuf.color.size.y), 0, + -1, 1, + ) +} + +gl_end_frame :: proc() { + gl.BindFramebuffer(gl.FRAMEBUFFER, 0) + + w_width, w_height := glfw.GetWindowSize(window) + + gl.Viewport(0, 0, w_width, w_height) + + renderer.projection = linalg.matrix_ortho3d( + f32(0), f32(w_width), + 0, f32(w_height), + -1, 1, + ) + + draw_rect({0, 0}, {f32(w_width), f32(w_height)}, tex = framebuf.color) + flush_batch(&renderer.draw_call) +} + +gl_draw :: proc(draw_call: Draw_Call) { + draw_call := draw_call + + gl.UseProgram(shader_program) + + gl.ActiveTexture(gl.TEXTURE0) + gl.BindTexture(gl.TEXTURE_2D, draw_call.tex) + + gl.Uniform1i(tex0_loc, 0) + gl.UniformMatrix4fv( + projection_loc, + 1, + false, + transmute([^]f32)(&draw_call.projection), + ) + gl.UniformMatrix4fv(view_loc, 1, false, transmute([^]f32)(&draw_call.view)) + + gl.BindBuffer(gl.ARRAY_BUFFER, vbo) + gl.BufferData( + gl.ARRAY_BUFFER, + size_of(Vertex) * len(draw_call.vertices), + raw_data(draw_call.vertices), + gl.DYNAMIC_DRAW, + ) + + gl.BindVertexArray(vao) + + if !draw_call.indexed { + gl.DrawArrays( + enum_conv[draw_call.vertex_mode], + 0, + i32(len(draw_call.vertices)), + ) + } else { + gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebo) + gl.BufferData( + gl.ELEMENT_ARRAY_BUFFER, + size_of(Index) * len(draw_call.indices), + raw_data(draw_call.indices), + gl.DYNAMIC_DRAW, + ) + + gl.DrawElements( + enum_conv[draw_call.vertex_mode], + i32(len(draw_call.indices)), + gl.UNSIGNED_SHORT, + nil, + ) + gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, 0) + } + + gl.BindBuffer(gl.ARRAY_BUFFER, 0) + gl.BindVertexArray(0) +} + +gl_clear :: proc(col: Color) { + gl.ClearColor(col.r, col.g, col.b, col.a) + gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) +} + +gl_init_texture :: proc( + texture: ^Texture, + data: []u8, + channels: i32, +) { + tex: u32 + gl.GenTextures(1, &tex) + + format := gl.RGBA + switch channels { + case 3: format = gl.RGB + case 4: format = gl.RGBA + case: panic("Unsupported amount of channels. Must be either 3 or 4.") + } + + gl.BindTexture(gl.TEXTURE_2D, tex) + gl.TexImage2D( + gl.TEXTURE_2D, + 0, + i32(format), + texture.size.x, + texture.size.y, + 0, + u32(format), + gl.UNSIGNED_BYTE, + raw_data(data), + ) + + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) + + gl.GenerateMipmap(gl.TEXTURE_2D) + + texture.handle = tex +} + +gl_destroy_texture :: proc(texture: Texture_Handle) { + texture := texture + gl.DeleteTextures(1, &texture) +} + +gl_init_screen :: proc(screen_size: Vec2i) { + assert(screen_size.x * screen_size.y > 0) + + gl.GenFramebuffers(1, &framebuf.handle) + gl.BindFramebuffer(gl.FRAMEBUFFER, framebuf.handle) + + color_tex: u32 + gl.GenTextures(1, &color_tex) + gl.BindTexture(gl.TEXTURE_2D, color_tex) + + gl.TexImage2D( + gl.TEXTURE_2D, + 0, + gl.RGB, + screen_size.x, + screen_size.y, + 0, + gl.RGB, + gl.UNSIGNED_BYTE, + nil, + ) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) + + gl.FramebufferTexture2D( + gl.FRAMEBUFFER, + gl.COLOR_ATTACHMENT0, + gl.TEXTURE_2D, + color_tex, + 0, + ) + + framebuf.color = Texture { + handle = color_tex, + size = screen_size, + } + + gl.GenRenderbuffers(1, &framebuf.depth) + gl.BindRenderbuffer(gl.RENDERBUFFER, framebuf.depth) + gl.RenderbufferStorage( + gl.RENDERBUFFER, + gl.DEPTH_COMPONENT32F, + screen_size.x, + screen_size.y, + ); + gl.FramebufferRenderbuffer( + gl.FRAMEBUFFER, + gl.DEPTH_ATTACHMENT, + gl.RENDERBUFFER, + framebuf.depth, + ); + + if gl.CheckFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE { + log.fatal("[OPENGL] Framebuffer could not be completed") + os.exit(1) + } + + gl.BindFramebuffer(gl.FRAMEBUFFER, 0) +} diff --git a/src/fw/renderer.odin b/src/fw/renderer.odin new file mode 100644 index 0000000..082a0d3 --- /dev/null +++ b/src/fw/renderer.odin @@ -0,0 +1,390 @@ +package fw + +import "core:log" +import "core:image" +import "core:math" +import "core:math/linalg" +import "core:math/linalg/glsl" + +Index :: u16 + +Renderer_Backend :: enum { + OpenGL, +} + +Vertex_Mode :: enum { + None, + Triangles, + Triangle_Strip, + Triangle_Fan, + Lines, + Line_Strip, + Line_Loop, + Points, +} + +Blend_Mode :: enum { + Alpha, + Additive, +} + +@(private) +All_Enums :: union { + Vertex_Mode, +} + +VTable :: struct { + start_frame: proc(), + end_frame: proc(), + draw: proc(Draw_Call), + clear: proc(Color), + init_texture: proc( + texture: ^Texture, + data: []u8, + channels: i32, + ), + destroy_texture: proc(texture: Texture_Handle), + init_screen: proc(screen_size: Vec2i), +} + +Texture_Handle :: u32 + +Texture :: struct { + handle: Texture_Handle, // for opengl, this is just the actual handle. for + // others, it can be an index to the real handle. + size: Vec2i, +} + +Vertex :: struct { + pos: Vec3, + uv: Vec2, + color: Vec4, +} + +Draw_Call :: struct { + tex: Texture_Handle, + vertex_mode: Vertex_Mode, + model_mat: [dynamic]Mat4, + vertices: [dynamic]Vertex, + indices: [dynamic]Index, + + projection: Mat4, + view: Mat4, + + indexed: bool, +} + +renderer: struct { + draw_call: Draw_Call, + backend: Renderer_Backend, + bg_col: Color, + white_1x1: Texture, + projection: Mat4, + view: Mat4, + + draw_calls_count: i32, + _draw_call_counter: i32, + + vt: VTable, +} = {} + +@(private) +_renderer_init :: proc(config: Config) { + renderer.bg_col = Color{0.2, 0.2, 0.2, 1} + + renderer.projection = linalg.matrix_ortho3d(f32(0), 800, 800, 0, 0, 1) + renderer.view = linalg.identity(Mat4) + + renderer.backend = config.renderer_backend + + switch config.renderer_backend{ + case .OpenGL: gl_init() + } + + white_1x1_data := []u8{255, 255, 255} + renderer.white_1x1 = create_texture(white_1x1_data, {1, 1}, 3) + + renderer.vt.init_screen(config.screen_size) +} + +@(private) +_renderer_deinit :: proc() { + destroy_texture(renderer.white_1x1) + + switch renderer.backend { + case .OpenGL: gl_deinit() + } +} + +flush_batch :: proc(draw_call: ^Draw_Call) { + renderer.vt.draw(draw_call^) + renderer._draw_call_counter += 1 +} + +new_batch :: proc( + tex: Texture_Handle, + vertex_mode: Vertex_Mode, + indexed: bool, +) { + renderer.draw_call.tex = tex + renderer.draw_call.vertex_mode = vertex_mode + renderer.draw_call.indexed = indexed + renderer.draw_call.projection = renderer.projection + renderer.draw_call.view = renderer.view + + clear(&renderer.draw_call.vertices) + clear(&renderer.draw_call.indices) +} + +@(private="file") +_add_vertex :: #force_inline proc(v: Vertex) { + append(&renderer.draw_call.vertices, v) +} + +@(private="file") +_add_index :: #force_inline proc(i: u16, start: Index) { + append(&renderer.draw_call.indices, start + i) +} + +can_flush :: proc() -> bool { + return renderer.draw_call.vertex_mode != .None && + len(renderer.draw_call.vertices) != 0 && + len(renderer.draw_call.indices) != 0 +} + +try_batch_calls :: proc( + tex: Texture_Handle, + vertex_mode: Vertex_Mode, + indexed: bool, +) { + cant_flush := !can_flush() + if cant_flush { + new_batch(tex, vertex_mode, indexed) + return + } + + can_batch := tex == renderer.draw_call.tex && + vertex_mode == renderer.draw_call.vertex_mode && + indexed == renderer.draw_call.indexed + if !can_batch { + flush_batch(&renderer.draw_call) + new_batch(tex, vertex_mode, indexed) + } +} + +create_texture_from_image :: #force_inline proc(img: ^image.Image) -> Texture { + return create_texture( + img.pixels.buf[:], + {i32(img.width), i32(img.height)}, + i32(img.channels), + ) +} + +create_texture :: proc(data: []u8, size: Vec2i, channels: i32) -> Texture { + texture := Texture{ + size = size, + } + renderer.vt.init_texture(&texture, data, channels) + return texture +} + +destroy_texture :: proc(texture: Texture) { + renderer.vt.destroy_texture(texture.handle) +} + +draw_line :: proc( + start: Vec2, + end: Vec2, + depth: f32 = 0, + color := Color{1, 1, 1, 1}, +) { + try_batch_calls(renderer.white_1x1.handle, .Lines, true) + + reserve(&renderer.draw_call.vertices, len(renderer.draw_call.vertices) + 2) + reserve(&renderer.draw_call.indices, len(renderer.draw_call.indices) + 2) + + start_idx := Index(len(renderer.draw_call.vertices)) + + _add_vertex(Vertex{{start.x, start.y, depth}, {0.5, 0.5}, color}) + _add_vertex(Vertex{{end.x, end.y, depth}, {0.5, 0.5}, color}) + + _add_index(start_idx, 0) + _add_index(start_idx, 1) +} + +draw_rect :: proc( + pos: Vec2, + size: Vec2, + depth: f32 = 0, + color := Color{1, 1, 1, 1}, + tex := renderer.white_1x1, + lines := false, +) { + try_batch_calls(tex.handle, .Triangles if !lines else .Lines, true) + + depth := depth + + if depth < -1 || depth > 1 { + log.warnf( + "Depth is out of range (%v). It will be clamped to -1..1.", + depth + ) + depth = math.clamp(depth, -1, 1) + } + + pos := linalg.round(pos) + + tl := Vertex{{pos.x, pos.y, depth}, {0, 0}, color} + tr := Vertex{{pos.x + size.x, pos.y, depth}, {1, 0}, color} + bl := Vertex{{pos.x, pos.y + size.y, depth}, {0, 1}, color} + br := Vertex{{pos.x + size.x, pos.y + size.y, depth}, {1, 1}, color} + + start := Index(len(renderer.draw_call.vertices)) + + reserve(&renderer.draw_call.vertices, len(renderer.draw_call.vertices) + 4) + _add_vertex(tl) + _add_vertex(tr) + _add_vertex(bl) + _add_vertex(br) + + + if lines { + reserve(&renderer.draw_call.indices, len(renderer.draw_call.indices) + 8) + + _add_index(start, 0) + _add_index(start, 1) + _add_index(start, 1) + _add_index(start, 3) + _add_index(start, 3) + _add_index(start, 2) + _add_index(start, 2) + _add_index(start, 0) + } else { + reserve(&renderer.draw_call.indices, len(renderer.draw_call.indices) + 6) + + _add_index(start, 0) + _add_index(start, 1) + _add_index(start, 2) + _add_index(start, 2) + _add_index(start, 1) + _add_index(start, 3) + } +} + +draw_tex :: proc( + tex: Texture, + pos: Vec2, + depth: f32 = 0, + scale := Vec2{1, 1}, + offset := Vec2{0, 0}, + color := Color{1, 1, 1, 1} +) { + draw_rect( + pos = pos - offset, + size = Vec2{f32(tex.size.x), f32(tex.size.y)} * scale, + depth = depth, + tex = tex, + color = color, + ) +} + +draw_tile :: proc( + tex: Texture, + pos: Vec2, + rect: Rect, + depth: f32 = 0, + color := Color{1, 1, 1, 1} +) { + pos := linalg.round(pos) + + tex_size := Vec2{f32(tex.size.x), f32(tex.size.y)} + + uv_start := rect.start / tex_size + uv_end := (rect.start + rect.size) / tex_size + + size := rect.size + tl := Vertex{{pos.x, pos.y, depth}, {uv_start.x, uv_start.y}, color} + tr := Vertex{{pos.x + size.x, pos.y, depth}, {uv_end.x, uv_start.y}, color} + bl := Vertex{{pos.x, pos.y + size.y, depth}, {uv_start.x, uv_end.y}, color} + br := Vertex{{pos.x + size.x, pos.y + size.y, depth}, {uv_end.x, uv_end.y}, color} + + try_batch_calls(tex.handle, .Triangles, true) + + reserve(&renderer.draw_call.indices, len(renderer.draw_call.indices) + 6) + reserve(&renderer.draw_call.vertices, len(renderer.draw_call.vertices) + 4) + + start := Index(len(renderer.draw_call.vertices)) + + _add_vertex(tl) + _add_vertex(tr) + _add_vertex(bl) + _add_vertex(br) + + _add_index(start, 0) + _add_index(start, 1) + _add_index(start, 2) + _add_index(start, 2) + _add_index(start, 1) + _add_index(start, 3) +} + +draw_tex_ex :: proc( + tex: Texture, + pos: Vec2, + depth: f32 = 0, + rot: f32 = 0, + scale := Vec2{1, 1}, + offset := Vec2{0, 0}, + shear := Vec2{0, 0}, + rect: Maybe(Rect) = nil, + color := Color{1, 1, 1, 1} +) { + tex_size := Vec2{f32(tex.size.x), f32(tex.size.y)} + rect := rect.? or_else Rect{{0, 0}, tex_size} + + pos := linalg.round(pos) + + pos_m: Mat4 = linalg.matrix4_translate(Vec3{pos.x, pos.y, 0}) + rotation_m: Mat4 = linalg.matrix4_rotate(rot, Vec3{0, 0, 1}) + scale_m: Mat4 = linalg.matrix4_scale(Vec3{scale.x, scale.y, 0}) + offset_m: Mat4 = linalg.matrix4_translate(-Vec3{offset.x, offset.y, 0}) + shear_m: Mat4 = linalg.identity(Mat4) + shear_m[1,0] = shear.y + shear_m[0,1] = shear.x + + model := linalg.transpose(pos_m * rotation_m * scale_m * shear_m * offset_m) + + size := rect.size + + tl_pos := Vec4{0, 0, 0, 1} * model + tr_pos := Vec4{size.x, 0, 0, 1} * model + bl_pos := Vec4{0, size.y, 0, 1} * model + br_pos := Vec4{size.x, size.y, 0, 1} * model + + uv_start := rect.start / tex_size + uv_end := (rect.start + rect.size) / tex_size + + tl := Vertex{{tl_pos.x, tl_pos.y, depth}, {uv_start.x, uv_start.y}, color} + tr := Vertex{{tr_pos.x, tr_pos.y, depth}, {uv_end.x, uv_start.y}, color} + bl := Vertex{{bl_pos.x, bl_pos.y, depth}, {uv_start.x, uv_end.y}, color} + br := Vertex{{br_pos.x, br_pos.y, depth}, {uv_end.x, uv_end.y}, color} + + try_batch_calls(tex.handle, .Triangles, true) + + reserve(&renderer.draw_call.indices, len(renderer.draw_call.indices) + 6) + reserve(&renderer.draw_call.vertices, len(renderer.draw_call.vertices) + 4) + + start := Index(len(renderer.draw_call.vertices)) + + _add_vertex(tl) + _add_vertex(tr) + _add_vertex(bl) + _add_vertex(br) + + _add_index(start, 0) + _add_index(start, 1) + _add_index(start, 2) + _add_index(start, 2) + _add_index(start, 1) + _add_index(start, 3) +} diff --git a/src/fw/shader.frag b/src/fw/shader.frag new file mode 100644 index 0000000..fdc8796 --- /dev/null +++ b/src/fw/shader.frag @@ -0,0 +1,16 @@ +#version 430 core + +in vec2 f_uv; +in vec4 f_col; + +out vec4 final_color; + +uniform sampler2D tex0; + +void main() { + vec4 color = texture(tex0, f_uv) * f_col; + if (color.a <= 0.5) { + discard; + } + final_color = color; +} diff --git a/src/fw/shader.vert b/src/fw/shader.vert new file mode 100644 index 0000000..6bf4e24 --- /dev/null +++ b/src/fw/shader.vert @@ -0,0 +1,18 @@ +#version 430 core + +layout (location = 0) in vec3 v_pos; +layout (location = 1) in vec2 v_uv; +layout (location = 2) in vec4 v_col; + +out vec2 f_uv; +out vec4 f_col; + +uniform mat4 projection; +uniform mat4 view; + +void main() { + gl_Position = projection * view * vec4(v_pos, 1.0); + + f_uv = v_uv; + f_col = v_col; +} diff --git a/src/input.odin b/src/input.odin index 8326564..ee90fcd 100644 --- a/src/input.odin +++ b/src/input.odin @@ -1,67 +1,25 @@ package demonchime -import rl "vendor:raylib" - -KeyboardInput :: union { - rl.KeyboardKey, - rl.MouseButton, -} - -ControllerInput :: union { -} - -Keybind :: struct { - input: KeyboardInput, - pressed: bool, - just_pressed: bool, -} +import fw "fw" actions: struct { - move_left: Keybind, - move_right: Keybind, - jump: Keybind, - dash: Keybind, - shoot: Keybind, - toggle_debug_mode: Keybind, + move_left: fw.Keybind, + move_right: fw.Keybind, + jump: fw.Keybind, + dash: fw.Keybind, + shoot: fw.Keybind, + toggle_debug_mode: fw.Keybind, + toggle_fullscreen: fw.Keybind, + exit: fw.Keybind, } init_keybinds :: proc() { actions.move_left.input = .A actions.move_right.input = .D - actions.jump.input = .SPACE - actions.dash.input = .LEFT_SHIFT - actions.shoot.input = rl.MouseButton.LEFT - actions.toggle_debug_mode.input = .GRAVE -} - -is_keybind_down :: proc(keybind: Keybind) -> bool { - switch val in keybind.input { - case rl.KeyboardKey: - return rl.IsKeyDown(val) - case rl.MouseButton: - return rl.IsMouseButtonDown(val) - } - - assert(false) - return false -} - -is_keybind_just_down :: proc(keybind: Keybind) -> bool { - switch val in keybind.input { - case rl.KeyboardKey: - return rl.IsKeyPressed(val) - case rl.MouseButton: - return rl.IsMouseButtonPressed(val) - } - - assert(false) - return false -} - -get_mouse_pos :: proc() -> (mouse_pos: Vec2) { - mouse_pos = Vec2{f32(rl.GetMouseX()), f32(rl.GetMouseY())} - mouse_pos /= Vec2{f32(rl.GetScreenWidth()), f32(rl.GetScreenHeight())} - mouse_pos *= SCREEN_SIZE - mouse_pos += state.camera.target - return + actions.jump.input = .Space + actions.dash.input = .Left_Shift + actions.shoot.input = fw.Mouse_Button.Left + actions.toggle_debug_mode.input = .T + actions.toggle_fullscreen.input = .F11 + actions.exit.input = .Escape } diff --git a/src/main.odin b/src/main.odin index a0c2fcb..20ea221 100644 --- a/src/main.odin +++ b/src/main.odin @@ -6,30 +6,32 @@ import "core:c" import "core:c/libc" import "core:fmt" import "core:log" -import "core:mem" import "core:math" import "core:math/linalg" - -import rl "vendor:raylib" +import "core:mem" import "phys" +import "fw" -Vec2 :: [2]f32 - -Rect :: struct { - start: Vec2, - size: Vec2, -} +Vec2 :: fw.Vec2 +Vec2i :: fw.Vec2i +Color :: fw.Color +Rect :: fw.Rect ROOM_FADE_SIZE :: 8 FIXED_UPDATE_RATE :: 1.0/60 +SCREEN_WIDTH :: 256 +SCREEN_HEIGHT :: 256 +SCREEN_SIZE :: Vec2{SCREEN_WIDTH, SCREEN_HEIGHT} +SCREEN_SIZE_INT :: Vec2i{SCREEN_WIDTH, SCREEN_HEIGHT} + state: struct { debug_mode: bool, camera_target: Vec2, last_fixed_update: f64, - camera: rl.Camera2D, + // camera: rl.Camera2D, prop_list: Entity_List(Prop), wiggle_prop_list: Entity_List(Wiggle_Prop), platform_list: Entity_List(Platform), @@ -39,46 +41,33 @@ state: struct { logger: log.Logger -raylib_log :: proc "c" ( - msg_type: rl.TraceLogLevel, - fmt: cstring, - args: ^c.va_list, -) { - context = runtime.default_context() - context.logger = logger - - msg_bytes: [1028]u8 - libc.vsnprintf(raw_data(msg_bytes[:]), 1028, fmt, args) - - msg := string(msg_bytes[:]) - - #partial switch msg_type { - case .DEBUG: log.debug(msg) - case .INFO: log.info(msg) - case .WARNING: log.warn(msg) - case .ERROR: log.error(msg) - case .FATAL: log.fatal(msg) - } -} - init :: proc() { - state.camera.zoom = 1 + fw.init({ + win_name = "Demonchime", + win_size = SCREEN_SIZE_INT * 3, + screen_size = SCREEN_SIZE_INT, + renderer_backend = .OpenGL, + }) init_keybinds() - init_draw() init_player() open_room(.Carrabassett0) } frame :: proc() { - if is_keybind_just_down(actions.toggle_debug_mode) { + if fw.is_keybind_just_down(actions.toggle_debug_mode) { state.debug_mode = !state.debug_mode } - dt := rl.GetFrameTime() + if fw.is_keybind_just_down(actions.toggle_fullscreen) { + // rl.ToggleBorderlessWindowed() + // rl.ToggleFullscreen() + } - if rl.GetTime() - state.last_fixed_update > FIXED_UPDATE_RATE { - state.last_fixed_update = rl.GetTime() + dt := f32(fw.get_delta_time()) + + if fw.get_time() - state.last_fixed_update > FIXED_UPDATE_RATE { + state.last_fixed_update = fw.get_time() for cb in fixed_update_callbacks { cb(FIXED_UPDATE_RATE) } @@ -88,24 +77,21 @@ frame :: proc() { cb(dt) } - state.camera.target = dt_lerp( - state.camera.target, - state.camera_target, - CAMERA_ACCEL, - ) - - draw_new_frame() - - cam := state.camera - cam.target = linalg.round(cam.target) - rl.BeginMode2D(cam) - - renderer.tint = get_room(current_room.id).background_color - draw_rect({ + // state.camera.target = dt_lerp( + // state.camera.target, + // state.camera_target, + // CAMERA_ACCEL, + // ) + + // cam := state.camera + // cam.target = linalg.round(cam.target) + // rl.BeginMode2D(cam) + + fw.draw_rect( {0, 0}, {f32(current_room.width), f32(current_room.height)}, - }) - renderer.tint = {1, 1, 1, 1} + color = get_room(current_room.id).background_color, + ) for cb in draw_callbacks { cb() @@ -113,66 +99,63 @@ frame :: proc() { draw_room(current_room.id) - rl.DrawRectangleGradientH( - 0, - 0, - ROOM_FADE_SIZE, - current_room.height, - rl.BLACK, - rl.BLANK, - ) - rl.DrawRectangleGradientH( - current_room.width - ROOM_FADE_SIZE, - 0, - ROOM_FADE_SIZE, - current_room.height, - rl.BLANK, - rl.BLACK, - ) - rl.DrawRectangleGradientV( - 0, - 0, - current_room.width, - ROOM_FADE_SIZE, - rl.BLACK, - rl.BLANK, - ) - rl.DrawRectangleGradientV( - 0, - current_room.height - ROOM_FADE_SIZE, - current_room.width, - ROOM_FADE_SIZE, - rl.BLANK, - rl.BLACK, - ) + // rl.DrawRectangleGradientH( + // 0, + // 0, + // ROOM_FADE_SIZE, + // current_room.height, + // rl.BLACK, + // rl.BLANK, + // ) + // rl.DrawRectangleGradientH( + // current_room.width - ROOM_FADE_SIZE, + // 0, + // ROOM_FADE_SIZE, + // current_room.height, + // rl.BLANK, + // rl.BLACK, + // ) + // rl.DrawRectangleGradientV( + // 0, + // 0, + // current_room.width, + // ROOM_FADE_SIZE, + // rl.BLACK, + // rl.BLANK, + // ) + // rl.DrawRectangleGradientV( + // 0, + // current_room.height - ROOM_FADE_SIZE, + // current_room.width, + // ROOM_FADE_SIZE, + // rl.BLANK, + // rl.BLACK, + // ) if state.debug_mode { // Draw all collisions body_it: int - renderer.tint = {1, 0.25, 0.5, 0.25} + color := Color{1, 0.25, 0.5, 0.25} for body in phys.iterate_bodies(&body_it) { rect := phys.get_rect(body) rect.start += phys.get_position(body) - draw_linerect(transmute(Rect)rect) - draw_rect(transmute(Rect)rect) + fw.draw_rect(rect.start, rect.size, color = color, lines = true) + fw.draw_rect(rect.start, rect.size, color = color) } - renderer.tint = {1, 1, 1, 1} } - rl.EndMode2D() - - fps_text := fmt.caprintf( - "FPS: %v", - rl.GetFPS(), - allocator = context.temp_allocator, - ) - rl.DrawText(fps_text, 5, 5, 8, rl.GREEN) - - if state.debug_mode { - rl.DrawText("Debug Mode", 5, 5 + 8, 8, rl.YELLOW) - } - - draw_end_frame() + // rl.EndMode2D() + // + // fps_text := fmt.caprintf( + // "FPS: %v", + // rl.GetFPS(), + // allocator = context.temp_allocator, + // ) + // rl.DrawText(fps_text, 5, 5, 8, rl.GREEN) + // + // if state.debug_mode { + // rl.DrawText("Debug Mode", 5, 5 + 8, 8, rl.YELLOW) + // } } cleanup :: proc() { @@ -186,6 +169,8 @@ cleanup :: proc() { delete_entity_list(state.rope_list) phys.destroy_world() + + fw.deinit() } main :: proc() { @@ -222,18 +207,14 @@ main :: proc() { context.logger = logger defer log.destroy_console_logger(logger) - rl.SetTraceLogCallback(raylib_log) - - rl.InitWindow(SCREEN_WIDTH * 3, SCREEN_HEIGHT * 3, "Demonchime") - rl.SetWindowState({.WINDOW_RESIZABLE}) - - rl.SetTargetFPS(240) - init() - for !rl.WindowShouldClose() { + for fw.next_frame() { frame() - free_all(context.temp_allocator) + + if fw.is_keybind_just_down(actions.exit) { + break + } } cleanup() diff --git a/src/math.odin b/src/math.odin index 0cd2a27..131da63 100644 --- a/src/math.odin +++ b/src/math.odin @@ -3,7 +3,7 @@ package demonchime import "core:math" import "core:math/linalg" -import rl "vendor:raylib" +import "fw" dt_lerp :: proc { dt_lerp_f32, @@ -11,7 +11,7 @@ dt_lerp :: proc { } dt_lerp_f32 :: proc(a: f32, b: f32, t: f32) -> f32 { - dt := rl.GetFrameTime() + dt := f32(fw.get_delta_time()) return math.lerp(b, a, math.pow(0.5, dt * t)) } diff --git a/src/phys/world.odin b/src/phys/world.odin index 70309b5..5207622 100644 --- a/src/phys/world.odin +++ b/src/phys/world.odin @@ -4,7 +4,7 @@ import "core:log" import "core:math" import "core:math/linalg" -import rl "vendor:raylib" +import "../fw" BIN_COUNT :: 2056 BIN_SIZE :: 64 @@ -191,7 +191,7 @@ get_colliding_bodies :: proc( } update_body :: proc(h: Body_Handle) { - dt := rl.GetFrameTime() + dt := f32(fw.get_delta_time()) b := _get_body(h) diff --git a/src/platform.odin b/src/platform.odin index a974811..38ce950 100644 --- a/src/platform.odin +++ b/src/platform.odin @@ -1,5 +1,6 @@ package demonchime +import "fw" import "phys" Platform :: struct { @@ -8,18 +9,17 @@ Platform :: struct { } make_platform :: proc(rect: Rect) -> (Entity_Handle, ^Platform) { - body := phys.make_body(transmute(phys.Rect)rect) - return make_entity(&state.platform_list, Platform{body = body}) + handle := phys.make_body(transmute(phys.Rect)rect) + return make_entity(&state.platform_list, Platform{body = handle}) } draw_platforms :: proc() { iter := iter_entity_list(state.platform_list) - renderer.tint = {1, 0, 0, 0.25} + color := Color{1, 0, 0, 0.25} for p in entity_list_iter(&iter) { rect := phys.get_rect(p.body) - draw_rect(cast(Rect)rect) + fw.draw_rect(rect.start, rect.size, color = color) } - renderer.tint = {1, 1, 1, 1} } clear_platforms :: proc() { diff --git a/src/player.odin b/src/player.odin index c87d2a6..5b0dd01 100644 --- a/src/player.odin +++ b/src/player.odin @@ -4,9 +4,8 @@ import "core:math" import "core:math/linalg" import "core:log" -import rl "vendor:raylib" - import "phys" +import "fw" Player_State :: enum { Default, @@ -72,10 +71,10 @@ _get_input_dir :: proc() -> f32 { input: f32 - if is_keybind_down(actions.move_left) { + if fw.is_keybind_down(actions.move_left) { input -= 1 } - if is_keybind_down(actions.move_right) { + if fw.is_keybind_down(actions.move_right) { input += 1 } @@ -92,12 +91,12 @@ _default_state :: proc(dt: f32) { set_sprite_active_tag(&player.sprite, "idle") } - if is_keybind_just_down(actions.jump) { + if fw.is_keybind_just_down(actions.jump) { player.jump_buffer = PLAYER_JUMP_BUFFERING } if player.owns_dash && - is_keybind_just_down(actions.dash) && + fw.is_keybind_just_down(actions.dash) && player.dash_cooldown <= 0 { _enter_dash() return @@ -122,9 +121,9 @@ _default_state :: proc(dt: f32) { } } - rel_mouse_pos := get_mouse_pos() - pos + rel_mouse_pos := fw.get_mouse_pos() - pos - if is_keybind_just_down(actions.shoot) { + if fw.is_keybind_just_down(actions.shoot) { mouse_dir := linalg.normalize0(rel_mouse_pos + {0, PLAYER_GUN_HEIGHT}) bullet_pos := pos @@ -157,7 +156,7 @@ _default_state :: proc(dt: f32) { } if .Down not_in collisions && - !is_keybind_down(actions.jump) && + !fw.is_keybind_down(actions.jump) && vel.y < PLAYER_JUMP_RELEASE_CUT { vel.y = PLAYER_JUMP_RELEASE_CUT } @@ -257,8 +256,8 @@ _change_rooms :: proc() { } new_cam_pos := _get_camera_target_pos() - state.camera.target += diff - state.camera_target += diff + // state.camera.target += diff + // state.camera_target += diff } } @@ -274,11 +273,8 @@ update_player :: proc(dt: f32) { update_sprite(&player.sprite, dt) - mouse_dir := linalg.normalize0(get_mouse_pos() - player.gun.sprite.pos) - player.gun.sprite.rotation = math.atan2( - mouse_dir.y, - mouse_dir.x, - ) * math.DEG_PER_RAD + mouse_dir := linalg.normalize0(fw.get_mouse_pos() - player.gun.sprite.pos) + player.gun.sprite.rotation = math.atan2(mouse_dir.y, mouse_dir.x) player.gun.sprite.pos = pos - Vec2{0, PLAYER_GUN_HEIGHT} player.gun.sprite.pos += -mouse_dir * player.gun.kickback diff --git a/src/prop.odin b/src/prop.odin index 34d4559..35e16e8 100644 --- a/src/prop.odin +++ b/src/prop.odin @@ -3,8 +3,7 @@ package demonchime import "core:math/linalg" import "core:log" -import rl "vendor:raylib" - +import "fw" import "phys" Prop :: struct { @@ -22,7 +21,7 @@ draw_props :: proc() { iter := iter_entity_list(state.prop_list) for p in entity_list_iter(&iter) { image := get_image(p.image_id) - draw_texture( + fw.draw_tex( image, p.pos, scale = p.scale, @@ -36,8 +35,8 @@ Wiggle_Prop :: struct { pos: Vec2, scale: Vec2, offset: Vec2, - rotation: f32, - rotation_factor: f32, + shear: f32, + shear_factor: f32, } make_wiggle_prop :: proc(prop: Wiggle_Prop) -> (Entity_Handle, ^Wiggle_Prop) { @@ -52,23 +51,23 @@ update_wiggle_props :: proc(dt: f32) { image := get_image(p.image_id) dist := linalg.length(p.pos - player_pos) - dist = f32(max(image.width, image.height)) - dist + dist = f32(max(image.size.x, image.size.y)) - dist if dist < 0 { dist = 0 } - p.rotation = player_vel.x / PLAYER_SPEED * dist * p.rotation_factor + p.shear = player_vel.x / PLAYER_SPEED * dist * p.shear_factor } } draw_wiggle_props :: proc() { iter := iter_entity_list(state.wiggle_prop_list) for p in entity_list_iter(&iter) { - draw_texture_full( + fw.draw_tex_ex( get_image(p.image_id), p.pos, - p.offset, - p.rotation, - p.scale, + offset = p.offset, + // rot = p.rotation, + shear = Vec2{-p.shear, 0}, ) } } @@ -95,7 +94,7 @@ object_spawner_prop :: proc(obj: Object_Resource) { tile := tiles[tile_id] img := get_image(tile.image) - pos := obj.pos - Vec2{0, f32(img.height)} + pos := obj.pos - Vec2{0, f32(img.size.y)} scale := Vec2{1, 1} if obj.size.x < 0 { scale.x = -1 @@ -114,14 +113,14 @@ object_spawner_prop :: proc(obj: Object_Resource) { .Windchimes_0, .Windchimes_1: offset := linalg.round(Vec2{ - f32(img.width) * 0.5, + f32(img.size.x) * 0.5, 0, }) - rotation_factor: f32 = 1 + shear_factor: f32 = 1 #partial switch tile.image { case .Carrabasset_Vines_0: - rotation_factor = 0.25 + shear_factor = 0.1 } make_wiggle_prop(Wiggle_Prop{ @@ -129,18 +128,18 @@ object_spawner_prop :: proc(obj: Object_Resource) { pos = pos + offset, scale = scale, offset = offset, - rotation_factor = -rotation_factor, + shear_factor = -shear_factor, }) case .Carrabassett_Small_Bush_0, .Carrabassett_Big_Bush_0: offset := linalg.round(Vec2{ - f32(img.width) * 0.5, - f32(img.height), + f32(img.size.x) * 0.5, + f32(img.size.y), }) - rotation_factor: f32 = 1 + shear_factor: f32 = 0.01 #partial switch tile.image { case .Carrabassett_Big_Bush_0: - rotation_factor = 0.25 + shear_factor = 0.01 } make_wiggle_prop(Wiggle_Prop{ @@ -148,7 +147,7 @@ object_spawner_prop :: proc(obj: Object_Resource) { pos = pos + offset, scale = scale, offset = offset, - rotation_factor = rotation_factor, + shear_factor = shear_factor, }) case: make_prop(Prop{ diff --git a/src/resources.odin b/src/resources.odin index 1bd567e..22fed57 100644 --- a/src/resources.odin +++ b/src/resources.odin @@ -1,8 +1,10 @@ package demonchime +import "core:image" +import "core:image/qoi" import "core:log" -import rl "vendor:raylib" +import "fw" Tiled_Property :: union { string, @@ -12,7 +14,7 @@ Tiled_Property :: union { } Image_Resource :: struct { - texture: rl.Texture2D, + texture: fw.Texture, anim: Animation_Id, data: []u8, } @@ -73,21 +75,15 @@ Room_Position_Resource :: struct { height: i32, } -get_image :: proc(id: Image_Id) -> rl.Texture2D { +get_image :: proc(id: Image_Id) -> fw.Texture { img_res := &images[id] - if !rl.IsTextureValid(img_res.texture) { - rl_img := rl.LoadImageFromMemory( - ".qoi", - raw_data(img_res.data), - i32(len(img_res.data)), - ) - if !rl.IsImageValid(rl_img) { - log.warnf("Could not load asset %v", id) - } - - img_res.texture = rl.LoadTextureFromImage(rl_img) - rl.UnloadImage(rl_img) + if img_res.texture.handle == 0 { + img, qoi_err := qoi.load_from_bytes(img_res.data) + defer image.destroy(img) + + img_res.texture = fw.create_texture_from_image(img) + log.debug(img_res.texture.size) } return img_res.texture diff --git a/src/rope.odin b/src/rope.odin index b321dab..7e2cbe1 100644 --- a/src/rope.odin +++ b/src/rope.odin @@ -4,7 +4,7 @@ import "core:log" import "core:math" import "core:math/linalg" -import rl "vendor:raylib" +import "fw" Rope :: struct { handle: Entity_Handle, @@ -25,10 +25,10 @@ draw_ropes :: proc() { for i in 0.. bool { draw_room :: proc(id: Room_Id) { draw_tile :: proc(x: i32, y: i32, tile_id: u32) { tile := tiles[tile_id] - rl.DrawTexturePro( + fw.draw_tile( get_image(tile.image), - rl.Rectangle { - x = f32(tile.rect.start.x), - y = f32(tile.rect.start.y), - width = f32(tile.rect.size.x), - height = f32(tile.rect.size.y), + Vec2{f32(x), f32(y)}, + Rect{ + {f32(tile.rect.start.x), f32(tile.rect.start.y)}, + {f32(tile.rect.size.x), f32(tile.rect.size.y)}, }, - rl.Rectangle { - x = f32(x), - y = f32(y), - width = f32(tile.rect.size.x), - height = f32(tile.rect.size.y), - }, - {0, 0}, - 0, - rl.WHITE, ) } -- cgit v1.3-2-g0d8e