-- WASM-4: https://wasm4.org/docs -- Configure compiler. -- NOTE: This must come first because it changes some compiler settings! ##[[ ldflags "-Wl,-zstack-size=14752,--no-entry,--import-memory -mexec-model=reactor" ldflags "-Wl,--initial-memory=65536,--max-memory=65536,--stack-first,--export-dynamic" if DEBUG then -- We should use at least 01 optimization, otherwise the application may use too much stack space. cflags "-O1 -g" ldflags "-Wl,--export-all,--no-gc-sections" else -- Optimization for the making the application small as possible. cflags "-Oz -g0 -flto" ldflags "-Wl,--strip-all,--gc-sections,--lto-O3" end -- Generates an illegal instruction on aborts/panics context.rootpragmas.abort = "trap" -- We will not write to stdout, instead any write to it will be hooked. context.rootpragmas.writestderr = "hooked" -- We don't need to emit `main()` entry point, we will hook this ourselves. context.rootpragmas.nogcentry = true -- Bundle `snprintf` (used by `string.format`). context.rootpragmas.usenanoprintf = true ]] -- ┌───────────────────────────────────────────────────────────────────────────┐ -- │ │ -- │ Platform Constants │ -- │ │ -- └───────────────────────────────────────────────────────────────────────────┘ global SCREEN_SIZE = 160 global FONT_SIZE = 8 -- ┌───────────────────────────────────────────────────────────────────────────┐ -- │ │ -- │ Memory Addresses │ -- │ │ -- └───────────────────────────────────────────────────────────────────────────┘ global PALETTE = (@*[4]uint32)(0x04) global DRAW_COLORS = (@*uint16)(0x14) global GAMEPAD1 = (@*uint8)(0x16) global GAMEPAD2 = (@*uint8)(0x17) global GAMEPAD3 = (@*uint8)(0x18) global GAMEPAD4 = (@*uint8)(0x19) global MOUSE_X = (@*int16)(0x1a) global MOUSE_Y = (@*int16)(0x1c) global MOUSE_BUTTONS = (@*uint8)(0x1e) global SYSTEM_FLAGS = (@*uint8)(0x1f) global NETPLAY = (@*uint8)(0x20) global FRAMEBUFFER = (@*[6400]uint8)(0xa0) global BUTTON_1 = 1 global BUTTON_2 = 2 global BUTTON_LEFT = 16 global BUTTON_RIGHT = 32 global BUTTON_UP = 64 global BUTTON_DOWN = 128 global MOUSE_LEFT = 1 global MOUSE_RIGHT = 2 global MOUSE_MIDDLE = 4 global SYSTEM_PRESERVE_FRAMEBUFFER = 1 global SYSTEM_HIDE_GAMEPAD_OVERLAY = 2 -- ┌───────────────────────────────────────────────────────────────────────────┐ -- │ │ -- │ Drawing Functions │ -- │ │ -- └───────────────────────────────────────────────────────────────────────────┘ -- Copies pixels to the framebuffer. global function blit(data: *[0]uint8, x: int32, y: int32, width: uint32, height: uint32, flags: uint32): void end -- Copies a subregion within a larger sprite atlas to the framebuffer. global function blitSub(data: *[0]uint8, x: int32, y: int32, width: uint32, height: uint32, srcX: uint32, srcY: uint32, stride: uint32, flags: uint32): void end global BLIT_2BPP = 1 global BLIT_1BPP = 0 global BLIT_FLIP_X = 2 global BLIT_FLIP_Y = 4 global BLIT_ROTATE = 8 -- Draws a line between two points. global function line(x1: int32, y1: int32, x2: int32, y2: int32): void end -- Draws a horizontal line. global function hline(x: int32, y: int32, len: uint32): void end -- Draws a vertical line. global function vline(x: int32, y: int32, len: uint32): void end -- Draws an oval (or circle). global function oval(x: int32, y: int32, width: uint32, height: uint32): void end -- Draws a rectangle. global function rect(x: int32, y: int32, width: uint32, height: uint32): void end -- Draws text using the built-in system font. global function text(str: cstring, x: int32, y: int32): void end -- ┌───────────────────────────────────────────────────────────────────────────┐ -- │ │ -- │ Sound Functions │ -- │ │ -- └───────────────────────────────────────────────────────────────────────────┘ -- Plays a sound tone. global function tone(frequency: uint32, duration: uint32, volume: uint32, flags: uint32): void end global TONE_PULSE1 = 0 global TONE_PULSE2 = 1 global TONE_TRIANGLE = 2 global TONE_NOISE = 3 global TONE_MODE1 = 0 global TONE_MODE2 = 4 global TONE_MODE3 = 8 global TONE_MODE4 = 12 global TONE_PAN_LEFT = 16 global TONE_PAN_RIGHT = 32 global TONE_NOTE_MODE = 64 -- ┌───────────────────────────────────────────────────────────────────────────┐ -- │ │ -- │ Storage Functions │ -- │ │ -- └───────────────────────────────────────────────────────────────────────────┘ -- Reads up to `size` bytes from persistent storage into the pointer `dest`. global function diskr(dest: pointer, size: uint32): uint32 end -- Writes up to `size` bytes from the pointer `src` into persistent storage. global function diskw(src: pointer, size: uint32): uint32 end -- ┌───────────────────────────────────────────────────────────────────────────┐ -- │ │ -- │ Trace functions │ -- │ │ -- └───────────────────────────────────────────────────────────────────────────┘ -- Prints a message to the debug console. global function trace(str: cstring): void end -- Prints a message to the debug console (C style printf). global function tracef(format: cstring, ...: cvarargs): void end -- ┌───────────────────────────────────────────────────────────────────────────┐ -- │ │ -- │ Nelua hooks and compiler configuration │ -- │ │ -- └───────────────────────────────────────────────────────────────────────────┘ ## if not pragmas.nogc then require 'allocators.gc' ## end require "stringbuilder" -- for `print()` -- Hook runtime errors to write using `trace()` instead of writing to C `stderr`. local function write_stderr(msg: cstring, len: usize, flush: boolean): void trace(msg) end -- Replace global print function to write using `trace()` instead of writing to C `stdout`. global function print(...: varargs) local sb: stringbuilder ## for i=1,select('#', ...) do ## if i > 1 then sb:write('\t') ## end sb:write(#[select(i, ...)]#) ## end trace(sb:view()) end -- Macro used to install `update` and `_start` WASM4 callbacks. ## function setup_wasm4_callbacks(update) ## static_assert(update, 'please declare update function!') local function _update(): void #[update]#() ## if not pragmas.nogc then -- We must always manually call garbage collection in the end of every frame. -- This is the only safe point to do so, because in WASM we cannot scan the function stack. gc:step() ## end end -- Hook application entry point. local function _start(): void ## if not pragmas.nogc then -- The GC should be initialized as the first thing. gc:init(nilptr) ## end local function nelua_main(argc: cint, argv: *cstring): cint end -- This will all code in top scopes. nelua_main(0,nilptr) end ## end