From e6144d904264edcc80b5f99e7c68c42c6f779335 Mon Sep 17 00:00:00 2001 From: Vasiliy Tereshkov Date: Thu, 9 Nov 2023 12:28:26 +0100 Subject: [PATCH] Bump submodules --- lib/umka | 2 +- src/bindings.c | 5 +- src/main.c | 2 +- src/nav.c | 7 +- src/staembed.c | 4731 +++++++++++++++--------------------------------- src/tophat.h | 2 +- umka/nav.um | 8 +- 7 files changed, 1514 insertions(+), 3243 deletions(-) diff --git a/lib/umka b/lib/umka index 707176f6..a482259e 160000 --- a/lib/umka +++ b/lib/umka @@ -1 +1 @@ -Subproject commit 707176f6aac9a7b8d95290fdca8ac7f3e9e023bf +Subproject commit a482259e64ae60c46350d252923d32b1f219e25b diff --git a/src/bindings.c b/src/bindings.c index cccfd6d4..7673738e 100644 --- a/src/bindings.c +++ b/src/bindings.c @@ -1110,12 +1110,13 @@ umth_nav_mesh_add_quad(UmkaStackSlot *p, UmkaStackSlot *r) void umth_nav_mesh_nav(UmkaStackSlot *p, UmkaStackSlot *r) { - th_vf2s *cameFrom = p[3].ptrVal; + th_vf2s *cameFrom = p[4].ptrVal; + void *cameFromType = p[3].ptrVal; th_navmesh *m = p[2].ptrVal; th_vf2 p1 = *(th_vf2 *)&p[1]; th_vf2 p2 = *(th_vf2 *)&p[0]; - th_navmesh_nav(cameFrom, m, p1, p2); + th_navmesh_nav(cameFrom, cameFromType, m, p1, p2); } void diff --git a/src/main.c b/src/main.c index e277f232..8e5cfcd8 100644 --- a/src/main.c +++ b/src/main.c @@ -38,7 +38,7 @@ warning(UmkaError *error) int th_init(const char *scriptpath, const char *script_src) { - char *mainmod_fmt = "import (mainmod = \"%s\"; \"window.um\"; \"nav.um\")\n" + char *mainmod_fmt = "import (mainmod = \"%s\"; \"window.um\")\n" "fn main() {}\n" "fn __th_init*() {\n" " mainmod.init()\n" diff --git a/src/nav.c b/src/nav.c index 8c766a39..b799289e 100644 --- a/src/nav.c +++ b/src/nav.c @@ -97,17 +97,15 @@ check_bounds(th_navmesh *m, th_vf2 p, size_t h) return p.x >= 0 && p.y >= 0 && p.x < m->w && p.y < h; } -static void *umka_vf2s = NULL; - void -th_navmesh_nav(th_vf2s *cameFrom, th_navmesh *m, th_vf2 p1, th_vf2 p2) +th_navmesh_nav(th_vf2s *cameFrom, void *cameFromType, th_navmesh *m, th_vf2 p1, th_vf2 p2) { const th_vf2 movemap[] = {{{-1, -1}}, {{+0, -1}}, {{+1, -1}}, {{-1, +0}}, {{+1, +0}}, {{-1, +1}}, {{+0, +1}}, {{+1, +1}}}; const size_t msiz = umkaGetDynArrayLen((void *)&m->d); const size_t mh = msiz / m->w; - umkaMakeDynArray(thg->umka, cameFrom, umka_vf2s, msiz); + umkaMakeDynArray(thg->umka, cameFrom, cameFromType, msiz); for (int i = 0; i < msiz; ++i) { cameFrom->data[i].x = -1; @@ -174,5 +172,4 @@ th_navmesh_nav(th_vf2s *cameFrom, th_navmesh *m, th_vf2 p1, th_vf2 p2) void th_nav_init(void) { - umka_vf2s = umkaGetType(thg->umka, "nav.um", "Vf2s"); } diff --git a/src/staembed.c b/src/staembed.c index 5217a680..730f1548 100644 --- a/src/staembed.c +++ b/src/staembed.c @@ -3071,17 +3071,15 @@ const char *th_em_modulesrc[] = { "\tumth_nav_mesh_add_quad(m, &q)\n" "}\n" "\n" -"type Vf2s* = []th.Vf2\n" -"\n" -"fn umth_nav_mesh_nav(cameFrom: ^Vf2s, m: ^Mesh, p1, p2: th.Vf2)\n" +"fn umth_nav_mesh_nav(cameFrom: ^[]th.Vf2, cameFromType: ^void, m: ^Mesh, p1, p2: th.Vf2)\n" "//~~fn Mesh.nav\n" "// Navigates between `p1` and `p2`. Returns the path as an array of `th.Vf2`s.\n" "// If it doesn\'t find any path, or one of the points is outside of the mask,\n" "// returns an empty array.\n" "fn (m: ^Mesh) nav*(p1, p2: th.Vf2): []th.Vf2 {\n" "//~~\n" -"\tvar cameFrom: Vf2s\n" -"\tumth_nav_mesh_nav(&cameFrom, m, p1, p2)\n" +"\tvar cameFrom: []th.Vf2\n" +"\tumth_nav_mesh_nav(&cameFrom, typeptr([]th.Vf2), m, p1, p2)\n" "\t\n" "\tpath := []th.Vf2{p2}\n" "\tp := p2\n" @@ -3931,2054 +3929,253 @@ const char *th_em_modulesrc[] = { "\treturn gui\n" "}\n" "", +}; +const char *th_em_modulenames[] = { "anim.um", "audio.um", "csv.um", "ent.um", "image.um", "input.um", "misc.um", "canvas.um", "ray.um", "rect.um", "tilemap.um", "window.um", "std/std.um", "particles.um", "lerp.um", "font.um", "th.um", "signal.um", "atlas.um", "shader.um", "color.um", "coll.um", "placeholders.um", "nav.um", "ui.um", }; +int th_em_modulenames_count = 25; +const char *th_em_misc[] = { +"BSD 3-Clause License\n" "\n" -"import (\n" -"\t\"std.um\"\n" -")\n" +"Copyright (c) 2023, Marek Maskarinec\n" +"All rights reserved.\n" "\n" -"//~~\n" -"const (\n" -"\tnil* = 0\n" -"\twindows*\n" -"\tunix*\n" -")\n" +"Redistribution and use in source and binary forms, with or without\n" +"modification, are permitted provided that the following conditions are met:\n" "\n" -"var fileseparator*: char // platform specific file separator. linux => /, windows => \\\n" -"var os*: int // current os\n" -"//~~\n" +"1. Redistributions of source code must retain the above copyright notice, this\n" +" list of conditions and the following disclaimer.\n" "\n" -"//~~fn init\n" -"// Automatically initializes platform specific stuff\n" -"fn init() {\n" -"//~~\n" -"\tos = windows\n" -"\tif std.getenv(\"HOME\") != \"\" {\n" -"\t\tos = unix\n" -"\t}\n" +"2. Redistributions in binary form must reproduce the above copyright notice,\n" +" this list of conditions and the following disclaimer in the documentation\n" +" and/or other materials provided with the distribution.\n" "\n" -"\tswitch os {\n" -"\tcase unix:\n" -"\t\tfileseparator = \'/\'\n" -"\tcase windows:\n" -"\t\tfileseparator = \'\\\\\'\n" -"\t}\n" -"}\n" +"3. Neither the name of the copyright holder nor the names of its\n" +" contributors may be used to endorse or promote products derived from\n" +" this software without specific prior written permission.\n" "\n" -"// checks, if string contains a char\n" -"fn chcont(inp: str, c: char): bool {\n" -"\tfor i:=0; i < len(inp); i++ {\n" -"\t\tif inp[i] == c {\n" -"\t\t\treturn true\n" -"\t\t}\n" -"\t}\n" -"\treturn false\n" +"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n" +"AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n" +"IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n" +"DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n" +"FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n" +"DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n" +"SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n" +"CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n" +"OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n" +"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" +"", +"v1.2\n" +"", +}; +const char *th_em_moduledocs[] = { +"## struct Anim\n" +"\n" +"```\n" +"type Anim* = struct {\n" +"\t// the source atlas\n" +"\tatl: atlas.Atlas\n" +"\t// the first cell of the animation\n" +"\tmin: int\n" +"\t// the last cell of the animation\n" +"\tmax: int\n" +"\tfps: real32\n" +"\t// offset in time\n" +"\toffset: int\n" "}\n" +"```\n" "\n" -"//~~fn dir\n" -"// returns the directory in inp\n" -"fn dir*(inp: str): str {\n" -"//~~\n" -"\tif os == nil {\n" -"\t\tinit()\n" -"\t}\n" +"Anim allows you to animate between individual frames of an atlas.\n" "\n" -"\tif !chcont(inp, fileseparator) {\n" -"\t\treturn \"\"\n" -"\t}\n" "\n" -"\tln := 0\n" -"\tfor inp[len(inp)-ln-1] != fileseparator {\n" -"\t\tln++\n" -"\t}\n" +"## fn mk\n" "\n" -"\treturn slice(inp, 0, len(inp)-ln)\n" -"}\n" +"```\n" +"fn mk*(atl: atlas.Atlas, fps: int, min: int = 0, max: int = -1 /* len(atl) - 1 */, offset: int = -1 /* th.time */): Anim {\n" +"```\n" "\n" -"//~~fn ext\n" -"// returns the extension of file inp. if there is no extension, or it is a diroctory, output is \"\"\n" -"fn ext*(inp: str): str {\n" -"//~~\n" -"\tif os == nil {\n" -"\t\tinit()\n" -"\t}\n" +"`Anim` constructor\n" "\n" -"\tif !chcont(inp, \'.\') {\n" -"\t\treturn \"\"\n" -"\t}\n" "\n" -"\tln := 0\n" -"\tfor inp[len(inp)-ln-1] != \'.\' {\n" -"\t\tln++\n" -"\t}\n" +"## fn Anim.animate\n" "\n" -"\treturn slice(inp, len(inp)-ln-1, len(inp))\n" -"}\n" +"```\n" +"fn (anm: ^Anim) animate*(time: int) {\n" +"```\n" "\n" -"//~~fn fromslash\n" -"// converts / to platform specific separator\n" -"fn fromslash*(inp: str): str {\n" -"//~~\n" -"\tif os == nil {\n" -"\t\tinit()\n" -"\t}\n" +"Crops the base atlas to the cell that should be visible at `time`.\n" "\n" -"\tif !chcont(inp, \'/\') || fileseparator == \'/\' {\n" -"\t\treturn inp\n" -"\t}\n" "\n" -"\tl := len(inp)\n" -"\tb := make([]char, l)\n" +"## fn Anim.framesPlayed\n" "\n" -"\tfor i:=0; i < l; i++ {\n" -"\t\tb[i] = inp[i]\n" -"\t\tif inp[i] == \'/\' {\n" -"\t\t\tb[i] = fileseparator\n" -"\t\t}\n" -"\t}\n" +"```\n" +"fn (anm: ^Anim) framesPlayed*(time: int): int {\n" +"```\n" "\n" -"\treturn str(b)\n" -"}\n" +"Returns how many frames were played at `time`.\n" "\n" -"//~~fn toslash\n" -"// converts platform specific separator to /\n" -"fn toslash*(inp: str) : str {\n" -"\tif os == nil {\n" -"\t\tinit()\n" -"\t}\n" "\n" -"\tif !chcont(inp, fileseparator) || fileseparator == \'/\' {\n" -"\t\treturn inp\n" -"\t}\n" +"", +"## \n" "\n" -"\tb := []char(inp)\n" -"\tfor i:=0; i < len(inp); i++ {\n" -"\t\tif inp[i] == fileseparator {\n" -"\t\t\tb[i] = \'/\'\n" -"\t\t}\n" -"\t}\n" +"```\n" +"```\n" "\n" -"\treturn b\n" -"}\n" +"Module for audio loading and playback.\n" "\n" -"//~~fn split\n" -"// returns the direcory and file of inp. if inp is a folder, it return \"\" as a file\n" -"fn split*(inp: str): (str, str) {\n" -"//~~\n" -"\tif os == nil {\n" -"\t\tinit()\n" -"\t}\n" "\n" -"\tdr := dir(inp)\n" -"\tif len(dr) == len(inp) { return dr, \"\" }\n" -"\tfname := slice(inp, len(dr), len(inp))\n" -"\treturn dr, fname\n" -"}\n" -"", -"import (\n" -"\t\"std.um\"\n" -")\n" +"## opaque Sound\n" "\n" -"//~~fn fmt\n" -"// \"{}\" in the string `s` will be subtituted for the arguments\n" -"fn fmt*(s: str, args: ..any): str {\n" -"//~~\n" -"\to := []char{}\n" -"\ta := 0\n" +"```\n" +"type Sound* = struct { _: ^struct{} }\n" +"```\n" "\n" -"\tl := len(s)\n" -"\tfor i:=0; i < l; i++ {\n" -"\t\t// handle \\{\n" -"\t\tif s[i] == \'\\\\\' && i < l-1 && s[i+1] == \'{\' {\n" -"\t\t\to = append(o, \'{\')\n" -"\t\t\ti++\n" -"\t\t\tcontinue\n" -"\t\t}\n" +"Represents an instance of a playable sound. It is an opaque structure.\n" "\n" -"\t\t// if normal character, just add it to the output\n" -"\t\tif s[i] != \'{\' {\n" -"\t\t\to = append(o, s[i])\n" -"\t\t\tcontinue\n" -"\t\t}\n" "\n" -"\t\tif a >= len(args) {\n" -"\t\t\terror(\"sfmt: not enough arguments\")\n" -"\t\t}\n" +"## fn load\n" "\n" -"\t\to = append(o, []char(sprintf(\"%v\", args[a])))\n" -"\t\ta++\n" +"```\n" +"fn load*(path: str, flags: LoadFlag = 0): Sound {\n" +"```\n" "\n" -"\t\t// skip the }\n" -"\t\ti++\n" -"\t}\n" +"Loads a sounds at path, if there is an error, the underlying pointer\n" +"will be `NULL` and `validate` will return false.\n" "\n" -"\tif a != len(args) {\n" -"\t\terror(\"sfmt: too many arguments\")\n" -"\t}\n" "\n" -"\treturn o\n" -"}\n" +"## fn Sound.validate\n" "\n" -"type vec2 = struct {\n" -"\tx, y: int\n" -"}\n" +"```\n" +"fn (s: ^Sound) validate*(): bool {\n" +"```\n" "\n" -"fn main() {\n" -"\tprintf(\"basic usage: %s\\n\", fmt(\"a number {}, a string {}\", 32, \"hello\"))\n" -"\tprintf(\"skip format tag: %s\\n\", fmt(\"skip me \\\\{}\"))\n" -"\tprintf(\"complex types: %s\\n\", fmt(\"what can this print? {} {}\",\n" -"\t\tvec2{2, 4}, []int{1, 2, 3, 4}))\n" -"}\n" -"", +"Returns `true` if `s` loaded correctly.\n" "\n" -"import (\n" -"\t\"std.um\"\n" -")\n" "\n" -"//~~type File\n" -"// Wrapper around `std.File`\n" -"type File* = struct { _: std.File }\n" -"//~~\n" +"## fn Sound.copy\n" "\n" -"//~~fn open\n" -"// Opens a file\n" -"fn open*(path, mode: str): File {\n" -"//~~\n" -"\treturn File{std.fopen(path, mode)}\n" -"}\n" +"```\n" +"fn (s: ^Sound) copy*(): Sound {\n" +"```\n" "\n" -"//~~fn File.close\n" -"// Closes a file\n" -"fn (f: ^File) close*() {\n" -"//~~\n" -"\tstd.fclose(f._)\n" -"}\n" +"Copies the sound. This will create another sound which can be configured\n" +"and played independently from the original sound.\n" "\n" -"//~~fn File.readall\n" -"// Reads all contents of a file into a string\n" -"fn (f: ^File) readall*(): str {\n" -"//~~\n" -" std.fseek(f._, 0, std.seekEnd)\n" -" size := std.ftell(f._)\n" -" std.fseek(f._, 0, std.seekBegin)\n" "\n" -" data := make([]char, size)\n" -" std.fread(f._, &data)\n" +"## fn Sound.isPlaying\n" "\n" -" return str(data)\n" -"}\n" +"```\n" +"fn (s: ^Sound) isPlaying*(): bool {\n" +"```\n" "\n" -"//~~fn File.write\n" -"// Writes text to a file\n" -"fn (f: ^File) write*(text: str) {\n" -"//~~\n" -"\tfprintf(f._, \"%s\", text)\n" -"}\n" +"Returns true if the sound is still playing.\n" "\n" -"//~~fn readall\n" -"// Reads all text from a file.\n" -"fn readall*(path: str): str {\n" -"//~~\n" -"\t\tf := open(path, \"r\")\n" -"\t\tif f._ == null {\n" -"\t\t\terror(\"file not found\")\n" -"\t\t}\n" "\n" -"\t\treturn f.readall()\n" -"}\n" +"## fn Sound.play\n" "\n" -"", +"```\n" +"fn (s: ^Sound) play*() {\n" +"```\n" "\n" -"import (\n" -"\t\"std.um\" // change me for your std.um location\n" -")\n" +"Plays the sound.\n" "\n" -"const (\n" -"\ttok_null = 0\n" -"\ttok_opener\n" -"\ttok_closer\n" -"\ttok_colon\n" -"\ttok_str\n" -"\ttok_int\n" -"\ttok_real\n" -"\ttok_const\n" -"\ttok_separator\n" -"\ttok_lopener\n" -"\ttok_lcloser\n" -")\n" "\n" -"type lexer = struct {\n" -"\tinp: str\n" -"\tlen: int\n" -"\tpos: int\n" -"\tlineno: int\n" -"}\n" +"## fn Sound.start\n" "\n" -"type token = struct {\n" -"\tt: int\n" -"\tpos: int\n" -"\tvalue: str\n" -"}\n" +"```\n" +"fn (s: ^Sound) start*(): ^Sound {\n" +"```\n" "\n" -"fn (l: ^lexer) get(): char {\n" -"\tif l.pos >= l.len { return \'\\0\' }\n" -"\tl.pos++\n" -"\treturn l.inp[l.pos-1]\n" -"}\n" +"The start function allows you to play a single sound multiple times.\n" +"It will create a copy and return a pointer to it, so you can controll it\n" +"while it is playing. The returned pointer can be discarded.\n" "\n" -"fn (l: ^lexer) lex_str(): str {\n" -"\tconst STEP = 64\n" -"\tout := make([]char, STEP)\n" -"\tbuflen := STEP\n" -"\tstart := l.pos\n" -"\tfor true {\n" -"\t\tc := l.inp[l.pos]\n" -"\t\tl.pos++\n" "\n" -"\t\tif l.pos > 1 && c == \'\"\' && l.inp[l.pos-2] != \'\\\\\' {\n" -"\t\t\tbreak\n" -"\t\t}\n" +"## fn Sound.stop\n" "\n" -"\t\tif l.pos-start >= buflen {\n" -"\t\t\tout = append(out, make([]char, STEP * 4))\n" -"\t\t\tbuflen += STEP * 4\n" -"\t\t}\n" +"```\n" +"fn (s: ^Sound) stop*() {\n" +"```\n" "\n" -"\t\tout[l.pos-start-1] = c\n" -"\t}\n" -"\treturn out\n" -"}\n" +"Stops the sound, but keeps the progress. If you want to start from the\n" +"begginning, use `audio.Sound.seekToFrame(0)`.\n" "\n" -"fn is_num(inp: char): bool {\n" -"\treturn ((inp >= \'0\' && inp <= \'9\') || inp == \'.\')\n" -"}\n" "\n" -"fn (l: ^lexer) lex_num(): (str, bool) {\n" -"\tout := \"\"\n" -"\tis_real := false\n" +"## fn Sound.setVol\n" "\n" -"\tfor true {\n" -"\t\tc := l.get()\n" -"\t\tif c == \'.\' { is_real = true }\n" -"\t\tif !is_num(c) { break }\n" -"\t\tout += c\n" -"\t}\n" +"```\n" +"fn (s: ^Sound) setVol*(vol: real32) {\n" +"```\n" "\n" -"\treturn out, is_real \n" -"}\n" +"Sets the volume as a multiplier of the base volume.\n" "\n" -"fn (l: ^lexer) lex_space(): str {\n" -"\tout := \"\"\n" -"\tl.pos--\n" -"\tc := l.get()\n" -"\tfor c != \' \' && c != \'}\' && c != \']\' && c != \'\\n\' && c != \',\' && c != \'\\t\' {\n" -"\t\tout += c\n" -"\t\tc = l.get()\n" -"\t}\n" -"\tl.pos--\n" -"\treturn out\n" -"}\n" "\n" -"fn (l: ^lexer) lex_next(): (token, bool) {\n" -"\tfor l.pos < l.len && (l.inp[l.pos] == \' \' || l.inp[l.pos] == \'\\n\' || l.inp[l.pos] == \'\\t\') {\n" -"\t\tif l.inp[l.pos] == \'\\n\' {\n" -"\t\t\tl.lineno++\n" -"\t\t}\n" -"\t\tl.pos++\n" -"\t}\n" +"## fn Sound.setPan\n" "\n" -"\tswitch l.get() {\n" -"\tcase \'{\':\n" -"\t\treturn token{tok_opener, l.pos, \"{\"}, true\n" -"\tcase \'}\':\n" -"\t\treturn token{tok_closer, l.pos, \"}\"}, true\n" -"\tcase \'[\':\n" -"\t\treturn token{tok_lopener, l.pos, \"[\"}, true\n" -"\tcase \']\':\n" -"\t\treturn token{tok_lcloser, l.pos, \"]\"}, true\n" -"\tcase \'\"\': // are \' or ` strings allowed?\n" -"\t\treturn token{tok_str, l.pos, l.lex_str()}, true\n" -"\tcase \'\\0\':\n" -"\t\treturn token{}, false\n" -"\tcase \':\':\n" -"\t\treturn token{tok_colon, l.pos, str(l.inp[l.pos-1])}, true\n" -"\tcase \',\':\n" -"\t\treturn token{tok_separator, l.pos, str(l.inp[l.pos-1])}, true\n" -"\tdefault:\n" -"\t\tif l.inp[l.pos-1] == \'-\' || is_num(l.inp[l.pos-1]) {\n" -"\t\t\tfirst := l.inp[l.pos-1]\n" -"\t\t\tval, is_real := l.lex_num()\n" -"\t\t\tt := tok_int\n" -"\t\t\tif is_real { t = tok_real }\n" -"\t\t\tl.pos--\n" -"\t\t\treturn token{t, l.pos, first + val}, true\n" -"\t\t}\n" +"```\n" +"fn (s: ^Sound) setPan*(pan: real32) {\n" +"```\n" "\n" -"\t\tval := l.lex_space()\n" -"\t\treturn token{tok_const, l.pos, val}, true\n" -"\t}\n" +"Sets the pan of the sound.\n" "\n" -"\treturn token{}, false\n" -"}\n" "\n" -"fn (l: ^lexer) parser_error(msg: str) {\n" -"\tprintf(\"error %d:%d: %s\\n\", l.lineno, msg)\n" -"}\n" +"## fn Sound.setPitch\n" "\n" -"fn (l: ^lexer) parse_object(): map[str]any\n" -"fn (l: ^lexer) parse_array(): []any\n" +"```\n" +"fn (s: ^Sound) setPitch*(pitch: real32) {\n" +"```\n" "\n" -"fn (l: ^lexer) parse_val(t: token): any {\n" -"\tswitch (t.t) {\n" -"\tcase tok_str:\n" -"\t\treturn t.value\n" -"\tcase tok_int:\n" -"\t\treturn std.atoi(t.value)\n" -"\tcase tok_real:\n" -"\t\treturn std.atof(t.value)\n" -"\tcase tok_opener:\n" -"\t\treturn l.parse_object()\n" -"\tcase tok_lopener:\n" -"\t\treturn l.parse_array()\n" -"\tcase tok_const:\n" -"\t\tif t.value == \"true\" {\n" -"\t\t\treturn true\n" -"\t\t} else if t.value == \"false\" {\n" -"\t\t\treturn false\n" -"\t\t} else if t.value == \"null\" {\n" -"\t\t\treturn null\n" -"\t\t} else {\n" -"\t\t\tl.parser_error(\"unknonw constant\")\n" -"\t\t}\n" -"\tdefault:\n" -"\t\tl.parser_error(\"unsupported json feature\")\n" -"\t}\n" +"Sets the pitch of the sound.\n" "\n" -"\treturn null\n" -"}\n" "\n" -"fn (l: ^lexer) parse_object(): map[str]any {\n" -"\tvar key: str\n" -"\tvar val: any\n" -"\tvar out: map[str]any\n" -"\t\n" -"\t// this looks horrible\n" -"\tt, stay := l.lex_next()\n" -"\tfor stay && t.t != tok_closer {\n" -"\t\tif t.t == tok_str {\n" -"\t\t\tnext, stay := l.lex_next()\n" -"\t\t\tif next.t != tok_colon {\n" -"\t\t\t\tl.parser_error(\"missing colon\")\n" -"\t\t\t\tbreak\n" -"\t\t\t}\n" +"## fn Sound.setLooping\n" "\n" -"\t\t\tkey = t.value\n" -"\t\t\tnext, stay = l.lex_next()\n" -"\t\t\tval = l.parse_val(next)\n" -"\t\t\tnext, stay = l.lex_next()\n" +"```\n" +"fn (s: ^Sound) setLooping*(looping: bool) {\n" +"```\n" "\n" -"\t\t\tif stay && next.t != tok_separator && next.t != tok_closer {\n" -"\t\t\t\tl.parser_error(\"missing comma.\")\n" -"\t\t\t}\n" +"Sets whether the sound will loop upon finishing.\n" "\n" -"\t\t\tout[key] = val\n" -"\t\t\tif next.t == tok_closer {\n" -"\t\t\t\tbreak\n" -"\t\t\t}\n" -"\t\t}\n" -"\t\tt, stay = l.lex_next()\n" -"\t}\n" "\n" -"\treturn out\n" -"}\n" +"## fn Sound.seekToFrame\n" "\n" -"fn (l: ^lexer) parse_array(): []any {\n" -"\tout := []any{}\n" +"```\n" +"fn (s: ^Sound) seekToFrame*(frame: uint) {\n" +"```\n" "\n" -"\tstay := true\n" -"\tt := token{}\n" -"\tfor stay && t.t != tok_lcloser {\n" -"\t\tt, stay = l.lex_next()\n" -"\t\tif t.t == tok_lcloser {\n" -"\t\t\tbreak\n" -"\t\t}\n" +"Seeks to a specified PCM frame.\n" "\n" -"\t\tout = append(out, l.parse_val(t))\n" -"\t\tt, stay = l.lex_next()\n" "\n" -"\t\tif stay && (t.t != tok_separator && t.t != tok_lcloser) {\n" -"\t\t\tl.parser_error(\"array elements are not separated correctly\")\n" -"\t\t\tbreak\n" -"\t\t}\n" -"\t}\n" -"\n" -"\treturn out\n" -"}\n" -"\n" -"//~~fn parse\n" -"// parses json provided as an input and returns either map[str]any or []any\n" -"fn parse*(inp: str): any {\n" -"//~~\n" -"\tl := lexer{inp, len(inp), 0, 1}\n" -"\n" -"\tt, end := l.lex_next()\n" -"\tvar out: any\n" -"\n" -"\tswitch (t.t) {\n" -"\tcase tok_opener:\n" -"\t\tout = l.parse_object()\n" -"\tcase tok_lopener:\n" -"\t\tout = l.parse_array()\n" -"\tdefault:\n" -"\t\tl.parser_error(\"top level type can only be an object or an array\")\n" -"\t}\n" -"\n" -"\treturn out\n" -"}\n" -"", -"\n" -"type State = int\n" -"const (\n" -"\tobject = State(0)\n" -"\tarray = State(1)\n" -")\n" -"\n" -"//~~type Encoder\n" -"type Encoder* = struct {\n" -"\t// Contains private fields\n" -"//~~\n" -"\tbuffer: str\n" -"\tpretty: bool\n" -"\n" -"\tnestLevel: int\n" -"\tputComma: bool\n" -"\tstate: []State\n" -"}\n" -"\n" -"//~~fn mk\n" -"// Creates an encoder.\n" -"fn mk*(pretty: bool = true): Encoder {\n" -"//~~\n" -"\treturn {\n" -"\t\tbuffer: \"\",\n" -"\t\tpretty: pretty,\n" -"\t\tstate: { object } }\n" -"}\n" -"\n" -"fn (this: ^Encoder) write(s: str) {\n" -"\tthis.buffer += s\n" -"}\n" -"\n" -"fn (this: ^Encoder) writec(c: char) {\n" -"\tthis.buffer += str(c)\n" -"}\n" -"\n" -"fn (this: ^Encoder) newLine() {\n" -"\tif this.putComma {\n" -"\t\tthis.writec(\',\')\n" -"\t\tthis.putComma = false\n" -"\t}\n" -"\n" -"\tif !this.pretty {\n" -"\t\treturn\n" -"\t}\n" -"\n" -"\tthis.writec(\'\\n\')\n" -"\tfor i:=0; i < this.nestLevel; i++ {\n" -"\t\tthis.writec(\'\\t\')\n" -"\t}\n" -"}\n" -"\n" -"fn (this: ^Encoder) getState(): State {\n" -"\treturn this.state[len(this.state) - 1]\n" -"}\n" -"\n" -"//~~fn Encoder.putKey\n" -"fn (this: ^Encoder) putKey*(key: str) {\n" -"//~~\n" -"\tthis.newLine()\n" -"\tthis.write(sprintf(\"\\\"%s\\\": \", key))\n" -"}\n" -"\n" -"//~~fn Encoder.putVal\n" -"fn (this: ^Encoder) putVal*(a: any) {\n" -"//~~\n" -"\tif this.getState() == array {\n" -"\t\tthis.newLine()\n" -"\t}\n" -"\n" -"\tthis.write(sprintf(\"%v\", a))\n" -"\tthis.putComma = true\n" -"}\n" -"\n" -"//~~fn Encoder.startObject\n" -"fn (this: ^Encoder) startObject*() {\n" -"//~~\n" -"\tif this.getState() == array {\n" -"\t\tthis.newLine()\n" -"\t}\n" -"\n" -"\tthis.writec(\'{\')\n" -"\tthis.putComma = false\n" -"\tthis.nestLevel++\n" -"\n" -"\tthis.state = append(this.state, object)\n" -"}\n" -"\n" -"//~~fn Encoder.endObject\n" -"fn (this: ^Encoder) endObject*() {\n" -"//~~\n" -"\tthis.nestLevel--\n" -"\tif this.pretty {\n" -"\t\tthis.putComma = false\n" -"\t\tthis.newLine()\n" -"\t}\n" -"\tthis.writec(\'}\')\n" -"\n" -"\tthis.putComma = true\n" -"\tif this.nestLevel < 0 {\n" -"\t\terror(\"Incorrect nesting\")\n" -"\t}\n" -"\n" -"\tthis.state = slice(this.state, 0, len(this.state) - 1)\n" -"}\n" -"\n" -"//~~fn Encoder.startArray\n" -"fn (this: ^Encoder) startArray*() {\n" -"//~~\n" -"\tif this.getState() == array {\n" -"\t\tthis.newLine()\n" -"\t}\n" -"\n" -"\tthis.writec(\'[\')\n" -"\tthis.putComma = false\n" -"\tthis.nestLevel++\n" -"\n" -"\tthis.state = append(this.state, array)\n" -"}\n" -"\n" -"//~~fn Encoder.endArray\n" -"fn (this: ^Encoder) endArray*() {\n" -"//~~\n" -"\tthis.nestLevel--\n" -"\n" -"\tif this.pretty {\n" -"\t\tthis.putComma = false\n" -"\t\tthis.newLine()\n" -"\t}\n" -"\tthis.writec(\']\')\n" -"\n" -"\tthis.putComma = true\n" -"\tif this.nestLevel < 0 {\n" -"\t\terror(\"Incorrect nesting\")\n" -"\t}\n" -"\n" -"\tthis.state = slice(this.state, 0, len(this.state) - 1)\n" -"}\n" -"\n" -"//~~fn Encoder.toStr\n" -"fn (this: ^Encoder) toStr*(): str {\n" -"//~~\n" -"\treturn this.buffer\n" -"}\n" -"\n" -"fn main() {\n" -"\tenc := mk()\n" -"\n" -"\tenc.startObject()\n" -"\t\tenc.putKey(\"x\")\n" -"\t\tenc.putVal(12.0)\n" -"\t\t\n" -"\t\tenc.putKey(\"y\")\n" -"\t\tenc.putVal(20.1)\n" -"\n" -"\t\tenc.putKey(\"numbers\")\n" -"\t\tenc.startArray()\n" -"\t\t\tenc.putVal(1)\n" -"\t\t\tenc.putVal(false)\n" -"\t\t\tenc.putVal(\"hello I\'m a string\")\n" -"\t\tenc.endArray()\n" -"\tenc.endObject()\n" -"\n" -"\tprintf(\"%s\\n\", enc.toStr())\n" -"}\n" -"", -"\n" -"import (\n" -"\t\"std.um\"\n" -")\n" -"\n" -"//~~\n" -"// A logging library.\n" -"//\n" -"// Every log has a tag. The tag is used to distinguish between different parts\n" -"// of the program. Every tag can have specific log level, which is different\n" -"// from the global log level. This allows you to enable the debug logs just for\n" -"// the code you are debugging.\n" -"//\n" -"// This library offers following loggin backends:\n" -"// * `ConsoleBackend` - log to `stdout`\n" -"// * `FileBackend` - log to file\n" -"//~~\n" -"\n" -"\n" -"//~~interface Backend\n" -"// Defines a logging backend.\n" -"type Backend* = interface {\n" -"//~~\n" -"\twrite(s: str)\n" -"}\n" -"\n" -"//~~enum LogLevel\n" -"type LogLevel* = int\n" -"const (\n" -"\tLogLevelDbg* = LogLevel(0)\n" -"\tLogLevelInf* = LogLevel(1)\n" -"\tLogLevelWrn* = LogLevel(2)\n" -"\tLogLevelSus* = LogLevel(3)\n" -"\tLogLevelErr* = LogLevel(4)\n" -")\n" -"//~~\n" -"\n" -"type Config = struct {\n" -"\tlevel: LogLevel\n" -"\ttagLevel: map[str]LogLevel\n" -"\tbackend: Backend\n" -"}\n" -"\n" -"//~~struct ConsoleBackend\n" -"// Backend which logs to the console. This is the default backend.\n" -"type ConsoleBackend* = struct { }\n" -"//~~\n" -"\n" -"fn (this: ^ConsoleBackend) write*(s: str) {\n" -"\tprintf(\"%s\", s)\n" -"}\n" -"\n" -"//~~struct FileBackend\n" -"// Backend which logs to a file. Created using `mkFileBackend`.\n" -"type FileBackend* = struct {\n" -"\t// Contains private fields\n" -"//~~\n" -"\tf: std.File\n" -"}\n" -"\n" -"fn (this: ^FileBackend) write*(s: str) {\n" -"\tfprintf(this.f, \"%s\", s)\n" -"}\n" -"\n" -"//~~fn FileBackend.close\n" -"// Closes the internal file.\n" -"fn (this: ^FileBackend) close*() {\n" -"//~~\n" -"\tstd.fclose(this.f)\n" -"}\n" -"\n" -"//~~fn mkFileBackend\n" -"// Creates a `FileBackend`. If `rewrite` is false, the file will be appended.\n" -"fn mkFileBackend*(path: str, rewrite: bool = false): FileBackend {\n" -"//~~\n" -"\treturn {\n" -"\t\tstd.fopen(path, rewrite ? \"w\" : \"a\")\n" -"\t}\n" -"}\n" -"\n" -"var (\n" -"\tconf: Config = { }\n" -")\n" -"\n" -"//~~fn init\n" -"// Initialize `logs.um`. You need to call this before using any other functions.\n" -"fn init*() {\n" -"//~~\n" -"\tconf = {\n" -"\t\tlevel: LogLevelInf,\n" -"\t\ttagLevel: {},\n" -"\t\tbackend: ConsoleBackend{}\n" -"\t}\n" -"}\n" -"\n" -"//~~fn setBackend\n" -"// Set the logging backend.\n" -"fn setBackend*(b: Backend) {\n" -"//~~\n" -"\tconf.backend = b\n" -"}\n" -"\n" -"//~~fn setGlobalLogLevel\n" -"// Set the global log level.\n" -"fn setGlobalLogLevel*(level: LogLevel) {\n" -"//~~\n" -"\tconf.level = level\n" -"}\n" -"\n" -"//~~fn setTagLogLevel\n" -"// Set the tag specific log level.\n" -"fn setTagLogLevel*(tag: str, level: LogLevel) {\n" -"//~~\n" -"\tconf.tagLevel[tag] = level\n" -"}\n" -"\n" -"fn fmt(s: str, args: []any): str {\n" -"\to := []char{}\n" -"\ta := 0\n" -"\n" -"\tl := len(s)\n" -"\tfor i:=0; i < l; i++ {\n" -"\t\t// handle \\{\n" -"\t\tif s[i] == \'\\\\\' && i < l-1 && s[i+1] == \'{\' {\n" -"\t\t\to = append(o, \'{\')\n" -"\t\t\ti++\n" -"\t\t\tcontinue\n" -"\t\t}\n" -"\n" -"\t\t// if normal character, just add it to the output\n" -"\t\tif s[i] != \'{\' {\n" -"\t\t\to = append(o, s[i])\n" -"\t\t\tcontinue\n" -"\t\t}\n" -"\n" -"\t\tif a >= len(args) {\n" -"\t\t\terror(\"sfmt: not enough arguments\")\n" -"\t\t}\n" -"\n" -"\t\to = append(o, []char(sprintf(\"%v\", args[a])))\n" -"\t\ta++\n" -"\n" -"\t\t// skip the }\n" -"\t\ti++\n" -"\t}\n" -"\n" -"\tif a != len(args) {\n" -"\t\terror(\"sfmt: too many arguments\")\n" -"\t}\n" -"\n" -"\treturn o\n" -"}\n" -"\n" -"fn getLogLevel(tag: str): LogLevel {\n" -"\tif validkey(conf.tagLevel, tag) {\n" -"\t\treturn conf.tagLevel[tag]\n" -"\t}\n" -"\n" -"\treturn conf.level\n" -"}\n" -"\n" -"fn logRaw(levelStr: str, tag: str, fmtStr: str, args: []any) {\n" -"\tdt := std.localtime(std.time())\n" -"\n" -"\tconf.backend.write(sprintf(\"[%s]: %04d-%02d-%02dT%02d:%02d:%02d: %s: %s\\n\",\n" -"\t\tlevelStr, dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, tag,\n" -"\t\tfmt(fmtStr, args))\n" -"\t)\n" -"}\n" -"\n" -"//~~fn dbg\n" -"fn dbg*(tag: str, fmt: str, args: ..any) {\n" -"//~~\n" -"\tif getLogLevel(tag) > LogLevelDbg {\n" -"\t\treturn\n" -"\t}\n" -"\n" -"\tlogRaw(\"DBG\", tag, fmt, args)\n" -"}\n" -"\n" -"//~~fn inf\n" -"fn inf*(tag: str, fmt: str, args: ..any) {\n" -"//~~\n" -"\tif getLogLevel(tag) > LogLevelInf {\n" -"\t\treturn\n" -"\t}\n" -"\n" -"\tlogRaw(\"INF\", tag, fmt, args)\n" -"}\n" -"\n" -"//~~fn wrn\n" -"fn wrn*(tag: str, fmt: str, args: ..any) {\n" -"//~~\n" -"\tif getLogLevel(tag) > LogLevelWrn {\n" -"\t\treturn\n" -"\t}\n" -"\n" -"\tlogRaw(\"WRN\", tag, fmt, args)\n" -"}\n" -"\n" -"//~~fn sus\n" -"fn sus*(tag: str, fmt: str, args: ..any) {\n" -"//~~\n" -"\tif getLogLevel(tag) > LogLevelSus {\n" -"\t\treturn\n" -"\t}\n" -"\n" -"\tlogRaw(\"SUS\", tag, fmt, args)\n" -"}\n" -"\n" -"//~~fn err\n" -"fn err*(tag: str, fmt: str, args: ..any) {\n" -"//~~\n" -"\tif getLogLevel(tag) > LogLevelErr {\n" -"\t\treturn\n" -"\t}\n" -"\n" -"\tlogRaw(\"ERR\", tag, fmt, args)\n" -"}\n" -"\n" -"fn main() {\n" -"\tinit()\n" -"\tsetTagLogLevel(\"debug.um\", LogLevelDbg)\n" -"\n" -"\tconst TAG = \"logs.um\"\n" -"\n" -"\tdbg(\"debug.um\", \"Debug log\")\n" -"\tdbg(TAG, \"Debug log\")\n" -"\tinf(TAG, \"Information log\")\n" -"\tinf(TAG, \"Testing the formatting \\\\{} {}\", 3.141)\n" -"\twrn(TAG, \"Warning log\")\n" -"\tsus(TAG, \"Suspicious log\")\n" -"\terr(TAG, \"Error log\")\n" -"\n" -"\tsetBackend(mkFileBackend(\"log.txt\", true))\n" -"\tdbg(\"debug.um\", \"Debug log\")\n" -"\tdbg(TAG, \"Debug log\")\n" -"\tinf(TAG, \"Information log\")\n" -"\twrn(TAG, \"Warning log\")\n" -"\tsus(TAG, \"Suspicious log\")\n" -"\terr(TAG, \"Error log\")\n" -"}\n" -"", -"\n" -"//~~\n" -"type Arr* = interface {\n" -"\tlen(): int\n" -"\tswap(i, j: int)\n" -"}\n" -"\n" -"type CmpFn* = fn(a: Arr, i, j: int): bool\n" -"//~~\n" -"\n" -"fn partition(a: Arr, f: CmpFn, s, e: int): int {\n" -"\ti := s - 1\n" -"\tfor j:=s; j < e; j++ {\n" -"\t\tif !f(a, j, e - 1) { continue }\n" -"\n" -"\t\ti++\n" -"\t\ta.swap(i, j)\n" -"\t}\n" -"\n" -"\ti++\n" -"\ta.swap(i, e - 1)\n" -"\n" -"\treturn i\n" -"}\n" -"\n" -"fn quicksort(a: Arr, f: CmpFn, s, e: int) {\n" -"\tif s >= e || s < 0 { return }\n" -"\n" -"\tpivot := partition(a, f, s, e)\n" -"\n" -"\tquicksort(a, f, s, pivot)\n" -"\tquicksort(a, f, pivot + 1, e)\n" -"}\n" -"\n" -"//~~fn sort\n" -"fn sort*(a: Arr, f: CmpFn) {\n" -"//~~\n" -"\tquicksort(a, f, 0, a.len())\n" -"}\n" -"\n" -"//~~\n" -"type IntArr* = []int\n" -"\n" -"fn (this: ^IntArr) len(): int {\n" -"\treturn len(this^)\n" -"}\n" -"\n" -"fn (this: ^IntArr) swap(i, j: int) {\n" -"\tt := this[i]\n" -"\tthis[i] = this[j]\n" -"\tthis[j] = t\n" -"}\n" -"\n" -"fn sortInt*(a: []int) {\n" -"\tsort(IntArr(a), CmpFn{\n" -"\t\tia := []int(a)\n" -"\t\treturn ia[i] < ia[j]\n" -"\t})\n" -"}\n" -"\n" -"fn main() {\n" -"\tnums := []int{ 3, 1, 4, 1, 5, 9, 2 }\n" -"\tprintf(\"nums: %s\\n\", repr(nums))\n" -"\tsortInt(nums)\n" -"\tprintf(\"nums: %s\\n\", repr(nums))\n" -"}\n" -"//~~\n" -"", -"\n" -"//~~fn contains\n" -"// returns true, if string is contained in another string\n" -"fn contains*(inp, check: str): bool {\n" -"//~~\n" -"\tfor i:=0; i < len(inp); i++ {\n" -"\t\tfor j:=0; i+j < len(inp) && inp[i+j] == check[j] && j < len(check); j++ {\n" -"\t\t\tif j == len(check) - 1 {\n" -"\t\t\t\treturn true\n" -"\t\t\t}\n" -"\t\t}\n" -"\t}\n" -"\n" -"\treturn false\n" -"}\n" -"\n" -"//~~fn join\n" -"// joins an array of string into one and adds a joiner between them\n" -"fn join*(inp: []str, joiner: str): str {\n" -"//~~\n" -"\ts := \"\"\n" -"\n" -"\tfor i:=0; i < len(inp); i++ {\n" -"\t\ts += inp[i]\n" -"\t\tif i != len(inp) - 1 {\n" -"\t\t\ts += joiner\n" -"\t\t}\n" -"\t}\n" -"\n" -"\treturn s\n" -"}\n" -"\n" -"fn _has_prefix(s, p: str, i, ls, lp: int): bool {\n" -"\tif ls - i < lp { return false }\n" -"\n" -"\tfor j:=0; j < lp; j++ {\n" -"\t\tif s[i] != p[j] { return false }\n" -"\t\ti++\n" -"\t}\n" -"\n" -"\treturn true\n" -"}\n" -"\n" -"//~~fn has_prefix\n" -"// Returns true if `s` starts with `p`\n" -"fn has_prefix*(s, p: str): bool {\n" -"//~~\n" -"\treturn _has_prefix(s, p, 0, len(s), len(p))\n" -"}\n" -"\n" -"//~~fn split\n" -"// Splits the string by a pattern\n" -"fn split*(s, p: str): []str {\n" -"//~~\n" -"\to := []str{}\n" -"\te := 0\n" -"\n" -"\tlp := len(p)\n" -"\tls := len(s)\n" -"\n" -"\tfor i:=0; i < ls; i++ {\n" -"\t\tif _has_prefix(s, p, i, ls, lp) {\n" -"\t\t\to = append(o, slice(s, e, i))\n" -"\t\t\ti += lp - 1\n" -"\t\t\te = i + 1\n" -"\t\t}\n" -"\t}\n" -"\n" -"\to = append(o, slice(s, e))\n" -"\n" -"\treturn o\n" -"}\n" -"\n" -"//~~fn replace\n" -"// replaces an pattern with a string\n" -"fn replace*(inp, pattern, replacer: str): str {\n" -"//~~\n" -"\treturn join(split(inp, pattern), replacer)\n" -"}\n" -"\n" -"fn chartoupper(inp: char): char {\n" -"\tif int(inp) >= int(\'a\') && int(inp) <= int(\'z\') {\n" -"\t\treturn char(int(inp) - 32) \n" -"\t}\n" -"\n" -"\treturn inp\n" -"}\n" -"\n" -"//~~fn toupper\n" -"// returns the same string, but characters are upper case\n" -"fn toupper*(inp: str): str {\n" -"//~~\n" -"\tl := len(inp)\n" -"\tb := make([]char, l)\n" -"\n" -"\tfor i:=0; i < l; i++ {\n" -"\t\tb[i] = chartoupper(inp[i])\n" -"\t}\n" -"\n" -"\treturn str(b)\n" -"}\n" -"\n" -"fn chartolower(inp: char): char {\n" -"\tif int(inp) >= 63 && int(inp) <= 90 {\n" -"\t\treturn char(int(inp) + 32) \n" -"\t}\n" -"\n" -"\treturn inp\n" -"}\n" -"\n" -"//~~fn tolower\n" -"// returns the same string, but all characters are lower case\n" -"fn tolower*(inp: str): str {\n" -"//~~\n" -"\tl := len(inp)\n" -"\tb := make([]char, l)\n" -"\n" -"\tfor i:=0; i < l; i++ {\n" -"\t\tb[i] = chartolower(inp[i])\n" -"\t}\n" -"\n" -"\treturn str(b)\n" -"}\n" -"\n" -"//~~fn repeat\n" -"// repeats string count number of times\n" -"fn repeat*(inp: str, count: int): str {\n" -"//~~\n" -"\ts := \"\"\n" -"\tfor i:=0; i < count; i++ { s += inp }\n" -"\treturn s\n" -"}\n" -"\n" -"//~~fn trimspaces\n" -"// trims whitespaces from the start and end of a string\n" -"fn trimspaces*(inp: str): str {\n" -"//~~\n" -"\tif len(inp) == 0 {\n" -"\t\treturn \"\"\n" -"\t}\n" -"\n" -"\tvar start, end: int\n" -"\n" -"\tfor start < len(inp) && inp[start] == \' \' {\n" -"\t\tstart++\n" -"\t}\n" -"\n" -"\tif start >= len(inp) {\n" -"\t\treturn \"\"\n" -"\t}\n" -"\n" -"\tend = len(inp)-1\n" -"\tfor end >= 0 && inp[end] == \' \' {\n" -"\t\tend--\n" -"\t}\n" -"\n" -"\tif end > len(inp) {\n" -"\t\tend = len(inp)\n" -"\t}\n" -"\n" -"\treturn slice(inp, start, end+1)\n" -"}\n" -"\n" -"//~~fn trimprefix\n" -"// trims a prefix of a string\n" -"fn trimprefix*(inp: str, prefix: str): str {\n" -"//~~\n" -"\tlenght := 0\n" -"\n" -"\tfor lenght < len(prefix) && lenght < len(inp) && inp[lenght] == prefix[lenght] {\n" -"\t\tlenght++\n" -"\t}\n" -"\n" -"\tif lenght != len(prefix) {\n" -"\t\treturn inp\n" -"\t}\n" -"\n" -"\treturn slice(inp, lenght, len(inp))\n" -"}\n" -"\n" -"//~~fn trimsuffix\n" -"// trims a suffix of a string\n" -"fn trimsuffix*(inp: str, suffix: str): str {\n" -"//~~\n" -"\tlenght := len(inp) - 1\n" -"\n" -"\tfor i:=len(suffix)-1; i >= 0 && lenght >= 0 && inp[lenght] == suffix[i]; i-- {\n" -"\t\tlenght--\n" -"\t}\n" -"\n" -"\tif len(inp) - 1 - lenght != len(suffix) {\n" -"\t\treturn inp\n" -"\t}\n" -"\n" -"\treturn slice(inp, 0, lenght+1)\n" -"}\n" -"", -}; -const char *th_em_modulenames[] = { "anim.um", "audio.um", "csv.um", "ent.um", "image.um", "input.um", "misc.um", "canvas.um", "ray.um", "rect.um", "tilemap.um", "window.um", "std/std.um", "particles.um", "lerp.um", "font.um", "th.um", "signal.um", "atlas.um", "shader.um", "color.um", "coll.um", "placeholders.um", "nav.um", "ui.um", "coulau/filepath.um", "coulau/fmt.um", "coulau/io.um", "coulau/json.um", "coulau/jsonenc.um", "coulau/logs.um", "coulau/sort.um", "coulau/strings.um", }; -int th_em_modulenames_count = 33; -const char *th_em_misc[] = { -"BSD 3-Clause License\n" -"\n" -"Copyright (c) 2023, Marek Maskarinec\n" -"All rights reserved.\n" -"\n" -"Redistribution and use in source and binary forms, with or without\n" -"modification, are permitted provided that the following conditions are met:\n" -"\n" -"1. Redistributions of source code must retain the above copyright notice, this\n" -" list of conditions and the following disclaimer.\n" -"\n" -"2. Redistributions in binary form must reproduce the above copyright notice,\n" -" this list of conditions and the following disclaimer in the documentation\n" -" and/or other materials provided with the distribution.\n" -"\n" -"3. Neither the name of the copyright holder nor the names of its\n" -" contributors may be used to endorse or promote products derived from\n" -" this software without specific prior written permission.\n" -"\n" -"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n" -"AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n" -"IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n" -"DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n" -"FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n" -"DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n" -"SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n" -"CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n" -"OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n" -"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" -"", -"v1.2\n" -"", -}; -const char *th_em_moduledocs[] = { -"## struct Anim\n" -"\n" -"```\n" -"type Anim* = struct {\n" -"\t// the source atlas\n" -"\tatl: atlas.Atlas\n" -"\t// the first cell of the animation\n" -"\tmin: int\n" -"\t// the last cell of the animation\n" -"\tmax: int\n" -"\tfps: real32\n" -"\t// offset in time\n" -"\toffset: int\n" -"}\n" -"```\n" -"\n" -"Anim allows you to animate between individual frames of an atlas.\n" -"\n" -"\n" -"## fn mk\n" -"\n" -"```\n" -"fn mk*(atl: atlas.Atlas, fps: int, min: int = 0, max: int = -1 /* len(atl) - 1 */, offset: int = -1 /* th.time */): Anim {\n" -"```\n" -"\n" -"`Anim` constructor\n" -"\n" -"\n" -"## fn Anim.animate\n" -"\n" -"```\n" -"fn (anm: ^Anim) animate*(time: int) {\n" -"```\n" -"\n" -"Crops the base atlas to the cell that should be visible at `time`.\n" -"\n" -"\n" -"## fn Anim.framesPlayed\n" -"\n" -"```\n" -"fn (anm: ^Anim) framesPlayed*(time: int): int {\n" -"```\n" -"\n" -"Returns how many frames were played at `time`.\n" -"\n" -"\n" -"", -"## \n" -"\n" -"```\n" -"```\n" -"\n" -"Module for audio loading and playback.\n" -"\n" -"\n" -"## opaque Sound\n" -"\n" -"```\n" -"type Sound* = struct { _: ^struct{} }\n" -"```\n" -"\n" -"Represents an instance of a playable sound. It is an opaque structure.\n" -"\n" -"\n" -"## fn load\n" -"\n" -"```\n" -"fn load*(path: str, flags: LoadFlag = 0): Sound {\n" -"```\n" -"\n" -"Loads a sounds at path, if there is an error, the underlying pointer\n" -"will be `NULL` and `validate` will return false.\n" -"\n" -"\n" -"## fn Sound.validate\n" -"\n" -"```\n" -"fn (s: ^Sound) validate*(): bool {\n" -"```\n" -"\n" -"Returns `true` if `s` loaded correctly.\n" -"\n" -"\n" -"## fn Sound.copy\n" -"\n" -"```\n" -"fn (s: ^Sound) copy*(): Sound {\n" -"```\n" -"\n" -"Copies the sound. This will create another sound which can be configured\n" -"and played independently from the original sound.\n" -"\n" -"\n" -"## fn Sound.isPlaying\n" -"\n" -"```\n" -"fn (s: ^Sound) isPlaying*(): bool {\n" -"```\n" -"\n" -"Returns true if the sound is still playing.\n" -"\n" -"\n" -"## fn Sound.play\n" -"\n" -"```\n" -"fn (s: ^Sound) play*() {\n" -"```\n" -"\n" -"Plays the sound.\n" -"\n" -"\n" -"## fn Sound.start\n" -"\n" -"```\n" -"fn (s: ^Sound) start*(): ^Sound {\n" -"```\n" -"\n" -"The start function allows you to play a single sound multiple times.\n" -"It will create a copy and return a pointer to it, so you can controll it\n" -"while it is playing. The returned pointer can be discarded.\n" -"\n" -"\n" -"## fn Sound.stop\n" -"\n" -"```\n" -"fn (s: ^Sound) stop*() {\n" -"```\n" -"\n" -"Stops the sound, but keeps the progress. If you want to start from the\n" -"begginning, use `audio.Sound.seekToFrame(0)`.\n" -"\n" -"\n" -"## fn Sound.setVol\n" -"\n" -"```\n" -"fn (s: ^Sound) setVol*(vol: real32) {\n" -"```\n" -"\n" -"Sets the volume as a multiplier of the base volume.\n" -"\n" -"\n" -"## fn Sound.setPan\n" -"\n" -"```\n" -"fn (s: ^Sound) setPan*(pan: real32) {\n" -"```\n" -"\n" -"Sets the pan of the sound.\n" -"\n" -"\n" -"## fn Sound.setPitch\n" -"\n" -"```\n" -"fn (s: ^Sound) setPitch*(pitch: real32) {\n" -"```\n" -"\n" -"Sets the pitch of the sound.\n" -"\n" -"\n" -"## fn Sound.setLooping\n" -"\n" -"```\n" -"fn (s: ^Sound) setLooping*(looping: bool) {\n" -"```\n" -"\n" -"Sets whether the sound will loop upon finishing.\n" -"\n" -"\n" -"## fn Sound.seekToFrame\n" -"\n" -"```\n" -"fn (s: ^Sound) seekToFrame*(frame: uint) {\n" -"```\n" -"\n" -"Seeks to a specified PCM frame.\n" -"\n" -"\n" -"## fn Sound.frameCount\n" -"\n" -"```\n" -"fn (s: ^Sound) frameCount*(): uint {\n" -"```\n" -"\n" -"Returns length of the sound in PCM frames.\n" -"\n" -"\n" -"## fn Sound.lengthMs\n" -"\n" -"```\n" -"fn (s: ^Sound) lengthMs*(): uint {\n" -"```\n" -"\n" -"Returns length of the sound in ms.\n" -"\n" -"\n" -"## fn Sound.setStartTimeMs\n" -"\n" -"```\n" -"fn (s: ^Sound) setStartTimeMs*(t: uint) {\n" -"```\n" -"\n" -"\n" -"\n" -"## fn Sound.setStopTimeMs\n" -"\n" -"```\n" -"fn (s: ^Sound) setStopTimeMs*(t: uint) {\n" -"```\n" -"\n" -"\n" -"\n" -"", -"## \n" -"\n" -"```\n" -"```\n" -"\n" -"A CSV parser, which also works for similar formats. It doesn\'t support\n" -"quotes, but you can escape characters using a backslash.\n" -"\n" -"\n" -"## fn parse\n" -"\n" -"```\n" -"fn parse*(inp: str, sep: char = \',\'): [][]str {\n" -"```\n" -"\n" -"Parses input into a 2d string array.\n" -"\n" -"\n" -"## fn encode\n" -"\n" -"```\n" -"fn encode*(inp: [][]str, sep: char = \',\'): str {\n" -"```\n" -"\n" -"Converts 2d array to csv string.\n" -"\n" -"\n" -"", -"## struct Ent\n" -"\n" -"```\n" -"type Ent* = struct {\n" -"\t// used as a collider, used as backup when invalid image is supplied\n" -"\tr: rect.Rect\n" -"\t// used in drawing\n" -"\ti: image.Image\n" -"\t// used to transform and translate the image and rect\n" -"\tt: th.Transform\n" -"\t// used as a color of the rect and a color filter for the image\n" -"\tc: uint32\n" -"}\n" -"```\n" -"\n" -"Entity is the main game object. It features drawing and collisions.\n" -"Every entity has an image used for drawing and a rectangle used\n" -"for collisions. It also has a transform used for transforming it\'s image\n" -"and rectangle.\n" -"\n" -"\n" -"## struct Coll\n" -"\n" -"```\n" -"type Coll* = struct {\n" -"\tindex: th.uu\n" -"\tpos: th.Vf2\n" -"}\n" -"```\n" -"\n" -"Value returned by get coll. It contains a position where the collision\n" -"happened and the index of the entity involved in said collision.\n" -"\n" -"\n" -"## fn Ent.draw\n" -"\n" -"```\n" -"fn (e: ^Ent) draw*() {\n" -"```\n" -"\n" -"Draws the entity onto the screen.\n" -"\n" -"\n" -"## fn mk\n" -"\n" -"```\n" -"fn mk*(img: image.Image = image.Image{}, t: th.Transform = th.Transform{ s: th.Vf2{1, 1} }): Ent {\n" -"```\n" -"\n" -"ent\'s constructor\n" -"\n" -"\n" -"## fn Ent.getColl\n" -"\n" -"```\n" -"fn (e: ^Ent) getColl*(s: []^Ent, maxColls: th.uu): []Coll {\n" -"```\n" -"\n" -"Checks collisions of e with entities in s. Checks at max maxColl collisions.\n" -"If s contains e, the collision won\'t be returned.\n" -"\n" -"\n" -"## fn Ent.animate\n" -"\n" -"```\n" -"fn (e: ^Ent) animate*(fps: int, frames: ^[]image.Image, t: int) {\n" -"```\n" -"\n" -"Animates the entity\'s image with one of the `anim` array. Won\'t begin on\n" -"the first frame. If you want that, use anim.Anim.\n" -"\n" -"\n" -"", -"## opaque Image\n" -"\n" -"```\n" -"type Image* = struct{ _: ^struct{} }\n" -"```\n" -"\n" -"Represents a drawable image. It is an opaque structure.\n" -"Images support a color filter. It is applied by multiplying the color\n" -"of each pixel with the filter.\n" -"\n" -"\n" -"## opaque RenderTarget\n" -"\n" -"```\n" -"type RenderTarget* = struct { _: ^struct{} }\n" -"```\n" -"\n" -"An image you can render to.\n" -"\n" -"\n" -"## fn createRenderTarget\n" -"\n" -"```\n" -"fn createRenderTarget*(size: th.Vf2, filter: int): RenderTarget {\n" -"```\n" -"\n" -"Creates a render target you can draw to, like to a window.\n" -"Filter specifies specfifies filtering for resulting image.\n" -"Image can be retrieved via `toImage`.\n" -"\n" -"\n" -"## fn RenderTarget.end\n" -"\n" -"```\n" -"fn (rt: ^RenderTarget) begin*() {\n" -"```\n" -"\n" -"Begins the render target rendering pass.\n" -"\n" -"\n" -"## fn RenderTarget.end\n" -"\n" -"```\n" -"fn (rt: ^RenderTarget) end*(wp: th.Vf2) {\n" -"```\n" -"\n" -"Ends the render target rendering pass.\n" -"\n" -"\n" -"## fn RenderTarget.toImage\n" -"\n" -"```\n" -"fn (rt: ^RenderTarget) toImage*(): Image {\n" -"```\n" -"\n" -"Returns the image of the render target.\n" -"Do not call `setfilter` on the resulting image.\n" -"\n" -"\n" -"## fn load\n" -"\n" -"```\n" -"fn load*(path: str): Image {\n" -"```\n" -"\n" -"Loads an image at path.\n" -"\n" -"\n" -"## fn Image.validate\n" -"\n" -"```\n" -"fn (i: ^Image) validate*(): bool {\n" -"```\n" -"\n" -"Returns true, if i\'s handle points to an image.\n" -"\n" -"\n" -"## fn Image.flipv\n" -"\n" -"```\n" -"fn (i: ^Image) flipv*(flip: bool) {\n" -"```\n" -"\n" -"Flips image on it\'s vertical axis.\n" -"\n" -"\n" -"## fn Image.fliph\n" -"\n" -"```\n" -"fn (i: ^Image) fliph*(flip: bool) {\n" -"```\n" -"\n" -"Flips image on it\'s horizontal axis.\n" -"\n" -"\n" -"## fn Image.draw\n" -"\n" -"```\n" -"fn (i: ^Image) draw*(t: th.Transform, color: uint32 = th.white) {\n" -"```\n" -"\n" -"Draws the image in screen coordinates. It transforms it with t and\n" -"applies color as a color filter.\n" -"\n" -"\n" -"## fn Image.drawNinepatch\n" -"\n" -"```\n" -"fn (i: ^Image) drawNinepatch*(outer, inner, dest: rect.Rect, color: uint32 = th.white, scale: real = 1.0) {\n" -"```\n" -"\n" -"Draws \"nine-patch\" image.\n" -"`outer` specifies the texture coordinates of the outer rect of source image,\n" -"`inner` specifies coordinates of inner rect of source image, positioned relative to `outer`.\n" -"You can tint with `color`.\n" -"![](img/ninepatch.png)\n" -"\n" -"\n" -"## fn Image.drawOnQuad\n" -"\n" -"```\n" -"fn (i: ^Image) drawOnQuad*(q: th.Quad, color: uint32 = th.white) {\n" -"```\n" -"\n" -"Draws the image on top of a quad with corners of the image positioned\n" -"on the verticies of the quad.\n" -"\n" -"\n" -"## fn Image.getDims\n" -"\n" -"```\n" -"fn (i: ^Image) getDims*(): th.Vf2 {\n" -"```\n" -"\n" -"Returns width and heigth.\n" -"\n" -"\n" -"## fn Image.crop\n" -"\n" -"```\n" -"fn (i: ^Image) crop*(tl, br: th.Vf2) {\n" -"```\n" -"\n" -"Crops an image. Coordinates are between 0, 0 (top left) and\n" -"1, 1 (bottom right)\n" -"\n" -"\n" -"## fn Image.cropPx\n" -"\n" -"```\n" -"fn (i: ^Image) cropPx*(tr, br: th.Vf2) {\n" -"```\n" -"\n" -"Same as `Image.crop`, but the positions are in pixels.\n" -"\n" -"\n" -"## fn Image.cropRect\n" -"\n" -"```\n" -"fn (i: ^Image) cropRect*(r: rect.Rect) {\n" -"```\n" -"\n" -"Same as `Image.crop`, but uses a rect instead of two positions.\n" -"\n" -"\n" -"## fn Image.cropQuad\n" -"\n" -"```\n" -"fn (i: ^Image) cropQuad*(q: th.Quad) {\n" -"```\n" -"\n" -"Crop an image using a quad.\n" -"\n" -"\n" -"## fn Image.getCropQuad\n" -"\n" -"```\n" -"fn (i: ^Image) getCropQuad*(): th.Quad {\n" -"```\n" -"\n" -"Crop an image using a quad.\n" -"\n" -"\n" -"## fn mk\n" -"\n" -"```\n" -"fn mk*(data: []uint32, dm: th.Vf2): Image {\n" -"```\n" -"\n" -"Creates an image from raw data.\n" -"\n" -"\n" -"## fn Image.copy\n" -"\n" -"```\n" -"fn (i: ^Image) copy*(): Image {\n" -"```\n" -"\n" -"Copies image into a new one.\n" -"\n" -"\n" -"## fn Image.setfilter\n" -"\n" -"```\n" -"fn (i: ^Image) setfilter*(filter: int) {\n" -"```\n" -"\n" -"Sets a mag/min filter. 0 is nearest, others are linear.\n" -"This function will regenerate the texture. This means it shouldn\'t be\n" -"used in a loop.\n" -"https://learnopengl.com/img/getting-started/texture_filtering.png\n" -"left is nearest, right is linear.\n" -"\n" -"\n" -"## fn Image.setData\n" -"\n" -"```\n" -"fn (i: ^Image) setData*(data: []uint32, dm: th.Vf2) {\n" -"```\n" -"\n" -"Updates the image data. dm are the dimensions of the new image.\n" -"The new image doesn\'t have to be the same size as the old one.\n" -"\n" -"\n" -"## fn Image.getData\n" -"\n" -"```\n" -"fn (i: ^Image) getData*(): []uint32 {\n" -"```\n" -"\n" -"Gets the image data. This downloads the data from the GPU on **each call**.\n" -"Don\'t use in performance critical sections.\n" -"\n" -"\n" -"", -"## \n" -"\n" -"```\n" -"```\n" -"\n" -"Module for getting keyboard and mouse input.\n" -"is* functions return info based on a us QWERTY layout. They are supposed to\n" -"be used for game controls. For text input use getStr.\n" -"\n" -"\n" -"## Keycode constants\n" -"\n" -"```\n" -"const (\n" -" mouse1* = 1 // NOTE: mouse 2 and 3 key codes are swapped\n" -" mouse2* = 3 // because sokol uses 3 for middle mouse\n" -" mouse3* = 2 // button.\n" -"\n" -" key_ctrl* = 16\n" -" key_shift* = 17\n" -" key_alt* = 18\n" -"\n" -" key_space* = 32\n" -" key_apostrophe* = 39 /* \' */\n" -" key_comma* = 44 /* , */\n" -" key_minus* = 45 /* - */\n" -" key_dot* = 46 /* . */\n" -" key_slash* = 47 /* / */\n" -" key_0* = 48\n" -" key_1* = 49\n" -" key_2* = 50\n" -" key_3* = 51\n" -" key_4* = 52\n" -" key_5* = 53\n" -" key_6* = 54\n" -" key_7* = 55\n" -" key_8* = 56\n" -" key_9* = 57\n" -" key_semicolon* = 59 /* ; */\n" -" key_equal* = 61 /* = */\n" -" key_a* = 65\n" -" key_b* = 66\n" -" key_c* = 67\n" -" key_d* = 68\n" -" key_e* = 69\n" -" key_f* = 70\n" -" key_g* = 71\n" -" key_h* = 72\n" -" key_i* = 73\n" -" key_j* = 74\n" -" key_k* = 75\n" -" key_l* = 76\n" -" key_m* = 77\n" -" key_n* = 78\n" -" key_o* = 79\n" -" key_p* = 80\n" -" key_q* = 81\n" -" key_r* = 82\n" -" key_s* = 83\n" -" key_t* = 84\n" -" key_u* = 85\n" -" key_v* = 86\n" -" key_w* = 87\n" -" key_x* = 88\n" -" key_y* = 89\n" -" key_z* = 90\n" -" key_left_bracket* = 91 /* [ */\n" -" key_backslash* = 92 /* \\ */\n" -" key_right_bracket* = 93 /* ] */\n" -" key_grave_accent* = 96 /* ` */\n" -" key_world_1* = 161 /* non-US #1 */\n" -" key_world_2* = 162 /* non-US #2 */\n" -" key_escape* = 256\n" -" key_enter* = 257\n" -" key_tab* = 258\n" -" key_backspace* = 259\n" -" key_insert* = 260\n" -" key_delete* = 261\n" -" key_right* = 262\n" -" key_left* = 263\n" -" key_down* = 264\n" -" key_up* = 265\n" -" key_page_up* = 266\n" -" key_page_down* = 267\n" -" key_home* = 268\n" -" key_end* = 269\n" -" key_caps_lock* = 280\n" -" key_scroll_lock* = 281\n" -" key_num_lock* = 282\n" -" key_print_screen* = 283\n" -" key_pause* = 284\n" -"\tkey_fn* = 289\n" -" key_fn1* = 290\n" -" key_fn2* = 291\n" -" key_fn3* = 292\n" -" key_fn4* = 293\n" -" key_fn5* = 294\n" -" key_fn6* = 295\n" -" key_fn7* = 296\n" -" key_fn8* = 297\n" -" key_fn9* = 298\n" -" key_fn10* = 299\n" -" key_fn11* = 300\n" -" key_fn12* = 301\n" -" key_fn13* = 302\n" -" key_fn14* = 303\n" -" key_fn15* = 304\n" -" key_fn16* = 305\n" -" key_fn17* = 306\n" -" key_fn18* = 307\n" -" key_fn19* = 308\n" -" key_fn20* = 309\n" -" key_fn21* = 310\n" -" key_fn22* = 311\n" -" key_fn23* = 312\n" -" key_fn24* = 313\n" -" key_fn25* = 314\n" -" key_kp_0* = 320\n" -" key_kp_1* = 321\n" -" key_kp_2* = 322\n" -" key_kp_3* = 323\n" -" key_kp_4* = 324\n" -" key_kp_5* = 325\n" -" key_kp_6* = 326\n" -" key_kp_7* = 327\n" -" key_kp_8* = 328\n" -" key_kp_9* = 329\n" -" key_kp_decimal* = 330\n" -" key_kp_divide* = 331\n" -" key_kp_multiply* = 332\n" -" key_kp_subtract* = 333\n" -" key_kp_add* = 334\n" -" key_kp_enter* = 335\n" -" key_kp_equal* = 336\n" -" key_left_shift* = 340\n" -" key_left_control* = 341\n" -" key_left_alt* = 342\n" -" key_left_super* = 343\n" -" key_right_shift* = 344\n" -" key_right_control* = 345\n" -" key_right_alt* = 346\n" -" key_right_super* = 347\n" -" key_menu* = 348\n" -")\n" -"```\n" -"\n" -"\n" -"\n" -"## fn getMousePos\n" -"\n" -"```\n" -"fn getMousePos*(): th.Vf2 {\n" -"```\n" -"\n" -"Returns the position of mouse cursor in relation to the screen.\n" -"\n" -"\n" -"## fn getGlobalMousePos\n" -"\n" -"```\n" -"fn getGlobalMousePos*(): th.Vf2 {\n" -"```\n" -"\n" -"Returns the position of mouse cursor in relation to cam.\n" -"\n" -"\n" -"## fn isPressed\n" -"\n" -"```\n" -"fn isPressed*(code: int): bool {\n" -"```\n" -"\n" -"Returns true if key is pressed. Either use codes defined in the file above,\n" -"or pass lower case char/number.\n" -"\n" -"\n" -"## fn isPressedc\n" -"\n" -"```\n" -"fn isPressedc*(code: char): bool {\n" -"```\n" -"\n" -"Like `isPressed`, but you can pass char as the code.\n" -"\n" -"\n" -"## fn isJustPressed\n" -"\n" -"```\n" -"fn isJustPressed*(code: int): bool {\n" -"```\n" -"\n" -"Returns, whether code was just pressed this loop.\n" -"\n" -"\n" -"## fn isJustPressedc\n" -"\n" -"```\n" -"fn isJustPressedc*(code: char): bool {\n" -"```\n" -"\n" -"Like `isJustPressed`, but you can pass char as the code.\n" -"\n" -"\n" -"## fn isPressedRepeat\n" -"\n" -"```\n" -"fn isPressedRepeat*(code: int): bool {\n" -"```\n" -"\n" -"Returns, whether code was just pressed this loop, with key repeat.\n" -"\n" -"\n" -"## fn isPressedRepeatc\n" -"\n" -"```\n" -"fn isPressedRepeatc*(code: char): bool {\n" -"```\n" -"\n" -"Like `isPressedRepeat`, but you can pass char as the code.\n" -"\n" -"\n" -"## fn isJustReleased\n" -"\n" -"```\n" -"fn isJustReleased*(code: int): bool {\n" -"```\n" -"\n" -"Returns true if a key was just released.\n" -"\n" -"\n" -"## fn isJustReleasedc\n" -"\n" -"```\n" -"fn isJustReleasedc*(code: char): bool {\n" -"```\n" -"\n" -"Like `isJustReleased`, but you can pass char as the code.\n" -"\n" -"\n" -"## fn clear\n" -"\n" -"```\n" -"fn clear*(code: int) {\n" -"```\n" -"\n" -"Clears both the pressed and justPressed state of a code.\n" -"\n" -"\n" -"## fn clearc\n" +"## fn Sound.frameCount\n" "\n" "```\n" -"fn clearc*(code: char) {\n" +"fn (s: ^Sound) frameCount*(): uint {\n" "```\n" "\n" -"Like `clear`, but you can pass char as the code.\n" +"Returns length of the sound in PCM frames.\n" "\n" "\n" -"## fn getStr\n" +"## fn Sound.lengthMs\n" "\n" "```\n" -"fn getStr*(): str {\n" +"fn (s: ^Sound) lengthMs*(): uint {\n" "```\n" "\n" -"Returns a string entered by the user in the last cycle.\n" +"Returns length of the sound in ms.\n" "\n" "\n" -"## fn getMouseDelta\n" +"## fn Sound.setStartTimeMs\n" "\n" "```\n" -"fn getMouseDelta*(): th.Vf2 {\n" +"fn (s: ^Sound) setStartTimeMs*(t: uint) {\n" "```\n" "\n" -"Returns the difference between mouse positions in the last cycle. Will work\n" -"even if `window.freezeCursor` is enabled.\n" "\n" "\n" -"## fn getMouseScroll\n" +"## fn Sound.setStopTimeMs\n" "\n" "```\n" -"fn getMouseScroll*(): th.Vf2 {\n" +"fn (s: ^Sound) setStopTimeMs*(t: uint) {\n" "```\n" "\n" -"Returns the scroll wheel value\n" "\n" "\n" "", @@ -5987,2829 +4184,2907 @@ const char *th_em_moduledocs[] = { "```\n" "```\n" "\n" -"Misc functions.\n" -"\n" -"\n" -"## fn readall\n" -"\n" -"```\n" -"fn readall*(path: str): str {\n" -"```\n" -"\n" -"Reads file content into a string.\n" -"\n" -"\n" -"## fn stepify\n" -"\n" -"```\n" -"fn stepify*(val, step: th.fu): th.fu {\n" -"```\n" -"\n" -"Snaps a value to step.\n" +"A CSV parser, which also works for similar formats. It doesn\'t support\n" +"quotes, but you can escape characters using a backslash.\n" "\n" "\n" -"## fn maxf\n" +"## fn parse\n" "\n" "```\n" -"fn maxf*(a, b: th.fu): th.fu {\n" +"fn parse*(inp: str, sep: char = \',\'): [][]str {\n" "```\n" "\n" +"Parses input into a 2d string array.\n" "\n" "\n" -"## fn minf\n" +"## fn encode\n" "\n" "```\n" -"fn minf*(a, b: th.fu): th.fu {\n" +"fn encode*(inp: [][]str, sep: char = \',\'): str {\n" "```\n" "\n" +"Converts 2d array to csv string.\n" "\n" "\n" "", -"## \n" -"\n" -"```\n" -"```\n" -"\n" -"Canvas library allowing for drawing basic shapes. Coordinates are based on\n" -"the screen.\n" -"\n" -"\n" -"## fn drawText\n" -"\n" -"```\n" -"fn drawText*(text: str, pos: th.Vf2, color: uint32, size: th.fu) {\n" -"```\n" -"\n" -"Draws a basic pixel text. Only ascii is supported.\n" -"\n" -"\n" -"## fn textSize\n" -"\n" -"```\n" -"fn textSize*(text: str, scale: th.fu): th.Vf2 {\n" -"```\n" -"\n" -"Returns the size of text taken by an equivalent drawText call.\n" -"\n" -"\n" -"## fn drawRect\n" +"## struct Ent\n" "\n" "```\n" -"fn drawRect*(color: uint32, r: rect.Rect) {\n" +"type Ent* = struct {\n" +"\t// used as a collider, used as backup when invalid image is supplied\n" +"\tr: rect.Rect\n" +"\t// used in drawing\n" +"\ti: image.Image\n" +"\t// used to transform and translate the image and rect\n" +"\tt: th.Transform\n" +"\t// used as a color of the rect and a color filter for the image\n" +"\tc: uint32\n" +"}\n" "```\n" "\n" -"Draws a Rectangle.\n" +"Entity is the main game object. It features drawing and collisions.\n" +"Every entity has an image used for drawing and a rectangle used\n" +"for collisions. It also has a transform used for transforming it\'s image\n" +"and rectangle.\n" "\n" "\n" -"## fn drawLine\n" +"## struct Coll\n" "\n" "```\n" -"fn drawLine*(color: uint32, b, e: th.Vf2, thickness: th.fu) {\n" +"type Coll* = struct {\n" +"\tindex: th.uu\n" +"\tpos: th.Vf2\n" +"}\n" "```\n" "\n" -"Draws a line.\n" +"Value returned by get coll. It contains a position where the collision\n" +"happened and the index of the entity involved in said collision.\n" "\n" "\n" -"## fn drawRectLines\n" +"## fn Ent.draw\n" "\n" "```\n" -"fn drawRectLines*(color: uint32, r: rect.Rect, thickness: real32 = 1.0) {\n" +"fn (e: ^Ent) draw*() {\n" "```\n" "\n" -"Draws rect border.\n" +"Draws the entity onto the screen.\n" "\n" "\n" -"## fn drawQuad\n" +"## fn mk\n" "\n" "```\n" -"fn drawQuad*(color: uint32, q: th.Quad) {\n" +"fn mk*(img: image.Image = image.Image{}, t: th.Transform = th.Transform{ s: th.Vf2{1, 1} }): Ent {\n" "```\n" "\n" -"Draws a convex quad.\n" +"ent\'s constructor\n" "\n" "\n" -"## fn beginScissorRect\n" +"## fn Ent.getColl\n" "\n" "```\n" -"fn beginScissorRect*(r: rect.Rect, debug: bool = false) {\n" +"fn (e: ^Ent) getColl*(s: []^Ent, maxColls: th.uu): []Coll {\n" "```\n" "\n" -"Disable rendering outside of rect `r`\n" +"Checks collisions of e with entities in s. Checks at max maxColl collisions.\n" +"If s contains e, the collision won\'t be returned.\n" "\n" "\n" -"## fn endScissor\n" +"## fn Ent.animate\n" "\n" "```\n" -"fn endScissor*() {\n" +"fn (e: ^Ent) animate*(fps: int, frames: ^[]image.Image, t: int) {\n" "```\n" "\n" -"Stops cropping\n" +"Animates the entity\'s image with one of the `anim` array. Won\'t begin on\n" +"the first frame. If you want that, use anim.Anim.\n" "\n" "\n" "", -"## struct Ray\n" -"\n" -"```\n" -"type Ray* = struct {\n" -"\tpos: th.Vf2\n" -"\tl: th.fu // length\n" -"\tr: th.fu // rotation\n" -"}\n" -"```\n" -"\n" -"Ray is a line specified by an origin, length and a rotation.\n" -"\n" -"\n" -"## fn mk\n" -"\n" -"```\n" -"fn mk*(pos: th.Vf2, l: th.fu, r: th.fu = 0.0): Ray {\n" -"```\n" -"\n" -"Ray constructor\n" -"\n" -"\n" -"## fn Ray.getColl\n" +"## opaque Image\n" "\n" "```\n" -"fn (r: ^Ray) getColl*(s: []^ent.Ent, maxColls: th.uu): []ent.Coll {\n" +"type Image* = struct{ _: ^struct{} }\n" "```\n" "\n" -"Checks the ray\'s collisions with a scene of ents. Similar to\n" -"`ent.Ent.getColl`\n" +"Represents a drawable image. It is an opaque structure.\n" +"Images support a color filter. It is applied by multiplying the color\n" +"of each pixel with the filter.\n" "\n" "\n" -"## fn Ray.getTilemapColl\n" +"## opaque RenderTarget\n" "\n" "```\n" -"fn (r: ^Ray) getTilemapColl*(t: tilemap.Tilemap, ic: ^th.Vf2): bool {\n" +"type RenderTarget* = struct { _: ^struct{} }\n" "```\n" "\n" -"Gets ray\'s collision to a tilemap.\n" +"An image you can render to.\n" "\n" "\n" -"## fn Ray.getEnd\n" +"## fn createRenderTarget\n" "\n" "```\n" -"fn (r: ^Ray) getEnd*(): th.Vf2 {\n" +"fn createRenderTarget*(size: th.Vf2, filter: int): RenderTarget {\n" "```\n" "\n" -"Returns the other point of the ray.\n" +"Creates a render target you can draw to, like to a window.\n" +"Filter specifies specfifies filtering for resulting image.\n" +"Image can be retrieved via `toImage`.\n" "\n" "\n" -"## fn Ray.draw\n" +"## fn RenderTarget.end\n" "\n" "```\n" -"fn (r: ^Ray) draw*(color: uint32, thickness: th.fu) {\n" +"fn (rt: ^RenderTarget) begin*() {\n" "```\n" "\n" -"Draws the ray to the screen.\n" +"Begins the render target rendering pass.\n" "\n" "\n" -"", -"## struct Rect\n" +"## fn RenderTarget.end\n" "\n" "```\n" -"type Rect* = struct {\n" -"\tx, y, w, h: th.fu\n" -"}\n" +"fn (rt: ^RenderTarget) end*(wp: th.Vf2) {\n" "```\n" "\n" -"A set of points representing a rectangle.\n" +"Ends the render target rendering pass.\n" "\n" "\n" -"## fn mk\n" +"## fn RenderTarget.toImage\n" "\n" "```\n" -"fn mk*(x, y, w, h: th.fu): Rect {\n" +"fn (rt: ^RenderTarget) toImage*(): Image {\n" "```\n" "\n" +"Returns the image of the render target.\n" +"Do not call `setfilter` on the resulting image.\n" "\n" "\n" -"## fn mk\n" +"## fn load\n" "\n" "```\n" -"fn fromVf2*(p: th.Vf2, dm: th.Vf2): Rect {\n" +"fn load*(path: str): Image {\n" "```\n" "\n" -"Creates a rect from two Vf2s - the position and the dimensions.\n" +"Loads an image at path.\n" "\n" "\n" -"## fn Rect.getPos\n" +"## fn Image.validate\n" "\n" "```\n" -"fn (r: ^Rect) getPos*(): th.Vf2 {\n" +"fn (i: ^Image) validate*(): bool {\n" "```\n" "\n" +"Returns true, if i\'s handle points to an image.\n" "\n" "\n" -"## fn Rect.getDims\n" +"## fn Image.flipv\n" "\n" "```\n" -"fn (r: ^Rect) getDims*(): th.Vf2 {\n" +"fn (i: ^Image) flipv*(flip: bool) {\n" "```\n" "\n" +"Flips image on it\'s vertical axis.\n" "\n" "\n" -"## fn Rect.getEnd\n" +"## fn Image.fliph\n" "\n" "```\n" -"fn (r: ^Rect) getEnd*(): th.Vf2 {\n" +"fn (i: ^Image) fliph*(flip: bool) {\n" "```\n" "\n" -"returns where the second point of the rectangle lies.\n" +"Flips image on it\'s horizontal axis.\n" "\n" "\n" -"## fn Rect.transformed\n" +"## fn Image.draw\n" "\n" "```\n" -"fn (r: ^Rect) transformed*(t: th.Transform): th.Quad {\n" +"fn (i: ^Image) draw*(t: th.Transform, color: uint32 = th.white) {\n" "```\n" "\n" -"Transforms a rect into a quad.\n" -"Order:\n" -"1. scale\n" -"2. rotation\n" -"3. position\n" +"Draws the image in screen coordinates. It transforms it with t and\n" +"applies color as a color filter.\n" "\n" "\n" -"## fn Rect.shrink\n" +"## fn Image.drawNinepatch\n" "\n" "```\n" -"fn (r: ^Rect) shrink*(p: th.Vf2): Rect {\n" +"fn (i: ^Image) drawNinepatch*(outer, inner, dest: rect.Rect, color: uint32 = th.white, scale: real = 1.0) {\n" "```\n" "\n" -"Shrink the rectangle by `p` pixels from all sides.\n" +"Draws \"nine-patch\" image.\n" +"`outer` specifies the texture coordinates of the outer rect of source image,\n" +"`inner` specifies coordinates of inner rect of source image, positioned relative to `outer`.\n" +"You can tint with `color`.\n" +"![](img/ninepatch.png)\n" "\n" "\n" -"## fn Rect.shift\n" +"## fn Image.drawOnQuad\n" "\n" "```\n" -"fn (r: ^Rect) shift*(p: th.Vf2): Rect {\n" +"fn (i: ^Image) drawOnQuad*(q: th.Quad, color: uint32 = th.white) {\n" "```\n" "\n" -"Shift the rectangle by `p` pixels.\n" +"Draws the image on top of a quad with corners of the image positioned\n" +"on the verticies of the quad.\n" "\n" "\n" -"## fn Rect.scale\n" +"## fn Image.getDims\n" "\n" "```\n" -"fn (r: ^Rect) scale*(p: th.Vf2): Rect {\n" +"fn (i: ^Image) getDims*(): th.Vf2 {\n" "```\n" "\n" -"Multiply the dimensions by `p`\n" +"Returns width and heigth.\n" "\n" "\n" -"## fn Rect.center\n" +"## fn Image.crop\n" "\n" "```\n" -"fn (r: ^Rect) center*(): th.Vf2 {\n" +"fn (i: ^Image) crop*(tl, br: th.Vf2) {\n" "```\n" "\n" -"Returns the position, which is the center of the rect.\n" +"Crops an image. Coordinates are between 0, 0 (top left) and\n" +"1, 1 (bottom right)\n" "\n" "\n" -"## fn Rect.centerWithinRect\n" +"## fn Image.cropPx\n" "\n" "```\n" -"fn (r: ^Rect) centerWithinRect*(child: Rect): Rect {\n" +"fn (i: ^Image) cropPx*(tr, br: th.Vf2) {\n" "```\n" "\n" -"Centers `child` with the rect `r`.\n" +"Same as `Image.crop`, but the positions are in pixels.\n" "\n" "\n" -"", -"## \n" +"## fn Image.cropRect\n" "\n" "```\n" +"fn (i: ^Image) cropRect*(r: rect.Rect) {\n" "```\n" "\n" -"Tilemaps allow for easy level construction and fast collisions. You can even\n" -"use them for some games instead of entities (tetris comes to mind)\n" +"Same as `Image.crop`, but uses a rect instead of two positions.\n" "\n" "\n" -"## Direction constants used for autotile\n" +"## fn Image.cropQuad\n" "\n" "```\n" -"const (\n" -"\ttop* = 1\n" -"\tright* = 2\n" -"\tbot* = 4\n" -"\tleft* = 8\n" -")\n" +"fn (i: ^Image) cropQuad*(q: th.Quad) {\n" "```\n" "\n" +"Crop an image using a quad.\n" "\n" "\n" -"## struct Tilemap\n" +"## fn Image.getCropQuad\n" "\n" "```\n" -"type Tilemap* = struct {\n" -"\tatlas: atlas.Atlas\n" -"\tpos: th.Vf2\n" -"\tw: th.uu // width of tilemap\n" -"\tcells: []th.uu // all cells (this will draw the tile in tiles with number in cells - 1)\n" -"\tcollMask: []bool // if true, the tile collides\n" -"\tscale: th.fu\n" -"}\n" +"fn (i: ^Image) getCropQuad*(): th.Quad {\n" "```\n" "\n" -"Tilemap struct\n" +"Crop an image using a quad.\n" "\n" "\n" "## fn mk\n" "\n" "```\n" -"fn mk*(cells: []th.uu, w: th.uu, at: atlas.Atlas, scale: th.fu = 1): Tilemap {\n" +"fn mk*(data: []uint32, dm: th.Vf2): Image {\n" "```\n" "\n" +"Creates an image from raw data.\n" "\n" "\n" -"## fn Tilemap.edit\n" +"## fn Image.copy\n" "\n" "```\n" -"fn (t: ^Tilemap) edit*(x, y, tile: int) {\n" +"fn (i: ^Image) copy*(): Image {\n" "```\n" "\n" -"Sets tile at [x, y] to tile.\n" +"Copies image into a new one.\n" "\n" "\n" -"## fn Tilemap.draw\n" +"## fn Image.setfilter\n" "\n" "```\n" -"fn (t: ^Tilemap) draw*() {\n" +"fn (i: ^Image) setfilter*(filter: int) {\n" "```\n" "\n" -"Draws the tilemap.\n" +"Sets a mag/min filter. 0 is nearest, others are linear.\n" +"This function will regenerate the texture. This means it shouldn\'t be\n" +"used in a loop.\n" +"https://learnopengl.com/img/getting-started/texture_filtering.png\n" +"left is nearest, right is linear.\n" "\n" "\n" -"## fn Tilemap.getColl\n" +"## fn Image.setData\n" "\n" "```\n" -"fn (t: ^Tilemap) getColl*(e: ent.Ent, ic: ^th.Vf2, pos: ^th.Vf2): bool {\n" +"fn (i: ^Image) setData*(data: []uint32, dm: th.Vf2) {\n" "```\n" "\n" -"Checks whether `e` collides with any of the tiles in `t`, which are in the\n" -"collmask.\n" +"Updates the image data. dm are the dimensions of the new image.\n" +"The new image doesn\'t have to be the same size as the old one.\n" "\n" -"* `ic`[out] - the position where a collision occured\n" -"* `pos`[out] - coordinates of a tile where a collision occured\n" "\n" -"Note: While there may be multiple collisions with a tilemap, this function\n" -"will only return one.\n" +"## fn Image.getData\n" "\n" +"```\n" +"fn (i: ^Image) getData*(): []uint32 {\n" +"```\n" "\n" -"## fn Tilemap.autotile\n" +"Gets the image data. This downloads the data from the GPU on **each call**.\n" +"Don\'t use in performance critical sections.\n" +"\n" +"\n" +"", +"## \n" "\n" "```\n" -"fn (t: ^Tilemap) autotile*(src, tileCfg: []th.uu, tile: th.uu) {\n" "```\n" "\n" -"Autotile turns all `tile` tiles in `src` into tiles in `tileCfg`, so they\n" -"follow up correctly. `tileCfg` is an array of 16 tiles. They are placed in\n" -"a way where OR of all the places where the tile continues (top, right bot,\n" -"right). The constants for them are defined in this file. Example:\n" -"tileCfg[top | bot] = 21\n" -"top | bot would look something like this: |\n" +"Module for getting keyboard and mouse input.\n" +"is* functions return info based on a us QWERTY layout. They are supposed to\n" +"be used for game controls. For text input use getStr.\n" "\n" "\n" -"", -"## Cursor types\n" +"## Keycode constants\n" "\n" "```\n" "const (\n" -"\tcursorDefault* = 0\t\t// Default system cursor\n" -"\tcursorArrow*\t\t\t// Normal cursor; Arrow cursor\n" -"\tcursorIBeam*\t\t\t// \'I\' text cursor; I-Beam\n" -"\tcursorCrosshair*\t\t// \'+\' cursor; Select region cursor\n" -"\tcursorFinger*\t\t\t// Index finger pointing cursor; Click cursor\n" -"\tcursorSizeEW*\t\t\t// \'<->\' cursor; Resize width cursor; Resize horizontally cursor; East-West resize cursor\n" -"\tcursorSizeNS*\t\t\t// Resize height cursor; Resize vertically cursor; North-South resize cursor\n" -"\tcursorSizeNWSE*\t\t\t// Resize width and height from the right side cursor; Northwest-Southeast resize cursor\n" -"\tcursorSizeSWNE*\t\t\t// Resize width and height from the left side cursor; Southwest-Northeast resize cursor\n" -"\tcursorSizeAll*\t\t\t// Resize all cursor; Move cursor\n" -"\tcursorNo*\t\t\t// \'(/)\' cursor; Disabled cursor; Disallowed cursor\n" -"\tcursorCount_*\n" +" mouse1* = 1 // NOTE: mouse 2 and 3 key codes are swapped\n" +" mouse2* = 3 // because sokol uses 3 for middle mouse\n" +" mouse3* = 2 // button.\n" +"\n" +" key_ctrl* = 16\n" +" key_shift* = 17\n" +" key_alt* = 18\n" +"\n" +" key_space* = 32\n" +" key_apostrophe* = 39 /* \' */\n" +" key_comma* = 44 /* , */\n" +" key_minus* = 45 /* - */\n" +" key_dot* = 46 /* . */\n" +" key_slash* = 47 /* / */\n" +" key_0* = 48\n" +" key_1* = 49\n" +" key_2* = 50\n" +" key_3* = 51\n" +" key_4* = 52\n" +" key_5* = 53\n" +" key_6* = 54\n" +" key_7* = 55\n" +" key_8* = 56\n" +" key_9* = 57\n" +" key_semicolon* = 59 /* ; */\n" +" key_equal* = 61 /* = */\n" +" key_a* = 65\n" +" key_b* = 66\n" +" key_c* = 67\n" +" key_d* = 68\n" +" key_e* = 69\n" +" key_f* = 70\n" +" key_g* = 71\n" +" key_h* = 72\n" +" key_i* = 73\n" +" key_j* = 74\n" +" key_k* = 75\n" +" key_l* = 76\n" +" key_m* = 77\n" +" key_n* = 78\n" +" key_o* = 79\n" +" key_p* = 80\n" +" key_q* = 81\n" +" key_r* = 82\n" +" key_s* = 83\n" +" key_t* = 84\n" +" key_u* = 85\n" +" key_v* = 86\n" +" key_w* = 87\n" +" key_x* = 88\n" +" key_y* = 89\n" +" key_z* = 90\n" +" key_left_bracket* = 91 /* [ */\n" +" key_backslash* = 92 /* \\ */\n" +" key_right_bracket* = 93 /* ] */\n" +" key_grave_accent* = 96 /* ` */\n" +" key_world_1* = 161 /* non-US #1 */\n" +" key_world_2* = 162 /* non-US #2 */\n" +" key_escape* = 256\n" +" key_enter* = 257\n" +" key_tab* = 258\n" +" key_backspace* = 259\n" +" key_insert* = 260\n" +" key_delete* = 261\n" +" key_right* = 262\n" +" key_left* = 263\n" +" key_down* = 264\n" +" key_up* = 265\n" +" key_page_up* = 266\n" +" key_page_down* = 267\n" +" key_home* = 268\n" +" key_end* = 269\n" +" key_caps_lock* = 280\n" +" key_scroll_lock* = 281\n" +" key_num_lock* = 282\n" +" key_print_screen* = 283\n" +" key_pause* = 284\n" +"\tkey_fn* = 289\n" +" key_fn1* = 290\n" +" key_fn2* = 291\n" +" key_fn3* = 292\n" +" key_fn4* = 293\n" +" key_fn5* = 294\n" +" key_fn6* = 295\n" +" key_fn7* = 296\n" +" key_fn8* = 297\n" +" key_fn9* = 298\n" +" key_fn10* = 299\n" +" key_fn11* = 300\n" +" key_fn12* = 301\n" +" key_fn13* = 302\n" +" key_fn14* = 303\n" +" key_fn15* = 304\n" +" key_fn16* = 305\n" +" key_fn17* = 306\n" +" key_fn18* = 307\n" +" key_fn19* = 308\n" +" key_fn20* = 309\n" +" key_fn21* = 310\n" +" key_fn22* = 311\n" +" key_fn23* = 312\n" +" key_fn24* = 313\n" +" key_fn25* = 314\n" +" key_kp_0* = 320\n" +" key_kp_1* = 321\n" +" key_kp_2* = 322\n" +" key_kp_3* = 323\n" +" key_kp_4* = 324\n" +" key_kp_5* = 325\n" +" key_kp_6* = 326\n" +" key_kp_7* = 327\n" +" key_kp_8* = 328\n" +" key_kp_9* = 329\n" +" key_kp_decimal* = 330\n" +" key_kp_divide* = 331\n" +" key_kp_multiply* = 332\n" +" key_kp_subtract* = 333\n" +" key_kp_add* = 334\n" +" key_kp_enter* = 335\n" +" key_kp_equal* = 336\n" +" key_left_shift* = 340\n" +" key_left_control* = 341\n" +" key_left_alt* = 342\n" +" key_left_super* = 343\n" +" key_right_shift* = 344\n" +" key_right_control* = 345\n" +" key_right_alt* = 346\n" +" key_right_super* = 347\n" +" key_menu* = 348\n" ")\n" "```\n" "\n" "\n" "\n" -"## Window dimensions\n" +"## fn getMousePos\n" "\n" "```\n" -"var (\n" -"\tw*, h*: int32\n" -")\n" +"fn getMousePos*(): th.Vf2 {\n" "```\n" "\n" +"Returns the position of mouse cursor in relation to the screen.\n" "\n" "\n" -"## Viewport size\n" +"## fn getGlobalMousePos\n" "\n" "```\n" -"var wp*: th.Vf2\n" +"fn getGlobalMousePos*(): th.Vf2 {\n" "```\n" "\n" +"Returns the position of mouse cursor in relation to cam.\n" "\n" "\n" -"## signal OnFrame\n" +"## fn isPressed\n" "\n" "```\n" -"var onFrame*: signal.Signal\n" +"fn isPressed*(code: int): bool {\n" "```\n" "\n" +"Returns true if key is pressed. Either use codes defined in the file above,\n" +"or pass lower case char/number.\n" "\n" "\n" -"## signal OnDestroy\n" +"## fn isPressedc\n" "\n" "```\n" -"var onDestroy*: signal.Signal\n" +"fn isPressedc*(code: char): bool {\n" "```\n" "\n" +"Like `isPressed`, but you can pass char as the code.\n" "\n" "\n" -"## fn setViewport\n" +"## fn isJustPressed\n" "\n" "```\n" -"fn setViewport*(dm: th.Vf2) {\n" +"fn isJustPressed*(code: int): bool {\n" "```\n" "\n" -"Sets the dimensions of the viewport. The dimensions are saved in the `wp`\n" -"variable.\n" -"\n" -"`dm`\n" -": dimension of the viewport\n" +"Returns, whether code was just pressed this loop.\n" "\n" "\n" -"## fn isDpiEnabled\n" +"## fn isJustPressedc\n" "\n" "```\n" -"fn isDpiEnabled*(): bool {\n" +"fn isJustPressedc*(code: char): bool {\n" "```\n" "\n" -"Returns true if DPI awareness was enabled\n" +"Like `isJustPressed`, but you can pass char as the code.\n" "\n" "\n" -"## fn getDpiScaleFactor\n" +"## fn isPressedRepeat\n" "\n" "```\n" -"fn getDpiScaleFactor*(): th.fu {\n" +"fn isPressedRepeat*(code: int): bool {\n" "```\n" "\n" -"Returns the DPI scaling of the current window.\n" -"If `dpiAware` was not enabled in window setup, this function will return 1.0 (default scaling).\n" +"Returns, whether code was just pressed this loop, with key repeat.\n" "\n" "\n" -"## fn setup\n" +"## fn isPressedRepeatc\n" "\n" "```\n" -"fn setup*(title: str = \"tophat game\", width: int = 400, height: int32 = 400) {\n" +"fn isPressedRepeatc*(code: char): bool {\n" "```\n" "\n" -"Sets up the engine and opens a window.\n" +"Like `isPressedRepeat`, but you can pass char as the code.\n" "\n" "\n" -"## fn cycle\n" +"## fn isJustReleased\n" "\n" "```\n" -"fn cycle(delta: real) {\n" +"fn isJustReleased*(code: int): bool {\n" "```\n" "\n" -"Cycle needs to be called every cycle for the window to work. If the window\n" -"was closed, it returns false.\n" +"Returns true if a key was just released.\n" "\n" "\n" -"## fn setFullscreen\n" +"## fn isJustReleasedc\n" "\n" "```\n" -"fn setFullscreen*(fullscreen: bool) {\n" +"fn isJustReleasedc*(code: char): bool {\n" "```\n" "\n" -"Makes window go full screen\n" +"Like `isJustReleased`, but you can pass char as the code.\n" "\n" "\n" -"## fn isFullscreen\n" +"## fn clear\n" "\n" "```\n" -"fn isFullscreen*(): bool {\n" +"fn clear*(code: int) {\n" "```\n" "\n" -"Returns true if window is fullscreen\n" +"Clears both the pressed and justPressed state of a code.\n" "\n" "\n" -"## fn getDims\n" +"## fn clearc\n" "\n" "```\n" -"fn getDims*(): th.Vf2 {\n" +"fn clearc*(code: char) {\n" "```\n" "\n" -"Returns dimensions of the window in screen pixels.\n" +"Like `clear`, but you can pass char as the code.\n" "\n" "\n" -"## fn setTargetFps\n" +"## fn getStr\n" "\n" "```\n" -"fn setTargetFps*(fps: int) {\n" +"fn getStr*(): str {\n" "```\n" "\n" -"Sets the fps limit.\n" -"\n" -"`fps`\n" -": amount of fps the limit should be set to\n" -"\n" +"Returns a string entered by the user in the last cycle.\n" "\n" "\n" -"## fn setDims\n" +"## fn getMouseDelta\n" "\n" "```\n" -"fn setDims*(dm: th.Vf2) {\n" +"fn getMouseDelta*(): th.Vf2 {\n" "```\n" "\n" -"Sets the dimensions of the window.\n" -"\n" -"`dm`\n" -": the target dimensions in screen pixels\n" +"Returns the difference between mouse positions in the last cycle. Will work\n" +"even if `window.freezeCursor` is enabled.\n" "\n" "\n" -"## fn setIcon\n" +"## fn getMouseScroll\n" "\n" "```\n" -"fn setIcon*(img: image.Image) {\n" +"fn getMouseScroll*(): th.Vf2 {\n" "```\n" "\n" -"Sets the window icon.\n" +"Returns the scroll wheel value\n" "\n" "\n" -"## fn showCursor\n" +"", +"## \n" "\n" "```\n" -"fn showCursor*(show: bool) {\n" "```\n" "\n" -"Show or hide the cursor, linux only.\n" +"Misc functions.\n" "\n" "\n" -"## fn freezeCursor\n" +"## fn readall\n" "\n" "```\n" -"fn freezeCursor*(freeze: bool) {\n" +"fn readall*(path: str): str {\n" "```\n" "\n" -"Freezes the cursor in place. `input.getMouseDelta` will still report mouse\n" -"movements. The cursor will be automatically hidden.\n" +"Reads file content into a string.\n" "\n" "\n" -"## fn setCursor\n" +"## fn stepify\n" "\n" "```\n" -"fn setCursor*(cursor: int) {\n" +"fn stepify*(val, step: th.fu): th.fu {\n" "```\n" "\n" -"Allows you to set the displaying cursor. Refer to the cursors section for available cursors.\n" +"Snaps a value to step.\n" "\n" "\n" -"## fn quit\n" +"## fn maxf\n" "\n" "```\n" -"fn quit*() {\n" +"fn maxf*(a, b: th.fu): th.fu {\n" "```\n" "\n" -"Exits the application. Use this instead of umka\'s default `exit`.\n" "\n" "\n" -"## fn setClipboard\n" +"## fn minf\n" "\n" "```\n" -"fn setClipboard*(s: str) {\n" +"fn minf*(a, b: th.fu): th.fu {\n" "```\n" "\n" -"Puts a string to the system clipboard.\n" "\n" "\n" -"## fn getClipboard\n" +"", +"## \n" "\n" "```\n" -"fn getClipboard*(): str {\n" "```\n" "\n" -"Gets a string from the system clipboard.\n" +"Canvas library allowing for drawing basic shapes. Coordinates are based on\n" +"the screen.\n" "\n" "\n" -"## fn setViewportOffset\n" +"## fn drawText\n" "\n" "```\n" -"fn setViewportOffset*(s: th.Vf2) {\n" +"fn drawText*(text: str, pos: th.Vf2, color: uint32, size: th.fu) {\n" "```\n" "\n" -"Sets the offset of the viewport.\n" +"Draws a basic pixel text. Only ascii is supported.\n" "\n" "\n" -"## fn getViewportOffset\n" +"## fn textSize\n" "\n" "```\n" +"fn textSize*(text: str, scale: th.fu): th.Vf2 {\n" "```\n" "\n" -"Gets the offset of the viewport (as set by `setViewportShift`)\n" +"Returns the size of text taken by an equivalent drawText call.\n" "\n" "\n" -"", -"", -"## \n" +"## fn drawRect\n" "\n" "```\n" +"fn drawRect*(color: uint32, r: rect.Rect) {\n" "```\n" "\n" -"Particles allow for *performant* and random particle systems.\n" +"Draws a Rectangle.\n" "\n" "\n" -"## struct Particle\n" +"## fn drawLine\n" "\n" "```\n" -"type Particle* = struct {\n" -"```\n" -"\n" -"Particle struct. You can tweak the start_time for godot-like explossivness.\n" -"\n" -"\n" -"## struct Emitter\n" -"\n" +"fn drawLine*(color: uint32, b, e: th.Vf2, thickness: th.fu) {\n" "```\n" -"type Emitter* = struct {\n" -"\tpos: th.Vf2 // position\n" -"\tdm: th.Vf2 // size of the emittion area\n" -"\tgravity: th.Vf2 // gravity\n" -"\trepeat: bool // if false, particle won\'t be renewed\n" -"\tactive: bool // false, if there aren\'t any active particles anymore\n" -"\n" -"\tangle: th.Vf2 // angle in which particles are emitted\n" -"\n" -"\tlifetime: th.uu // lifetime of particles\n" -"\tlifetimeRandomness: th.fu // randomness in %/100\n" -"\n" -"\tvelocity: th.fu // velocity\n" -"\tvelocityRandomness: th.fu // randomness in %/100\n" "\n" -"\tsize: th.fu // size\n" -"\tsizeRandomness: th.fu // randomness in %/100\n" -"\tmaxSize: th.fu // size at the end of particles lifetime\n" +"Draws a line.\n" "\n" -"\trotation: th.fu\n" -"\trotationRandomness: th.fu\n" -"\tmaxRotation: th.fu\n" "\n" -"\tcolors: []uint32 // array of colors, which are interpolated between\n" +"## fn drawRectLines\n" "\n" -"\tparticles: []Particle // list of particles\n" -"}\n" +"```\n" +"fn drawRectLines*(color: uint32, r: rect.Rect, thickness: real32 = 1.0) {\n" "```\n" "\n" -"Emitter. This is where everything is configured.\n" +"Draws rect border.\n" "\n" "\n" -"## fn Emitter.draw\n" +"## fn drawQuad\n" "\n" "```\n" -"fn (e: ^Emitter) draw*(t: int32) {\n" +"fn drawQuad*(color: uint32, q: th.Quad) {\n" "```\n" "\n" -"Draws and updates the particles.\n" +"Draws a convex quad.\n" "\n" "\n" -"## fn Emitter.genParticles\n" +"## fn beginScissorRect\n" "\n" "```\n" -"fn (e: ^Emitter) genParticles*(time, count: uint, explosiveness: th.fu = 0.0) {\n" +"fn beginScissorRect*(r: rect.Rect, debug: bool = false) {\n" "```\n" "\n" -"Generates particles for an emitter. The time specifies the time the first\n" -"particles is emitted. The explosiveness argument specifies the interval at\n" -"which particles are emitted using this formula:\n" -"/ ```umka\n" -"/ e.lifetime / count * explosiveness\n" -"/ ```\n" +"Disable rendering outside of rect `r`\n" "\n" "\n" -"", -"## \n" +"## fn endScissor\n" "\n" "```\n" +"fn endScissor*() {\n" "```\n" "\n" -"Simple linear interpolation module.\n" +"Stops cropping\n" "\n" "\n" "", -"## \n" +"## struct Ray\n" "\n" "```\n" +"type Ray* = struct {\n" +"\tpos: th.Vf2\n" +"\tl: th.fu // length\n" +"\tr: th.fu // rotation\n" +"}\n" "```\n" "\n" -"Module for font rendering. Unicode is supported, but only left to right.\n" +"Ray is a line specified by an origin, length and a rotation.\n" "\n" "\n" -"## Filtering constants\n" +"## fn mk\n" "\n" "```\n" -"const (\n" -"\tfilterNearest* = 0\n" -"\tfilterLinear* = 1\n" -")\n" +"fn mk*(pos: th.Vf2, l: th.fu, r: th.fu = 0.0): Ray {\n" "```\n" "\n" +"Ray constructor\n" "\n" "\n" -"## opaque Font\n" +"## fn Ray.getColl\n" "\n" "```\n" -"type Font* = struct { _: ^struct{} }\n" +"fn (r: ^Ray) getColl*(s: []^ent.Ent, maxColls: th.uu): []ent.Coll {\n" "```\n" "\n" +"Checks the ray\'s collisions with a scene of ents. Similar to\n" +"`ent.Ent.getColl`\n" "\n" "\n" -"## fn load\n" +"## fn Ray.getTilemapColl\n" "\n" "```\n" -"fn load*(path: str, size: th.fu, filter: uint32 = filterLinear): Font {\n" +"fn (r: ^Ray) getTilemapColl*(t: tilemap.Tilemap, ic: ^th.Vf2): bool {\n" "```\n" "\n" +"Gets ray\'s collision to a tilemap.\n" "\n" "\n" -"## fn Font.validate\n" +"## fn Ray.getEnd\n" "\n" "```\n" -"fn (f: ^Font) validate*(): bool {\n" +"fn (r: ^Ray) getEnd*(): th.Vf2 {\n" "```\n" "\n" +"Returns the other point of the ray.\n" "\n" "\n" -"## fn Font.draw\n" +"## fn Ray.draw\n" "\n" "```\n" -"fn (f: ^Font) draw*(text: str, pos: th.Vf2, color: uint32, scale: th.fu = 1.0) {\n" +"fn (r: ^Ray) draw*(color: uint32, thickness: th.fu) {\n" "```\n" "\n" +"Draws the ray to the screen.\n" "\n" "\n" -"## fn Font.measure\n" +"", +"## struct Rect\n" "\n" "```\n" -"fn (f: ^Font) measure*(text: str): th.Vf2 {\n" +"type Rect* = struct {\n" +"\tx, y, w, h: th.fu\n" +"}\n" "```\n" "\n" +"A set of points representing a rectangle.\n" "\n" "\n" -"", -"## \n" +"## fn mk\n" "\n" "```\n" +"fn mk*(x, y, w, h: th.fu): Rect {\n" "```\n" "\n" -"Module with useful variables and types.\n" -"Variables: time, delta, platform\n" -"Constants: black, white, red, green, blue, yellow, magenta, cyan.\n" "\n" "\n" -"## Tophat type aliases\n" +"## fn mk\n" "\n" "```\n" -"type fu* = real32\n" -"// standard type for integer values\n" -"type iu* = int32\n" -"// standard type for unsigned values\n" -"type uu* = uint32\n" +"fn fromVf2*(p: th.Vf2, dm: th.Vf2): Rect {\n" "```\n" "\n" -"standard type for real values\n" +"Creates a rect from two Vf2s - the position and the dimensions.\n" "\n" "\n" -"## struct Vf2\n" +"## fn Rect.getPos\n" "\n" "```\n" -"type Vf2* = struct {\n" -"\tx, y: fu\n" -"}\n" +"fn (r: ^Rect) getPos*(): th.Vf2 {\n" "```\n" "\n" -"vector 2\n" "\n" "\n" -"## fn mkVf2\n" +"## fn Rect.getDims\n" "\n" "```\n" -"fn mkVf2*(x: fu = 0, y: fu = 0): Vf2 {\n" -"\treturn Vf2{x, y}\n" -"}\n" +"fn (r: ^Rect) getDims*(): th.Vf2 {\n" "```\n" "\n" -"Vf2 constructor\n" "\n" "\n" -"## fn Vf2.rotated\n" +"## fn Rect.getEnd\n" "\n" "```\n" -"fn (p: ^Vf2) rotated*(origin: Vf2, rot: fu): Vf2 {\n" +"fn (r: ^Rect) getEnd*(): th.Vf2 {\n" "```\n" "\n" -"rotates `p` around `origin` with `rot` in degrees\n" +"returns where the second point of the rectangle lies.\n" "\n" "\n" -"## fn Vf2.distanceTo\n" +"## fn Rect.transformed\n" "\n" "```\n" -"fn (p1: ^Vf2) distanceTo*(p2: Vf2): fu {\n" +"fn (r: ^Rect) transformed*(t: th.Transform): th.Quad {\n" "```\n" "\n" -"distance between p1 and p2\n" +"Transforms a rect into a quad.\n" +"Order:\n" +"1. scale\n" +"2. rotation\n" +"3. position\n" "\n" "\n" -"## fn Vf2.angleTo\n" +"## fn Rect.shrink\n" "\n" "```\n" -"fn (p1: ^Vf2) angleTo*(p2: Vf2): real {\n" +"fn (r: ^Rect) shrink*(p: th.Vf2): Rect {\n" "```\n" "\n" -"Angle between p1 and p2\n" +"Shrink the rectangle by `p` pixels from all sides.\n" "\n" "\n" -"## fn Vf2.abs\n" +"## fn Rect.shift\n" "\n" "```\n" -"fn (p: ^Vf2) abs*(): Vf2 {\n" +"fn (r: ^Rect) shift*(p: th.Vf2): Rect {\n" "```\n" "\n" -"Absolute value of a vector.\n" +"Shift the rectangle by `p` pixels.\n" "\n" "\n" -"## fn Vf2.round\n" +"## fn Rect.scale\n" "\n" "```\n" -"fn (p: ^Vf2) round*(): Vf2 {\n" +"fn (r: ^Rect) scale*(p: th.Vf2): Rect {\n" "```\n" "\n" -"Rounds a vector.\n" +"Multiply the dimensions by `p`\n" "\n" "\n" -"## fn Vf2.trunc\n" +"## fn Rect.center\n" "\n" "```\n" -"fn (p: ^Vf2) trunc*(): Vf2 {\n" +"fn (r: ^Rect) center*(): th.Vf2 {\n" "```\n" "\n" -"Truncates a vector.\n" +"Returns the position, which is the center of the rect.\n" "\n" "\n" -"## fn Vf2.floor\n" +"## fn Rect.centerWithinRect\n" "\n" "```\n" -"fn (p: ^Vf2) floor*(): Vf2 {\n" +"fn (r: ^Rect) centerWithinRect*(child: Rect): Rect {\n" "```\n" "\n" -"Floors a vector.\n" +"Centers `child` with the rect `r`.\n" "\n" "\n" -"## fn Vf2.ceil\n" +"", +"## \n" "\n" "```\n" -"fn (p: ^Vf2) ceil*(): Vf2 {\n" "```\n" "\n" -"Ceils a vector.\n" +"Tilemaps allow for easy level construction and fast collisions. You can even\n" +"use them for some games instead of entities (tetris comes to mind)\n" "\n" "\n" -"## fn vf2f\n" +"## Direction constants used for autotile\n" "\n" "```\n" -"fn vf2f*(f: fu): Vf2 {\n" +"const (\n" +"\ttop* = 1\n" +"\tright* = 2\n" +"\tbot* = 4\n" +"\tleft* = 8\n" +")\n" "```\n" "\n" -"Creates a vector with both x and y set to f\n" "\n" "\n" -"## fn Vf2.sub\n" +"## struct Tilemap\n" "\n" "```\n" -"fn (p: ^Vf2) sub*(p2: Vf2): Vf2 {\n" +"type Tilemap* = struct {\n" +"\tatlas: atlas.Atlas\n" +"\tpos: th.Vf2\n" +"\tw: th.uu // width of tilemap\n" +"\tcells: []th.uu // all cells (this will draw the tile in tiles with number in cells - 1)\n" +"\tcollMask: []bool // if true, the tile collides\n" +"\tscale: th.fu\n" +"}\n" "```\n" "\n" -"Subtracts a vector from another one.\n" +"Tilemap struct\n" "\n" "\n" -"## fn Vf2.subf\n" +"## fn mk\n" "\n" "```\n" -"fn (p: ^Vf2) subf*(f: fu): Vf2 {\n" +"fn mk*(cells: []th.uu, w: th.uu, at: atlas.Atlas, scale: th.fu = 1): Tilemap {\n" "```\n" "\n" -"Subtracts a fu from a vector.\n" "\n" "\n" -"## fn Vf2.add\n" +"## fn Tilemap.edit\n" "\n" "```\n" -"fn (p: ^Vf2) add*(p2: Vf2): Vf2 {\n" +"fn (t: ^Tilemap) edit*(x, y, tile: int) {\n" "```\n" "\n" -"Adds a vector to another one.\n" +"Sets tile at [x, y] to tile.\n" "\n" "\n" -"## fn Vf2.addf\n" +"## fn Tilemap.draw\n" "\n" "```\n" -"fn (p: ^Vf2) addf*(f: fu): Vf2 {\n" +"fn (t: ^Tilemap) draw*() {\n" "```\n" "\n" -"Adds a fu to a vector.\n" +"Draws the tilemap.\n" "\n" "\n" -"## fn Vf2.div\n" +"## fn Tilemap.getColl\n" "\n" "```\n" -"fn (p: ^Vf2) div*(p2: Vf2): Vf2 {\n" +"fn (t: ^Tilemap) getColl*(e: ent.Ent, ic: ^th.Vf2, pos: ^th.Vf2): bool {\n" "```\n" "\n" -"Divides a vector by another one.\n" +"Checks whether `e` collides with any of the tiles in `t`, which are in the\n" +"collmask.\n" "\n" +"* `ic`[out] - the position where a collision occured\n" +"* `pos`[out] - coordinates of a tile where a collision occured\n" "\n" -"## fn Vf2.divf\n" +"Note: While there may be multiple collisions with a tilemap, this function\n" +"will only return one.\n" +"\n" +"\n" +"## fn Tilemap.autotile\n" "\n" "```\n" -"fn (p: ^Vf2) divf*(f: fu): Vf2 {\n" +"fn (t: ^Tilemap) autotile*(src, tileCfg: []th.uu, tile: th.uu) {\n" "```\n" "\n" -"Divides a vector by a fu.\n" +"Autotile turns all `tile` tiles in `src` into tiles in `tileCfg`, so they\n" +"follow up correctly. `tileCfg` is an array of 16 tiles. They are placed in\n" +"a way where OR of all the places where the tile continues (top, right bot,\n" +"right). The constants for them are defined in this file. Example:\n" +"tileCfg[top | bot] = 21\n" +"top | bot would look something like this: |\n" "\n" "\n" -"## fn Vf2.mul\n" +"", +"## Cursor types\n" "\n" "```\n" -"fn (p: ^Vf2) mul*(p2: Vf2): Vf2 {\n" +"const (\n" +"\tcursorDefault* = 0\t\t// Default system cursor\n" +"\tcursorArrow*\t\t\t// Normal cursor; Arrow cursor\n" +"\tcursorIBeam*\t\t\t// \'I\' text cursor; I-Beam\n" +"\tcursorCrosshair*\t\t// \'+\' cursor; Select region cursor\n" +"\tcursorFinger*\t\t\t// Index finger pointing cursor; Click cursor\n" +"\tcursorSizeEW*\t\t\t// \'<->\' cursor; Resize width cursor; Resize horizontally cursor; East-West resize cursor\n" +"\tcursorSizeNS*\t\t\t// Resize height cursor; Resize vertically cursor; North-South resize cursor\n" +"\tcursorSizeNWSE*\t\t\t// Resize width and height from the right side cursor; Northwest-Southeast resize cursor\n" +"\tcursorSizeSWNE*\t\t\t// Resize width and height from the left side cursor; Southwest-Northeast resize cursor\n" +"\tcursorSizeAll*\t\t\t// Resize all cursor; Move cursor\n" +"\tcursorNo*\t\t\t// \'(/)\' cursor; Disabled cursor; Disallowed cursor\n" +"\tcursorCount_*\n" +")\n" "```\n" "\n" -"Multiplies a vector by another one.\n" "\n" "\n" -"## fn Vf2.mulf\n" +"## Window dimensions\n" "\n" "```\n" -"fn (p: ^Vf2) mulf*(f: fu): Vf2 {\n" +"var (\n" +"\tw*, h*: int32\n" +")\n" "```\n" "\n" -"Multiplies a vector by a fu.\n" "\n" "\n" -"## fn Vf2.mag\n" +"## Viewport size\n" "\n" "```\n" -"fn (p: ^Vf2) mag*(): fu {\n" +"var wp*: th.Vf2\n" "```\n" "\n" -"Returns the magnitude of a vector p.\n" "\n" "\n" -"## fn Vf2.norm\n" +"## signal OnFrame\n" "\n" "```\n" -"fn (p: ^Vf2) norm*(): Vf2 {\n" +"var onFrame*: signal.Signal\n" "```\n" "\n" -"Normalizes a vector.\n" "\n" "\n" -"## fn Vf2.dot\n" +"## signal OnDestroy\n" "\n" "```\n" -"fn (p: ^Vf2) dot*(q: Vf2): fu {\n" +"var onDestroy*: signal.Signal\n" "```\n" "\n" -"Calculates dot product between 2 vectors.\n" "\n" "\n" -"## struct Transform\n" +"## fn setViewport\n" "\n" "```\n" -"type Transform* = struct {\n" -"\tp: Vf2 // position\n" -"\ts: Vf2 // scale\n" -"\to: Vf2 // origin\n" -"\tr: fu // rotation\n" -"}\n" +"fn setViewport*(dm: th.Vf2) {\n" "```\n" "\n" -"Struct defining transformation. Used for example by entities.\n" +"Sets the dimensions of the viewport. The dimensions are saved in the `wp`\n" +"variable.\n" "\n" +"`dm`\n" +": dimension of the viewport\n" "\n" -"## fn mkTransform\n" +"\n" +"## fn isDpiEnabled\n" "\n" "```\n" -"fn mkTransform*(p: Vf2, s: Vf2 = Vf2{1, 1}, o: Vf2 = Vf2{0, 0}, r: fu = 0.0): Transform {\n" +"fn isDpiEnabled*(): bool {\n" "```\n" "\n" -"Transform constructor\n" +"Returns true if DPI awareness was enabled\n" "\n" "\n" -"## fn Transform.transformed\n" +"## fn getDpiScaleFactor\n" "\n" "```\n" -"fn (o: ^Transform) transformed*(t: Transform): Transform {\n" +"fn getDpiScaleFactor*(): th.fu {\n" "```\n" "\n" -"Transforms a transform with another transform.\n" +"Returns the DPI scaling of the current window.\n" +"If `dpiAware` was not enabled in window setup, this function will return 1.0 (default scaling).\n" "\n" "\n" -"## fn Vf2.transformed\n" +"## fn setup\n" "\n" "```\n" -"fn (v: ^Vf2) transformed*(t: Transform): Vf2 {\n" +"fn setup*(title: str = \"tophat game\", width: int = 400, height: int32 = 400) {\n" "```\n" "\n" -"Transforms a vf2 to another vf2.\n" -"Order:\n" -"1. scale\n" -"2. rotation\n" -"3. position\n" -"\n" -"This allows conversion from a relative to an absolute vf2.\n" +"Sets up the engine and opens a window.\n" "\n" "\n" -"## type Quad\n" +"## fn cycle\n" "\n" "```\n" -"type Quad* = [4]Vf2\n" +"fn cycle(delta: real) {\n" "```\n" "\n" +"Cycle needs to be called every cycle for the window to work. If the window\n" +"was closed, it returns false.\n" "\n" "\n" -"## fn Quad.getMax\n" +"## fn setFullscreen\n" "\n" "```\n" -"fn (q: ^Quad) getMax*(): Vf2 {\n" +"fn setFullscreen*(fullscreen: bool) {\n" "```\n" "\n" -"Gets the maximum coordinate.\n" +"Makes window go full screen\n" "\n" "\n" -"## fn Quad.getMin\n" +"## fn isFullscreen\n" "\n" "```\n" -"fn (q: ^Quad) getMin*(): Vf2 {\n" +"fn isFullscreen*(): bool {\n" "```\n" "\n" -"Gets the minimum coordinate.\n" +"Returns true if window is fullscreen\n" "\n" "\n" -"## fn Quad.getDims\n" +"## fn getDims\n" "\n" "```\n" -"fn (q: ^Quad) getDims*(): Vf2 {\n" +"fn getDims*(): th.Vf2 {\n" "```\n" "\n" -"Returns the dimensions of the quad\'s bounding box\n" +"Returns dimensions of the window in screen pixels.\n" "\n" "\n" -"## fn getGlobal\n" +"## fn setTargetFps\n" "\n" "```\n" -"fn getGlobal*(): ^struct{} {\n" +"fn setTargetFps*(fps: int) {\n" "```\n" "\n" -"returns a pointer to the th_global. Set this as your extensions thg.\n" +"Sets the fps limit.\n" +"\n" +"`fps`\n" +": amount of fps the limit should be set to\n" "\n" "\n" -"## fn getFuncs\n" +"\n" +"## fn setDims\n" "\n" "```\n" -"fn getFuncs*(): ^struct{} {\n" +"fn setDims*(dm: th.Vf2) {\n" "```\n" "\n" -"returns pointer to tophat functions. Pass this to th_ext_set.\n" +"Sets the dimensions of the window.\n" "\n" +"`dm`\n" +": the target dimensions in screen pixels\n" "\n" -"## var enableErrrors\n" +"\n" +"## fn setIcon\n" "\n" "```\n" -"var enableErrors*: bool = true\n" +"fn setIcon*(img: image.Image) {\n" "```\n" "\n" -"If true, errors will result in a call to error(), otherwise printf is used.\n" +"Sets the window icon.\n" "\n" "\n" -"## Color constants\n" +"## fn showCursor\n" "\n" "```\n" -"const (\n" -"\tblack* = 0xff\n" -"\twhite* = 0xffffffff\n" -"\tred* = 0xff0000ff\n" -"\tgreen* = 0x00ff00ff\n" -"\tblue* = 0x0000ffff\n" -"\tyellow* = 0xffff00ff\n" -"\tmagenta* = 0xff00ffff\n" -"\tcyan* = 0x00ffffff\n" -")\n" +"fn showCursor*(show: bool) {\n" "```\n" "\n" +"Show or hide the cursor, linux only.\n" "\n" "\n" -"## enum Platform\n" +"## fn freezeCursor\n" "\n" "```\n" -"type Platform* = int\n" -"const (\n" -"\tPlatformUnknown* = 0\n" -"\tPlatformLinux*\n" -"\tPlatformWindows*\n" -"\tPlatformMacOs*\n" -"\tPlatformWeb*\n" -")\n" +"fn freezeCursor*(freeze: bool) {\n" "```\n" "\n" +"Freezes the cursor in place. `input.getMouseDelta` will still report mouse\n" +"movements. The cursor will be automatically hidden.\n" "\n" "\n" -"## Misc variables\n" +"## fn setCursor\n" "\n" "```\n" -"var (\n" -"\t// time in ms from start of the game\n" -"\ttime*: uint\n" -"\t// length of the last frame in ms\n" -"\tdelta*: int\n" -"\t// platform tophat is running on\n" -"\tplatform*: Platform\n" -")\n" +"fn setCursor*(cursor: int) {\n" "```\n" "\n" +"Allows you to set the displaying cursor. Refer to the cursors section for available cursors.\n" "\n" "\n" -"", -"## \n" +"## fn quit\n" "\n" "```\n" +"fn quit*() {\n" "```\n" "\n" -"A module for importless communication between modules. A signal is a set of\n" -"callbacks. You can use signals directly in your own structs if you want\n" -"them to be instance specific, of you can use global signals which are\n" -"adressed by a string name.\n" +"Exits the application. Use this instead of umka\'s default `exit`.\n" "\n" "\n" -"## type Callback\n" +"## fn setClipboard\n" "\n" "```\n" -"type Callback* = fn(args: []any)\n" +"fn setClipboard*(s: str) {\n" "```\n" "\n" -"`args` is a list of arguments passed to the `emit` method.\n" +"Puts a string to the system clipboard.\n" "\n" "\n" -"## type Id\n" +"## fn getClipboard\n" "\n" "```\n" -"type Id* = uint\n" +"fn getClipboard*(): str {\n" "```\n" "\n" +"Gets a string from the system clipboard.\n" "\n" "\n" -"## type Signal\n" +"## fn setViewportOffset\n" "\n" "```\n" -"type Signal* = map[Id]Callback\n" +"fn setViewportOffset*(s: th.Vf2) {\n" "```\n" "\n" +"Sets the offset of the viewport.\n" "\n" "\n" -"## fn mk\n" +"## fn getViewportOffset\n" "\n" "```\n" -"fn mk*(): Signal {\n" "```\n" "\n" -"`Signal` constructor\n" +"Gets the offset of the viewport (as set by `setViewportShift`)\n" "\n" "\n" -"## fn Signal.register\n" +"", +"", +"## \n" "\n" "```\n" -"fn (this: ^Signal) register*(callback: Callback): Id {\n" "```\n" "\n" -"Registers a callback to a signal and returns the callback id.\n" +"Particles allow for *performant* and random particle systems.\n" "\n" "\n" -"## fn Signal.remove\n" +"## struct Particle\n" "\n" "```\n" -"fn (this: ^Signal) remove*(id: Id) {\n" +"type Particle* = struct {\n" "```\n" "\n" -"Removes a callback by id.\n" +"Particle struct. You can tweak the start_time for godot-like explossivness.\n" "\n" "\n" -"## fn Signal.emit\n" +"## struct Emitter\n" "\n" "```\n" -"fn (this: ^Signal) emit*(args: ..any) {\n" -"```\n" +"type Emitter* = struct {\n" +"\tpos: th.Vf2 // position\n" +"\tdm: th.Vf2 // size of the emittion area\n" +"\tgravity: th.Vf2 // gravity\n" +"\trepeat: bool // if false, particle won\'t be renewed\n" +"\tactive: bool // false, if there aren\'t any active particles anymore\n" "\n" -"Emits a signal.\n" +"\tangle: th.Vf2 // angle in which particles are emitted\n" "\n" +"\tlifetime: th.uu // lifetime of particles\n" +"\tlifetimeRandomness: th.fu // randomness in %/100\n" "\n" -"## fn Signal.clear\n" +"\tvelocity: th.fu // velocity\n" +"\tvelocityRandomness: th.fu // randomness in %/100\n" "\n" -"```\n" -"fn (this: ^Signal) clear*() {\n" +"\tsize: th.fu // size\n" +"\tsizeRandomness: th.fu // randomness in %/100\n" +"\tmaxSize: th.fu // size at the end of particles lifetime\n" +"\n" +"\trotation: th.fu\n" +"\trotationRandomness: th.fu\n" +"\tmaxRotation: th.fu\n" +"\n" +"\tcolors: []uint32 // array of colors, which are interpolated between\n" +"\n" +"\tparticles: []Particle // list of particles\n" +"}\n" "```\n" "\n" -"Removes all signal handlers.\n" +"Emitter. This is where everything is configured.\n" "\n" "\n" -"## fn register\n" +"## fn Emitter.draw\n" "\n" "```\n" -"fn register*(name: str, callback: Callback): Id {\n" +"fn (e: ^Emitter) draw*(t: int32) {\n" "```\n" "\n" -"Registers a callback to a global signal. There is no need to explicitly\n" -"create global signals. Returns id of the added callback\n" +"Draws and updates the particles.\n" "\n" "\n" -"## fn remove\n" +"## fn Emitter.genParticles\n" "\n" "```\n" -"fn remove*(name: str, id: Id) {\n" +"fn (e: ^Emitter) genParticles*(time, count: uint, explosiveness: th.fu = 0.0) {\n" "```\n" "\n" -"Removes a callback from a global signal by id.\n" +"Generates particles for an emitter. The time specifies the time the first\n" +"particles is emitted. The explosiveness argument specifies the interval at\n" +"which particles are emitted using this formula:\n" +"/ ```umka\n" +"/ e.lifetime / count * explosiveness\n" +"/ ```\n" "\n" "\n" -"## fn remove\n" +"", +"## \n" "\n" "```\n" -"fn clear*(name: str) {\n" "```\n" "\n" -"Removes all signal handlers from a global signal.\n" +"Simple linear interpolation module.\n" "\n" "\n" -"## fn emit\n" +"", +"## \n" "\n" "```\n" -"fn emit*(name: str, args: ..any) {\n" "```\n" "\n" -"Calls all callbacks associated with the passed global signal name.\n" +"Module for font rendering. Unicode is supported, but only left to right.\n" "\n" "\n" -"", -"## struct Atlas\n" +"## Filtering constants\n" "\n" "```\n" -"type Atlas* = struct {\n" -"\ti: image.Image // source image\n" -"\tcs: th.Vf2 // size of a cell in pixels\n" -"\tdm: th.Vf2 // amount of cells in image\n" -"}\n" +"const (\n" +"\tfilterNearest* = 0\n" +"\tfilterLinear* = 1\n" +")\n" "```\n" "\n" -"Atlas is an image containing tiles in a square grid.\n" "\n" "\n" -"## fn mk\n" +"## opaque Font\n" "\n" "```\n" -"fn mk*(i: image.Image, dm: th.Vf2): Atlas {\n" +"type Font* = struct { _: ^struct{} }\n" "```\n" "\n" -"i: source image\n" -"dm: amount of cells\n" "\n" "\n" -"## fn Atlas.coords\n" +"## fn load\n" "\n" "```\n" -"fn (a: ^Atlas) coords*(n: int): th.Vf2 {\n" +"fn load*(path: str, size: th.fu, filter: uint32 = filterLinear): Font {\n" "```\n" "\n" -"returns the coordinates of the nth tile\n" "\n" "\n" -"## fn Atlas.cropSource\n" +"## fn Font.validate\n" "\n" "```\n" -"fn (a: ^Atlas) cropSource*(at: th.Vf2) {\n" +"fn (f: ^Font) validate*(): bool {\n" "```\n" "\n" -"Crops the sourse image to only show a wanted tile\n" "\n" "\n" -"## fn Atlas.draw\n" +"## fn Font.draw\n" "\n" "```\n" -"fn (a: ^Atlas) draw*(at: th.Vf2, t: th.Transform) {\n" +"fn (f: ^Font) draw*(text: str, pos: th.Vf2, color: uint32, scale: th.fu = 1.0) {\n" "```\n" "\n" -"Draws the tile at `at`\n" "\n" "\n" -"", -"## opaque Shader\n" +"## fn Font.measure\n" "\n" "```\n" -"type Shader* = struct {\n" +"fn (f: ^Font) measure*(text: str): th.Vf2 {\n" "```\n" "\n" -"Shader allows you to define your own vertex and fragment GLSL shaders. This\n" -"is a low-level feature, so it\'s very easy to mess up.\n" "\n" -"In tophat, instead of a main function, shaders provide th_vertex and\n" -"th_fragment. The signature of th_vertex is:\n" +"\n" +"", +"## \n" "\n" "```\n" -"vec2 th_vertex(vec2 vert);\n" "```\n" "\n" -"where vert is the position of the vertex taken from the vertex buffer.\n" -"The output is the vertex shader output.\n" +"Module with useful variables and types.\n" +"Variables: time, delta, platform\n" +"Constants: black, white, red, green, blue, yellow, magenta, cyan.\n" "\n" -"As for fragment shaders, there are two types of them. One for canvas\n" -"and one for images. In canvas shaders, the fragment function is very simple:\n" +"\n" +"## Tophat type aliases\n" "\n" "```\n" -"vec4 th_fragment(vec4 color);\n" +"type fu* = real32\n" +"// standard type for integer values\n" +"type iu* = int32\n" +"// standard type for unsigned values\n" +"type uu* = uint32\n" "```\n" "\n" -"Image fragment function looks like this:\n" +"standard type for real values\n" "\n" -"```\n" -"vec4 th_fragment(sampler2D tex, vec2 coord);\n" -"```\n" "\n" -"where tex is the texture and coord are the texture coordinates. Be aware to\n" -"swap the output of the `texture2D` function. Example:\n" +"## struct Vf2\n" "\n" "```\n" -"texture2D(tex, coord).abgr\n" +"type Vf2* = struct {\n" +"\tx, y: fu\n" +"}\n" "```\n" "\n" +"vector 2\n" +"\n" "\n" -"## Default shader constants\n" +"## fn mkVf2\n" "\n" "```\n" -"const (\n" -"\tdefaultImageShader* = Shader{1}\n" -"\tdefaultCanvasShader* = Shader{2}\n" -")\n" +"fn mkVf2*(x: fu = 0, y: fu = 0): Vf2 {\n" +"\treturn Vf2{x, y}\n" +"}\n" "```\n" "\n" +"Vf2 constructor\n" "\n" "\n" -"## struct Uniform\n" +"## fn Vf2.rotated\n" "\n" "```\n" -"type Uniform* = struct {\n" -"\ts: Shader\n" -"\tl: uint\n" -"}\n" +"fn (p: ^Vf2) rotated*(origin: Vf2, rot: fu): Vf2 {\n" "```\n" "\n" -"Represents a GLSL uniform.\n" +"rotates `p` around `origin` with `rot` in degrees\n" "\n" "\n" -"## fn mkCanvas\n" +"## fn Vf2.distanceTo\n" "\n" "```\n" -"fn mkCanvas*(vertex, fragment: str): Shader {\n" +"fn (p1: ^Vf2) distanceTo*(p2: Vf2): fu {\n" "```\n" "\n" -"Compiles a canvas shader from source. If there is a compilation error, it\n" -"will print something to the console.\n" +"distance between p1 and p2\n" "\n" "\n" -"## fn mkImage\n" +"## fn Vf2.angleTo\n" "\n" "```\n" -"fn mkImage*(vertex, fragment: str): Shader {\n" +"fn (p1: ^Vf2) angleTo*(p2: Vf2): real {\n" "```\n" "\n" -"Compiles an image shader from source. If there is a compilation error, it\n" -"will print something to the console.\n" +"Angle between p1 and p2\n" "\n" "\n" -"## fn Shader.pickForCanvas\n" +"## fn Vf2.abs\n" "\n" "```\n" -"fn (s: ^Shader) pickForCanvas*() {\n" +"fn (p: ^Vf2) abs*(): Vf2 {\n" "```\n" "\n" -"Picks the shader to be used for canvas drawing. Flushes the canvas batch.\n" +"Absolute value of a vector.\n" "\n" "\n" -"## fn Shader.pickForImage\n" +"## fn Vf2.round\n" "\n" "```\n" -"fn (s: ^Shader) pickForImage*() {\n" +"fn (p: ^Vf2) round*(): Vf2 {\n" "```\n" "\n" -"Picks the shader to be used for image drawing. Flushes the image batch.\n" +"Rounds a vector.\n" "\n" "\n" -"## fn Shader.getUniformLocation\n" +"## fn Vf2.trunc\n" "\n" "```\n" -"fn (s: ^Shader) getUniformLocation*(name: str): Uniform {\n" +"fn (p: ^Vf2) trunc*(): Vf2 {\n" "```\n" "\n" -"Retunrs a uniform by name.\n" +"Truncates a vector.\n" "\n" "\n" -"## fn Uniform.setInt\n" +"## fn Vf2.floor\n" "\n" "```\n" -"fn (u: ^Uniform) setInt*(value: int) {\n" +"fn (p: ^Vf2) floor*(): Vf2 {\n" "```\n" "\n" -"Sets a uniform to an int value. Flushes both batches.\n" +"Floors a vector.\n" "\n" "\n" -"## fn Uniform.setVf2\n" +"## fn Vf2.ceil\n" "\n" "```\n" -"fn (u: ^Uniform) setVf2*(value: th.Vf2) {\n" +"fn (p: ^Vf2) ceil*(): Vf2 {\n" "```\n" "\n" -"Sets a uniform to a vf2. Flushes both batches.\n" +"Ceils a vector.\n" "\n" "\n" -"", -"## \n" +"## fn vf2f\n" "\n" "```\n" +"fn vf2f*(f: fu): Vf2 {\n" "```\n" "\n" -"Color operations. Operate on RGBA uint32 values.\n" +"Creates a vector with both x and y set to f\n" "\n" "\n" -"## fn hsv\n" +"## fn Vf2.sub\n" "\n" "```\n" -"fn hsv*(h, s, v: th.fu, a: th.fu = 1.0): uint32 {\n" +"fn (p: ^Vf2) sub*(p2: Vf2): Vf2 {\n" "```\n" "\n" -"Converts HSV values into RGBA uint32 color.\n" -"NOTE: Hue is between 0 and 1\n" +"Subtracts a vector from another one.\n" "\n" "\n" -"## fn alpha\n" +"## fn Vf2.subf\n" "\n" "```\n" -"fn alpha*(c: uint32, to: th.fu): uint32 {\n" +"fn (p: ^Vf2) subf*(f: fu): Vf2 {\n" "```\n" "\n" -"Sets alpha of the color c to a value in to.\n" +"Subtracts a fu from a vector.\n" "\n" "\n" -"## fn rgb\n" +"## fn Vf2.add\n" "\n" "```\n" -"fn rgb*(r, g, b: th.fu, a: th.fu = 1.0): uint32 {\n" +"fn (p: ^Vf2) add*(p2: Vf2): Vf2 {\n" "```\n" "\n" -"Constructs RGBA uint32 from RGBA of reals.\n" +"Adds a vector to another one.\n" "\n" "\n" -"", -"## \n" +"## fn Vf2.addf\n" "\n" "```\n" +"fn (p: ^Vf2) addf*(f: fu): Vf2 {\n" "```\n" "\n" -"Builtin collision functions. The ic argument stores the collision position.\n" +"Adds a fu to a vector.\n" "\n" "\n" -"## fn lineToLine\n" +"## fn Vf2.div\n" "\n" "```\n" -"fn lineToLine*(b1, e1, b2, e2: th.Vf2, ic: ^th.Vf2): bool {\n" +"fn (p: ^Vf2) div*(p2: Vf2): Vf2 {\n" "```\n" "\n" -"Checks for a collision between 2 lines specified by their end points.\n" +"Divides a vector by another one.\n" "\n" "\n" -"## fn vf2ToQuad\n" +"## fn Vf2.divf\n" "\n" "```\n" -"fn vf2ToQuad*(p: th.Vf2, q: th.Quad, ic: ^th.Vf2): bool {\n" +"fn (p: ^Vf2) divf*(f: fu): Vf2 {\n" "```\n" "\n" -"Checks for a collision between a vf2 and a quad.\n" +"Divides a vector by a fu.\n" "\n" "\n" -"## fn lineToQuad\n" +"## fn Vf2.mul\n" "\n" "```\n" -"fn lineToQuad*(b, e: th.Vf2, q: th.Quad, ic: ^th.Vf2): bool {\n" +"fn (p: ^Vf2) mul*(p2: Vf2): Vf2 {\n" "```\n" "\n" -"Check for a collision between a line and quad edges.\n" +"Multiplies a vector by another one.\n" "\n" "\n" -"## fn quadToQuad\n" +"## fn Vf2.mulf\n" "\n" "```\n" -"fn quadToQuad*(q1, q2: th.Quad, ic: ^th.Vf2): bool {\n" +"fn (p: ^Vf2) mulf*(f: fu): Vf2 {\n" "```\n" "\n" -"Check for a collision between two quads.\n" +"Multiplies a vector by a fu.\n" "\n" "\n" -"## fn vf2ToRect\n" +"## fn Vf2.mag\n" "\n" "```\n" -"fn vf2ToRect*(p: th.Vf2, r: rect.Rect): bool {\n" +"fn (p: ^Vf2) mag*(): fu {\n" "```\n" "\n" -"Check for a collision between a vf2 and a rectangle.\n" +"Returns the magnitude of a vector p.\n" "\n" "\n" -"## fn rectToRect\n" +"## fn Vf2.norm\n" "\n" "```\n" -"fn rectToRect*(r1, r2: rect.Rect): bool {\n" +"fn (p: ^Vf2) norm*(): Vf2 {\n" "```\n" "\n" -"Check for a collision between two rects\n" +"Normalizes a vector.\n" "\n" "\n" -"", -"## Placeholder images\n" +"## fn Vf2.dot\n" "\n" "```\n" -"var (\n" -"\t// an image useful for testing\n" -"\ttest*: image.Image\n" -"\t// the image used for the app icon\n" -"\ticon*: image.Image\n" -"\t// Windows 95 style button, to be used with ninepatch (image.um) \n" -"\tbutton*: image.Image\n" -")\n" +"fn (p: ^Vf2) dot*(q: Vf2): fu {\n" "```\n" "\n" -"These images are included with tophat and don\'t have to be loaded.\n" +"Calculates dot product between 2 vectors.\n" "\n" "\n" -"", -"## struct Mesh\n" +"## struct Transform\n" "\n" "```\n" -"type Mesh* = struct {\n" -"\t// The mesh data.\n" -"\td: []bool\n" -"\t// The dimensions and position of the mesh, r.w == w * s\n" -"\tr: rect.Rect\n" -"\t// Width of the mesh. Used to adress the mesh data.\n" -"\tw: th.uu\n" -"\t// Scale of one cell (cell is a square)\n" -"\ts: th.fu\n" +"type Transform* = struct {\n" +"\tp: Vf2 // position\n" +"\ts: Vf2 // scale\n" +"\to: Vf2 // origin\n" +"\tr: fu // rotation\n" "}\n" "```\n" "\n" -"Mesh is a 2d array of bool cells. If a cell is true, the cell can be used\n" -"in a path. The mesh is located in a world using the `r` field. A cell can\n" -"have an arbitrary size as specified by `s`.\n" -"\n" -"The mesh can be edited using the `addQuad` method, but it should be trivial\n" -"to add your own, similar methods.\n" -"\n" -"Please use the `mk` constructor to construct a `Mesh`, unless you really\n" -"know what you\'re doing.\n" +"Struct defining transformation. Used for example by entities.\n" "\n" "\n" -"## fn mk\n" +"## fn mkTransform\n" "\n" "```\n" -"fn mk*(r: rect.Rect, s: th.fu): Mesh {\n" +"fn mkTransform*(p: Vf2, s: Vf2 = Vf2{1, 1}, o: Vf2 = Vf2{0, 0}, r: fu = 0.0): Transform {\n" "```\n" "\n" -"Creates a new nav mesh.\n" -"`r`\n" -": the rectangle of the mask\n" -"\'s\'\n" -": the scale of the mask\n" +"Transform constructor\n" "\n" "\n" -"## fn Mesh.addQuad\n" +"## fn Transform.transformed\n" "\n" "```\n" -"fn (m: ^Mesh) addQuad*(q: th.Quad) {\n" +"fn (o: ^Transform) transformed*(t: Transform): Transform {\n" "```\n" "\n" -"Sets mask\'s fields overlapping `q` to `false`.\n" +"Transforms a transform with another transform.\n" "\n" "\n" -"## fn Mesh.nav\n" +"## fn Vf2.transformed\n" "\n" "```\n" -"fn (m: ^Mesh) nav*(p1, p2: th.Vf2): []th.Vf2 {\n" +"fn (v: ^Vf2) transformed*(t: Transform): Vf2 {\n" "```\n" "\n" -"Navigates between `p1` and `p2`. Returns the path as an array of `th.Vf2`s.\n" -"If it doesn\'t find any path, or one of the points is outside of the mask,\n" -"returns an empty array.\n" +"Transforms a vf2 to another vf2.\n" +"Order:\n" +"1. scale\n" +"2. rotation\n" +"3. position\n" "\n" +"This allows conversion from a relative to an absolute vf2.\n" "\n" -"## fn Mesh.draw\n" +"\n" +"## type Quad\n" "\n" "```\n" -"fn (m: ^Mesh) draw*(alpha: real32 = 1.0) {\n" +"type Quad* = [4]Vf2\n" "```\n" "\n" -"Draws the mesh for debugging purposes.\n" "\n" "\n" -"", -"## \n" +"## fn Quad.getMax\n" "\n" "```\n" +"fn (q: ^Quad) getMax*(): Vf2 {\n" "```\n" "\n" -"`ui.um` offers an immediate GUI library suitable both for simple game menus\n" -"and more complex applications. See the [tutorial](/tut/spritesheet.html)\n" -"for example usage.\n" +"Gets the maximum coordinate.\n" "\n" "\n" -"## struct BoxStyle\n" +"## fn Quad.getMin\n" "\n" "```\n" -"type BoxStyle* = struct {\n" -"\timg: image.Image\n" -"\touter, inner: rect.Rect\n" -"\tscale: th.fu\n" -"\tcolor: uint32\n" -"}\n" +"fn (q: ^Quad) getMin*(): Vf2 {\n" "```\n" "\n" -"`BoxStyle` describes how a box within the GUI is styled. In this case box\n" -"can be anything, ranging from a button to a container. By default the box\n" -"is drawn using the `image.Image.drawNinepatch` method. However if the image\n" -"is invalid, a rectangle with color `color` is drawn.\n" +"Gets the minimum coordinate.\n" "\n" "\n" -"## interface Font\n" +"## fn Quad.getDims\n" "\n" "```\n" -"type Font* = interface {\n" -"\tdraw(text: str, pos: th.Vf2, color: uint32, scale: th.fu = 1.0)\n" -"\tmeasure(test: str): th.Vf2\n" -"}\n" +"fn (q: ^Quad) getDims*(): Vf2 {\n" "```\n" "\n" -"This interface is used by all elements that draw text. A `font.Font`\n" -"implements this interface.\n" +"Returns the dimensions of the quad\'s bounding box\n" "\n" "\n" -"## struct PixelFont\n" +"## fn getGlobal\n" "\n" "```\n" -"type PixelFont* = struct { }\n" +"fn getGlobal*(): ^struct{} {\n" "```\n" "\n" -"This struct implement the `Font` interface using the `canvas.um` pixel font.\n" +"returns a pointer to the th_global. Set this as your extensions thg.\n" "\n" "\n" -"## struct Style\n" +"## fn getFuncs\n" "\n" "```\n" -"type Style* = struct {\n" -"\t// current font\n" -"\tft: Font\n" -"\t// font scale\n" -"\tftScale: th.fu\n" -"\t// text color\n" -"\tftColor: uint32\n" -"\n" -"\t// Positive box - i. e. unpressed button\n" -"\tposBox: BoxStyle\n" -"\t// Negative box - i. e. pressed button, text box\n" -"\tnegBox: BoxStyle\n" -"\t// Used to draw containers\n" -"\tcontainerBox: BoxStyle\n" -"}\n" +"fn getFuncs*(): ^struct{} {\n" "```\n" "\n" -"`Style` is used as a global state for styling the GUI.\n" +"returns pointer to tophat functions. Pass this to th_ext_set.\n" "\n" "\n" -"## interface Container\n" +"## var enableErrrors\n" "\n" "```\n" -"type Container* = interface {\n" -"\t// This adds a rectangle to the container, and returns the rectangle\n" -"\t// which was actually added (the container can modify the rectangle).\n" -"\t// See individual containers for further documentation.\n" -"\tpushRect(r: rect.Rect): rect.Rect\n" -"\tgetDims(): rect.Rect\n" -"}\n" +"var enableErrors*: bool = true\n" "```\n" "\n" -"Containers are used to layout elements or other containers.\n" +"If true, errors will result in a call to error(), otherwise printf is used.\n" "\n" "\n" -"## struct Gui\n" +"## Color constants\n" "\n" "```\n" -"type Gui* = struct {\n" -"\t// user context passed to layout functions\n" -"\tctx: any\n" -"\n" -"\t// the index of the current selection. TODO implement properly\n" -"\tselection: int\n" -"\t// true, if the layout is being evaluated, not drawn\n" -"\tisEval: bool\n" -"\t// contains more unexported fields\n" +"const (\n" +"\tblack* = 0xff\n" +"\twhite* = 0xffffffff\n" +"\tred* = 0xff0000ff\n" +"\tgreen* = 0x00ff00ff\n" +"\tblue* = 0x0000ffff\n" +"\tyellow* = 0xffff00ff\n" +"\tmagenta* = 0xff00ffff\n" +"\tcyan* = 0x00ffffff\n" +")\n" "```\n" "\n" -"This is the main struct of any UI. Styles and containers are in a stack.\n" "\n" "\n" -"## fn mk\n" +"## enum Platform\n" "\n" "```\n" -"fn mk*(r: rect.Rect, s: Style): Gui\n" +"type Platform* = int\n" +"const (\n" +"\tPlatformUnknown* = 0\n" +"\tPlatformLinux*\n" +"\tPlatformWindows*\n" +"\tPlatformMacOs*\n" +"\tPlatformWeb*\n" +")\n" "```\n" "\n" -"Creates a new gui spanning `r`, with style `s`.\n" "\n" "\n" -"## type LayoutFn\n" +"## Misc variables\n" "\n" "```\n" -"type LayoutFn* = fn(gui: ^Gui)\n" +"var (\n" +"\t// time in ms from start of the game\n" +"\ttime*: uint\n" +"\t// length of the last frame in ms\n" +"\tdelta*: int\n" +"\t// platform tophat is running on\n" +"\tplatform*: Platform\n" +")\n" "```\n" "\n" -"The layout function calls different element or container methods to create\n" -"the user interface itself. It is called in the `eval` and `draw`.\n" "\n" "\n" -"## fn BoxStyle.draw\n" +"", +"## \n" "\n" "```\n" -"fn (this: ^BoxStyle) draw*(r: rect.Rect) {\n" "```\n" "\n" -"Draws a rectangle using a BoxStyle\n" +"A module for importless communication between modules. A signal is a set of\n" +"callbacks. You can use signals directly in your own structs if you want\n" +"them to be instance specific, of you can use global signals which are\n" +"adressed by a string name.\n" "\n" "\n" -"## fn Gui.pushStyle\n" +"## type Callback\n" "\n" "```\n" -"fn (this: ^Gui) pushStyle*(s: Style) {\n" +"type Callback* = fn(args: []any)\n" "```\n" "\n" -"Pushes a style onto the style stack.\n" +"`args` is a list of arguments passed to the `emit` method.\n" "\n" "\n" -"## fn Gui.popStyle\n" +"## type Id\n" "\n" "```\n" -"fn (this: ^Gui) popStyle*() {\n" +"type Id* = uint\n" "```\n" "\n" -"Pops a style from the style stack.\n" "\n" "\n" -"## fn Gui.getStyle\n" +"## type Signal\n" "\n" "```\n" -"fn (this: ^Gui) getStyle*(): ^Style {\n" +"type Signal* = map[Id]Callback\n" "```\n" "\n" -"Returns a pointer to the style atop the style stack.\n" "\n" "\n" -"## fn Gui.getContainer\n" +"## fn mk\n" "\n" "```\n" -"fn (this: ^Gui) getContainer*(): Container {\n" +"fn mk*(): Signal {\n" "```\n" "\n" -"Returns the container atop the container stack.\n" +"`Signal` constructor\n" "\n" "\n" -"## fn Gui.pushRect\n" +"## fn Signal.register\n" "\n" "```\n" -"fn (this: ^Gui) pushRect*(r: rect.Rect): rect.Rect {\n" +"fn (this: ^Signal) register*(callback: Callback): Id {\n" "```\n" "\n" -"Shortcut to `this.getContainer().pushRect(r)`\n" +"Registers a callback to a signal and returns the callback id.\n" "\n" "\n" -"## fn Gui.getDims\n" +"## fn Signal.remove\n" "\n" "```\n" -"fn (this: ^Gui) getDims*(): rect.Rect {\n" +"fn (this: ^Signal) remove*(id: Id) {\n" "```\n" "\n" -"Shortcut to `this.getContainer().getDims(r)`\n" +"Removes a callback by id.\n" "\n" "\n" -"## fn Gui.dupStyle\n" +"## fn Signal.emit\n" "\n" "```\n" -"fn (this: ^Gui) dupStyle*() {\n" +"fn (this: ^Signal) emit*(args: ..any) {\n" "```\n" "\n" -"Duplicates the current style.\n" +"Emits a signal.\n" "\n" "\n" -"## fn Gui.pushContainer\n" +"## fn Signal.clear\n" "\n" "```\n" -"fn (this: ^Gui) pushContainer*(c: Container) {\n" +"fn (this: ^Signal) clear*() {\n" "```\n" "\n" -"Pushes a container onto the container stack.\n" +"Removes all signal handlers.\n" "\n" "\n" -"## fn Gui.popContainer\n" +"## fn register\n" "\n" "```\n" -"fn (this: ^Gui) popContainer*() {\n" +"fn register*(name: str, callback: Callback): Id {\n" "```\n" "\n" -"Pops a container from the container stack.\n" +"Registers a callback to a global signal. There is no need to explicitly\n" +"create global signals. Returns id of the added callback\n" "\n" "\n" -"## fn Gui.eval\n" +"## fn remove\n" "\n" "```\n" -"fn (this: ^Gui) eval*(layout: LayoutFn) {\n" +"fn remove*(name: str, id: Id) {\n" "```\n" "\n" -"Runs the evaluation phase on `layout`.\n" +"Removes a callback from a global signal by id.\n" "\n" "\n" -"## fn Gui.draw\n" +"## fn remove\n" "\n" "```\n" -"fn (this: ^Gui) draw*(layout: LayoutFn) {\n" +"fn clear*(name: str) {\n" "```\n" "\n" -"Runs the draw phase on `layout`.\n" +"Removes all signal handlers from a global signal.\n" "\n" "\n" -"## enum BoxGrow\n" +"## fn emit\n" "\n" "```\n" -"type BoxGrow* = uint\n" -"const (\n" -"\t// Increments by an amount set by the user.\n" -"\tBoxGrowDimension* = BoxGrow(0)\n" -"\t// Divides the container into `n` equal parts.\n" -"\tBoxGrowSubdivision* = BoxGrow(1)\n" -")\n" +"fn emit*(name: str, args: ..any) {\n" "```\n" "\n" -"The different types of \"growing\" the box can do.\n" +"Calls all callbacks associated with the passed global signal name.\n" "\n" "\n" -"## enum BoxDirection\n" +"", +"## struct Atlas\n" "\n" "```\n" -"type BoxDirection* = uint\n" -"const (\n" -"\tBoxDirectionDown* = BoxDirection(0)\n" -"\tBoxDirectionRight* = BoxDirection(1)\n" -"\tBoxDirectionUp* = BoxDirection(2)\n" -"\tBoxDirectionLeft* = BoxDirection(3)\n" -")\n" +"type Atlas* = struct {\n" +"\ti: image.Image // source image\n" +"\tcs: th.Vf2 // size of a cell in pixels\n" +"\tdm: th.Vf2 // amount of cells in image\n" +"}\n" "```\n" "\n" -"Direction in which the box will grow.\n" +"Atlas is an image containing tiles in a square grid.\n" "\n" "\n" -"## struct BoxConfig\n" +"## fn mk\n" "\n" "```\n" -"type BoxConfig* = struct {\n" -"\t// dimension to grow by if `BoxGrowDimension` is used\n" -"\tdimension: th.fu\n" -"\t// number of subdivisions if `BoxGrowSubdivisions` is used\n" -"\tsubdivisions: uint\n" -"\t// the grow type\n" -"\tgrowType: BoxGrow\n" -"\t// the grow direction\n" -"\tdir: BoxDirection\n" -"\t// rect passed to the current container\n" -"\trect: rect.Rect\n" -"\t// padding inserted after each element\n" -"\tpadding: th.fu\n" -"}\n" +"fn mk*(i: image.Image, dm: th.Vf2): Atlas {\n" "```\n" "\n" -"Configuration of the `Box` container.\n" +"i: source image\n" +"dm: amount of cells\n" "\n" "\n" -"## struct Box\n" +"## fn Atlas.coords\n" "\n" "```\n" -"type Box* = struct {\n" -"\tgrow: th.fu\n" -"\tdm: rect.Rect\n" -"\tcfg: BoxConfig\n" -"}\n" +"fn (a: ^Atlas) coords*(n: int): th.Vf2 {\n" "```\n" "\n" -"`Box` is the main layout. It puts the elements next to each other,\n" -"according to the config.\n" -"\n" -"If the dimensions of the rect passed to `pushRect` are non zero, they will\n" -"be kept. Position is always forced.\n" +"returns the coordinates of the nth tile\n" "\n" "\n" -"## fn Gui.box\n" +"## fn Atlas.cropSource\n" "\n" "```\n" -"fn (gui: ^Gui) box*(cfg: BoxConfig = {\n" -"\tdimension: 30,\n" -"\tgrowType: BoxGrowDimension,\n" -"\tdir: BoxDirectionDown }) {\n" +"fn (a: ^Atlas) cropSource*(at: th.Vf2) {\n" "```\n" "\n" -"Adds the `Box` container to the gui.\n" +"Crops the sourse image to only show a wanted tile\n" "\n" "\n" -"## struct StackConfig\n" +"## fn Atlas.draw\n" "\n" "```\n" -"type StackConfig* = struct {\n" -"\trect: rect.Rect\n" -"\tpadding: th.fu\n" -"}\n" +"fn (a: ^Atlas) draw*(at: th.Vf2, t: th.Transform) {\n" "```\n" "\n" -"Configuration for the `Stack` container.\n" +"Draws the tile at `at`\n" "\n" "\n" -"## struct Stack\n" +"", +"## opaque Shader\n" "\n" "```\n" -"type Stack* = struct {\n" -"\tdm: rect.Rect\n" -"\tcfg: StackConfig\n" -"}\n" +"type Shader* = struct {\n" "```\n" "\n" -"The stack container puts elements on top of each other.\n" -"If a property of the rect passed to `pushRect` is zero, it will be changed\n" -"to an equivalent property of the containers\' dimensions (minus the padding),\n" -"else it will stay the same. This means stack can be used either to put\n" -"multiple elements/containers on top of each other, or for absolutely\n" -"positioned elements.\n" -"\n" +"Shader allows you to define your own vertex and fragment GLSL shaders. This\n" +"is a low-level feature, so it\'s very easy to mess up.\n" "\n" -"## fn Gui.stack\n" +"In tophat, instead of a main function, shaders provide th_vertex and\n" +"th_fragment. The signature of th_vertex is:\n" "\n" "```\n" -"fn (gui: ^Gui) stack*(cfg: StackConfig = {}) {\n" +"vec2 th_vertex(vec2 vert);\n" "```\n" "\n" -"Adds the `Stack` container to the gui.\n" -"\n" +"where vert is the position of the vertex taken from the vertex buffer.\n" +"The output is the vertex shader output.\n" "\n" -"## struct ScrollAreaConfig\n" +"As for fragment shaders, there are two types of them. One for canvas\n" +"and one for images. In canvas shaders, the fragment function is very simple:\n" "\n" "```\n" -"type ScrollAreaConfig* = struct {\n" -"\trect: rect.Rect\n" -"\t// scroll speed. Default is 1\n" -"\tspeed: real32\n" -"\t// if true, scrolling will be horizontal\n" -"\thorizontal: bool\n" -"}\n" +"vec4 th_fragment(vec4 color);\n" "```\n" "\n" -"Configuration for the scroll area.\n" +"Image fragment function looks like this:\n" "\n" +"```\n" +"vec4 th_fragment(sampler2D tex, vec2 coord);\n" +"```\n" "\n" -"## struct ScrollArea\n" +"where tex is the texture and coord are the texture coordinates. Be aware to\n" +"swap the output of the `texture2D` function. Example:\n" "\n" "```\n" -"type ScrollArea* = struct {\n" -"\tdm: rect.Rect\n" -"\tcfg: ScrollAreaConfig\n" -"\tscroll: ^real32\n" -"\tmaxScroll: real32\n" -"}\n" +"texture2D(tex, coord).abgr\n" "```\n" "\n" -"Scroll area is a container which allows the user to scroll. It acts as a\n" -"stack container, but all the elements are shifted by the scroll.\n" -"\n" "\n" -"## fn Gui.scrollArea\n" +"## Default shader constants\n" "\n" "```\n" -"fn (gui: ^Gui) scrollArea*(scroll: ^real32, maxScroll: real32, cfg: ScrollAreaConfig = {}) {\n" +"const (\n" +"\tdefaultImageShader* = Shader{1}\n" +"\tdefaultCanvasShader* = Shader{2}\n" +")\n" "```\n" "\n" -"Pushes a scroll area. `scroll` is both input and output value. Both `scroll`\n" -"and `maxScroll` are in pixels.\n" "\n" "\n" -"## struct ButtonConfig\n" +"## struct Uniform\n" "\n" "```\n" -"type ButtonConfig* = struct {\n" -"\trect: rect.Rect\n" +"type Uniform* = struct {\n" +"\ts: Shader\n" +"\tl: uint\n" "}\n" "```\n" "\n" -"Configuration for the button.\n" +"Represents a GLSL uniform.\n" "\n" "\n" -"## fn Gui.button\n" +"## fn mkCanvas\n" "\n" "```\n" -"fn (gui: ^Gui) button*(cfg: ButtonConfig = {}): bool {\n" +"fn mkCanvas*(vertex, fragment: str): Shader {\n" "```\n" "\n" -"Adds a button to the gui. The button acts like a `Stack` container, but it\n" -"is drawn using the pos/nexBox styles and handles clicks. If the button is\n" -"pressed and the gui is in the eval phase, the return value will be true.\n" +"Compiles a canvas shader from source. If there is a compilation error, it\n" +"will print something to the console.\n" "\n" "\n" -"## struct LabelConfig\n" +"## fn mkImage\n" "\n" "```\n" -"type LabelConfig* = struct {\n" -"\t// centers the label along the X axis, enables `stretchX`\n" -"\tcenterX: bool\n" -"\t// centers the label along the Y axis, enables `stretchY`\n" -"\tcenterY: bool\n" -"\t// if false, the rect passed to `pushRect` will have the width of\n" -"\t// the text, else it will be 0\n" -"\tstretchX: bool\n" -"\t// if false, the rect passed to `pushRect` will have the height of\n" -"\t// the text, else it will be 0\n" -"\tstretchY: bool\n" -"\t// forces the rectangle the label will use\n" -"\trect: rect.Rect\n" -"}\n" +"fn mkImage*(vertex, fragment: str): Shader {\n" "```\n" "\n" +"Compiles an image shader from source. If there is a compilation error, it\n" +"will print something to the console.\n" "\n" "\n" -"## fn Gui.label\n" +"## fn Shader.pickForCanvas\n" "\n" "```\n" -"fn (gui: ^Gui) label*(text: str, cfg: LabelConfig = {\n" +"fn (s: ^Shader) pickForCanvas*() {\n" "```\n" "\n" -"Draws a label using the current font style.\n" +"Picks the shader to be used for canvas drawing. Flushes the canvas batch.\n" "\n" "\n" -"## fn Gui.qbutton\n" +"## fn Shader.pickForImage\n" "\n" "```\n" -"fn (gui: ^Gui) qbutton*(text: str, cfg: ButtonConfig = {}): bool {\n" +"fn (s: ^Shader) pickForImage*() {\n" "```\n" "\n" -"Adds a button with a label to gui.\n" +"Picks the shader to be used for image drawing. Flushes the image batch.\n" "\n" "\n" -"## struct TextBoxConfig\n" +"## fn Shader.getUniformLocation\n" "\n" "```\n" -"type TextBoxConfig* = struct {\n" -"\t// force the rect of the text box\n" -"\trect: rect.Rect\n" -"}\n" +"fn (s: ^Shader) getUniformLocation*(name: str): Uniform {\n" "```\n" "\n" +"Retunrs a uniform by name.\n" "\n" "\n" -"## struct TextBox\n" +"## fn Uniform.setInt\n" "\n" "```\n" -"type TextBox* = struct {\n" -"\t// the content of the textbox\n" -"\tbuffer: str\n" -"\t// index of the cursor\n" -"\tcursor: int\n" -"}\n" +"fn (u: ^Uniform) setInt*(value: int) {\n" "```\n" "\n" +"Sets a uniform to an int value. Flushes both batches.\n" "\n" "\n" -"## fn TextBox.clear\n" +"## fn Uniform.setVf2\n" "\n" "```\n" -"fn (this: ^TextBox) clear*() {\n" -"\tthis.buffer = \"\"\n" -"\tthis.cursor = 0\n" -"}\n" +"fn (u: ^Uniform) setVf2*(value: th.Vf2) {\n" "```\n" "\n" -"Clears the textbox\n" +"Sets a uniform to a vf2. Flushes both batches.\n" "\n" "\n" +"", "## \n" "\n" "```\n" -"\tgui.idx++\n" -"\n" -"\tr := gui.pushRect(cfg.rect)\n" +"```\n" "\n" -"\thover := gui.hover(r)\n" +"Color operations. Operate on RGBA uint32 values.\n" "\n" -"\tif gui.isEval {\n" -"\t\tif input.isJustPressed(input.mouse1) && hover {\n" -"\t\t\tgui.selection = gui.idx\n" -"\t\t}\n" "\n" -"\t\tif input.isJustPressed(input.mouse1) && !hover &&\n" -"\t\t\tgui.selection == gui.idx {\n" -"\t\t\t\tgui.selection = 0\n" -"\t\t}\n" -"\t\t\n" -"\t\tif input.isJustPressed(input.key_escape) && gui.selection == gui.idx {\n" -"\t\t\tgui.selection = 0\n" -"\t\t}\n" +"## fn hsv\n" "\n" -"\t\tif gui.selection != gui.idx {\n" -"\t\t\treturn\n" -"\t\t}\n" +"```\n" +"fn hsv*(h, s, v: th.fu, a: th.fu = 1.0): uint32 {\n" +"```\n" "\n" -"\t\tif input.isJustPressed(input.key_left) ||\n" -"\t\t\tinput.isPressedRepeat(input.key_left) {\n" -"\t\t\tif tb.cursor > 0 { tb.cursor-- }\n" -"\t\t}\n" +"Converts HSV values into RGBA uint32 color.\n" +"NOTE: Hue is between 0 and 1\n" "\n" -"\t\tif input.isJustPressed(input.key_right) ||\n" -"\t\t\tinput.isPressedRepeat(input.key_right) {\n" -"\t\t\tif tb.cursor < len(tb.buffer) { tb.cursor++ }\n" -"\t\t}\n" "\n" -"\t\tif input.isJustPressed(input.key_backspace) ||\n" -"\t\t\tinput.isPressedRepeat(input.key_backspace) {\n" +"## fn alpha\n" "\n" -"\t\t\tif tb.cursor > 0 {\n" -"\t\t\t\ttb.buffer = slice(tb.buffer, 0, tb.cursor - 1) +\n" -"\t\t\t\t\tslice(tb.buffer, tb.cursor)\n" -"\t\t\t\ttb.cursor--\n" -"\t\t\t}\n" -"\t\t}\n" +"```\n" +"fn alpha*(c: uint32, to: th.fu): uint32 {\n" +"```\n" "\n" -"\t\tv := true\n" +"Sets alpha of the color c to a value in to.\n" "\n" -"\t\tif input.isPressed(input.key_ctrl) && input.isJustPressedc(\'u\') {\n" -"\t\t\ttb.clear()\n" -"\t\t\tv = false\n" -"\t\t}\n" "\n" -"\t\ts := input.getStr()\n" -"\t\tfor i in s {\n" -"\t\t\tif int(s[i]) < int(\' \') || int(s[i]) == int(\'z\') + 1 {\n" -"\t\t\t\tv = false\n" -"\t\t\t}\n" -"\t\t}\n" -"\t\tif len(s) > 0 && v {\n" -"\t\t\ttb.buffer = slice(tb.buffer, 0, tb.cursor) + s +\n" -"\t\t\t\tslice(tb.buffer, tb.cursor)\n" -"\t\t\ttb.cursor += len(s)\n" -"\t\t}\n" +"## fn rgb\n" "\n" -"\t\treturn\n" -"\t}\n" +"```\n" +"fn rgb*(r, g, b: th.fu, a: th.fu = 1.0): uint32 {\n" +"```\n" "\n" +"Constructs RGBA uint32 from RGBA of reals.\n" "\n" -"\tstyle := gui.getStyle()\n" "\n" -"\tstyle.negBox.draw(r)\n" -"\tcanvas.beginScissorRect(r)\n" +"", +"## \n" "\n" -"\tdm := style.ft.measure(tb.buffer).mulf(style.ftScale)\n" +"```\n" +"```\n" "\n" -"\tp := th.Vf2{}\n" -"\tp.y = r.y + r.h/2 - dm.y/2\n" -"\tc := th.Vf2{r.x, p.y}\n" +"Builtin collision functions. The ic argument stores the collision position.\n" "\n" -"\tcdmx := style.ft.measure(slice(tb.buffer, 0, tb.cursor)).x * style.ftScale\n" -"\tif cdmx < r.w - 2 {\n" -"\t\tp.x = r.x + 1\n" -"\t\tc.x = p.x + cdmx\n" -"\t} else {\n" -"\t\tc.x = r.x + r.w - 1\n" -"\t\tp.x = c.x - cdmx\n" -"\t}\n" -"\t\n" -"\taW := style.ft.measure(\"A\").x * style.ftScale\n" "\n" -"\tstyle.ft.draw(tb.buffer, p, style.ftColor, style.ftScale)\n" -"\tif gui.selection == gui.idx {\n" -"\t\tcanvas.drawRect(style.ftColor, rect.mk(c.x, c.y, aW / 4, dm.y))\n" -"\t}\n" +"## fn lineToLine\n" "\n" -"\tcanvas.endScissor()\n" -"}\n" +"```\n" +"fn lineToLine*(b1, e1, b2, e2: th.Vf2, ic: ^th.Vf2): bool {\n" "```\n" "\n" +"Checks for a collision between 2 lines specified by their end points.\n" "\n" "\n" -"## \n" +"## fn vf2ToQuad\n" "\n" "```\n" +"fn vf2ToQuad*(p: th.Vf2, q: th.Quad, ic: ^th.Vf2): bool {\n" "```\n" "\n" +"Checks for a collision between a vf2 and a quad.\n" "\n" "\n" -"## \n" +"## fn lineToQuad\n" "\n" "```\n" +"fn lineToQuad*(b, e: th.Vf2, q: th.Quad, ic: ^th.Vf2): bool {\n" +"```\n" "\n" -"\tif cfg.centerX { cfg.stretchX = true }\n" -"\tif cfg.centerY { cfg.stretchY = true }\n" +"Check for a collision between a line and quad edges.\n" "\n" -"\tr := cfg.rect\n" -"\tdm := i.getDims().mul(cfg.scale)\n" -"\tif r.w == 0 { r.w = dm.x }\n" -"\tif r.h == 0 { r.h = dm.y }\n" "\n" -"\tif cfg.stretchX { r.w = 0 }\n" -"\tif cfg.stretchY { r.h = 0 }\n" +"## fn quadToQuad\n" "\n" -"\tr = gui.pushRect(r)\n" +"```\n" +"fn quadToQuad*(q1, q2: th.Quad, ic: ^th.Vf2): bool {\n" +"```\n" "\n" -"\tif gui.isEval { return }\n" +"Check for a collision between two quads.\n" "\n" -"\tx := r.x\n" -"\ty := r.y\n" -"\tif cfg.centerX {\n" -"\t\tx += (r.w - dm.x) / 2\n" -"\t}\n" "\n" -"\tif cfg.centerY {\n" -"\t\ty += (r.h - dm.y) / 2\n" -"\t}\n" +"## fn vf2ToRect\n" "\n" -"\ti.draw(th.Transform{\n" -"\t\tp: { x, y },\n" -"\t\ts: cfg.scale }, cfg.color)\n" -"}\n" +"```\n" +"fn vf2ToRect*(p: th.Vf2, r: rect.Rect): bool {\n" "```\n" "\n" +"Check for a collision between a vf2 and a rectangle.\n" "\n" "\n" -"## \n" +"## fn rectToRect\n" "\n" "```\n" +"fn rectToRect*(r1, r2: rect.Rect): bool {\n" "```\n" "\n" +"Check for a collision between two rects\n" "\n" "\n" "", -"## \n" +"## Placeholder images\n" "\n" "```\n" -"const (\n" -"\tnil* = 0\n" -"\twindows*\n" -"\tunix*\n" +"var (\n" +"\t// an image useful for testing\n" +"\ttest*: image.Image\n" +"\t// the image used for the app icon\n" +"\ticon*: image.Image\n" +"\t// Windows 95 style button, to be used with ninepatch (image.um) \n" +"\tbutton*: image.Image\n" ")\n" -"\n" -"var fileseparator*: char // platform specific file separator. linux => /, windows => \\\n" -"var os*: int // current os\n" "```\n" "\n" +"These images are included with tophat and don\'t have to be loaded.\n" "\n" "\n" -"## fn init\n" +"", +"## struct Mesh\n" "\n" "```\n" -"fn init() {\n" +"type Mesh* = struct {\n" +"\t// The mesh data.\n" +"\td: []bool\n" +"\t// The dimensions and position of the mesh, r.w == w * s\n" +"\tr: rect.Rect\n" +"\t// Width of the mesh. Used to adress the mesh data.\n" +"\tw: th.uu\n" +"\t// Scale of one cell (cell is a square)\n" +"\ts: th.fu\n" +"}\n" "```\n" "\n" -"Automatically initializes platform specific stuff\n" +"Mesh is a 2d array of bool cells. If a cell is true, the cell can be used\n" +"in a path. The mesh is located in a world using the `r` field. A cell can\n" +"have an arbitrary size as specified by `s`.\n" +"\n" +"The mesh can be edited using the `addQuad` method, but it should be trivial\n" +"to add your own, similar methods.\n" +"\n" +"Please use the `mk` constructor to construct a `Mesh`, unless you really\n" +"know what you\'re doing.\n" "\n" "\n" -"## fn dir\n" +"## fn mk\n" "\n" "```\n" -"fn dir*(inp: str): str {\n" +"fn mk*(r: rect.Rect, s: th.fu): Mesh {\n" "```\n" "\n" -"returns the directory in inp\n" +"Creates a new nav mesh.\n" +"`r`\n" +": the rectangle of the mask\n" +"\'s\'\n" +": the scale of the mask\n" "\n" "\n" -"## fn ext\n" +"## fn Mesh.addQuad\n" "\n" "```\n" -"fn ext*(inp: str): str {\n" +"fn (m: ^Mesh) addQuad*(q: th.Quad) {\n" "```\n" "\n" -"returns the extension of file inp. if there is no extension, or it is a diroctory, output is \"\"\n" +"Sets mask\'s fields overlapping `q` to `false`.\n" "\n" "\n" -"## fn fromslash\n" +"## fn Mesh.nav\n" "\n" "```\n" -"fn fromslash*(inp: str): str {\n" +"fn (m: ^Mesh) nav*(p1, p2: th.Vf2): []th.Vf2 {\n" "```\n" "\n" -"converts / to platform specific separator\n" +"Navigates between `p1` and `p2`. Returns the path as an array of `th.Vf2`s.\n" +"If it doesn\'t find any path, or one of the points is outside of the mask,\n" +"returns an empty array.\n" "\n" "\n" -"## fn toslash\n" +"## fn Mesh.draw\n" "\n" "```\n" -"fn toslash*(inp: str) : str {\n" -"\tif os == nil {\n" -"\t\tinit()\n" -"\t}\n" +"fn (m: ^Mesh) draw*(alpha: real32 = 1.0) {\n" +"```\n" "\n" -"\tif !chcont(inp, fileseparator) || fileseparator == \'/\' {\n" -"\t\treturn inp\n" -"\t}\n" +"Draws the mesh for debugging purposes.\n" "\n" -"\tb := []char(inp)\n" -"\tfor i:=0; i < len(inp); i++ {\n" -"\t\tif inp[i] == fileseparator {\n" -"\t\t\tb[i] = \'/\'\n" -"\t\t}\n" -"\t}\n" "\n" -"\treturn b\n" -"}\n" +"", +"## \n" +"\n" +"```\n" "```\n" "\n" -"converts platform specific separator to /\n" +"`ui.um` offers an immediate GUI library suitable both for simple game menus\n" +"and more complex applications. See the [tutorial](/tut/spritesheet.html)\n" +"for example usage.\n" "\n" "\n" -"## \n" +"## struct BoxStyle\n" "\n" "```\n" +"type BoxStyle* = struct {\n" +"\timg: image.Image\n" +"\touter, inner: rect.Rect\n" +"\tscale: th.fu\n" +"\tcolor: uint32\n" +"}\n" "```\n" "\n" +"`BoxStyle` describes how a box within the GUI is styled. In this case box\n" +"can be anything, ranging from a button to a container. By default the box\n" +"is drawn using the `image.Image.drawNinepatch` method. However if the image\n" +"is invalid, a rectangle with color `color` is drawn.\n" "\n" "\n" -"", -"## fn fmt\n" +"## interface Font\n" "\n" "```\n" -"fn fmt*(s: str, args: ..any): str {\n" +"type Font* = interface {\n" +"\tdraw(text: str, pos: th.Vf2, color: uint32, scale: th.fu = 1.0)\n" +"\tmeasure(test: str): th.Vf2\n" +"}\n" "```\n" "\n" -"\"{}\" in the string `s` will be subtituted for the arguments\n" +"This interface is used by all elements that draw text. A `font.Font`\n" +"implements this interface.\n" "\n" "\n" -"", -"## type File\n" +"## struct PixelFont\n" "\n" "```\n" -"type File* = struct { _: std.File }\n" +"type PixelFont* = struct { }\n" "```\n" "\n" -"Wrapper around `std.File`\n" +"This struct implement the `Font` interface using the `canvas.um` pixel font.\n" "\n" "\n" -"## fn open\n" +"## struct Style\n" "\n" "```\n" -"fn open*(path, mode: str): File {\n" +"type Style* = struct {\n" +"\t// current font\n" +"\tft: Font\n" +"\t// font scale\n" +"\tftScale: th.fu\n" +"\t// text color\n" +"\tftColor: uint32\n" +"\n" +"\t// Positive box - i. e. unpressed button\n" +"\tposBox: BoxStyle\n" +"\t// Negative box - i. e. pressed button, text box\n" +"\tnegBox: BoxStyle\n" +"\t// Used to draw containers\n" +"\tcontainerBox: BoxStyle\n" +"}\n" "```\n" "\n" -"Opens a file\n" +"`Style` is used as a global state for styling the GUI.\n" "\n" "\n" -"## fn File.close\n" +"## interface Container\n" "\n" "```\n" -"fn (f: ^File) close*() {\n" +"type Container* = interface {\n" +"\t// This adds a rectangle to the container, and returns the rectangle\n" +"\t// which was actually added (the container can modify the rectangle).\n" +"\t// See individual containers for further documentation.\n" +"\tpushRect(r: rect.Rect): rect.Rect\n" +"\tgetDims(): rect.Rect\n" +"}\n" "```\n" "\n" -"Closes a file\n" +"Containers are used to layout elements or other containers.\n" "\n" "\n" -"## fn File.readall\n" +"## struct Gui\n" "\n" "```\n" -"fn (f: ^File) readall*(): str {\n" +"type Gui* = struct {\n" +"\t// user context passed to layout functions\n" +"\tctx: any\n" +"\n" +"\t// the index of the current selection. TODO implement properly\n" +"\tselection: int\n" +"\t// true, if the layout is being evaluated, not drawn\n" +"\tisEval: bool\n" +"\t// contains more unexported fields\n" "```\n" "\n" -"Reads all contents of a file into a string\n" +"This is the main struct of any UI. Styles and containers are in a stack.\n" "\n" "\n" -"## fn File.write\n" +"## fn mk\n" "\n" "```\n" -"fn (f: ^File) write*(text: str) {\n" +"fn mk*(r: rect.Rect, s: Style): Gui\n" "```\n" "\n" -"Writes text to a file\n" +"Creates a new gui spanning `r`, with style `s`.\n" "\n" "\n" -"## fn readall\n" +"## type LayoutFn\n" "\n" "```\n" -"fn readall*(path: str): str {\n" +"type LayoutFn* = fn(gui: ^Gui)\n" "```\n" "\n" -"Reads all text from a file.\n" +"The layout function calls different element or container methods to create\n" +"the user interface itself. It is called in the `eval` and `draw`.\n" "\n" "\n" -"", -"## fn parse\n" +"## fn BoxStyle.draw\n" "\n" "```\n" -"fn parse*(inp: str): any {\n" +"fn (this: ^BoxStyle) draw*(r: rect.Rect) {\n" "```\n" "\n" -"parses json provided as an input and returns either map[str]any or []any\n" +"Draws a rectangle using a BoxStyle\n" "\n" "\n" -"", -"## type Encoder\n" +"## fn Gui.pushStyle\n" "\n" "```\n" -"type Encoder* = struct {\n" -"\t// Contains private fields\n" +"fn (this: ^Gui) pushStyle*(s: Style) {\n" "```\n" "\n" +"Pushes a style onto the style stack.\n" "\n" "\n" -"## fn mk\n" +"## fn Gui.popStyle\n" "\n" "```\n" -"fn mk*(pretty: bool = true): Encoder {\n" +"fn (this: ^Gui) popStyle*() {\n" "```\n" "\n" -"Creates an encoder.\n" +"Pops a style from the style stack.\n" "\n" "\n" -"## fn Encoder.putKey\n" +"## fn Gui.getStyle\n" "\n" "```\n" -"fn (this: ^Encoder) putKey*(key: str) {\n" +"fn (this: ^Gui) getStyle*(): ^Style {\n" "```\n" "\n" +"Returns a pointer to the style atop the style stack.\n" "\n" "\n" -"## fn Encoder.putVal\n" +"## fn Gui.getContainer\n" "\n" "```\n" -"fn (this: ^Encoder) putVal*(a: any) {\n" +"fn (this: ^Gui) getContainer*(): Container {\n" "```\n" "\n" +"Returns the container atop the container stack.\n" "\n" "\n" -"## fn Encoder.startObject\n" +"## fn Gui.pushRect\n" "\n" "```\n" -"fn (this: ^Encoder) startObject*() {\n" +"fn (this: ^Gui) pushRect*(r: rect.Rect): rect.Rect {\n" "```\n" "\n" +"Shortcut to `this.getContainer().pushRect(r)`\n" "\n" "\n" -"## fn Encoder.endObject\n" +"## fn Gui.getDims\n" "\n" "```\n" -"fn (this: ^Encoder) endObject*() {\n" +"fn (this: ^Gui) getDims*(): rect.Rect {\n" "```\n" "\n" +"Shortcut to `this.getContainer().getDims(r)`\n" "\n" "\n" -"## fn Encoder.startArray\n" +"## fn Gui.dupStyle\n" "\n" "```\n" -"fn (this: ^Encoder) startArray*() {\n" +"fn (this: ^Gui) dupStyle*() {\n" "```\n" "\n" +"Duplicates the current style.\n" "\n" "\n" -"## fn Encoder.endArray\n" +"## fn Gui.pushContainer\n" "\n" "```\n" -"fn (this: ^Encoder) endArray*() {\n" +"fn (this: ^Gui) pushContainer*(c: Container) {\n" "```\n" "\n" +"Pushes a container onto the container stack.\n" "\n" "\n" -"## fn Encoder.toStr\n" +"## fn Gui.popContainer\n" "\n" "```\n" -"fn (this: ^Encoder) toStr*(): str {\n" +"fn (this: ^Gui) popContainer*() {\n" "```\n" "\n" +"Pops a container from the container stack.\n" "\n" "\n" -"", -"## \n" +"## fn Gui.eval\n" "\n" "```\n" +"fn (this: ^Gui) eval*(layout: LayoutFn) {\n" "```\n" "\n" -"A logging library.\n" +"Runs the evaluation phase on `layout`.\n" +"\n" "\n" -"Every log has a tag. The tag is used to distinguish between different parts\n" -"of the program. Every tag can have specific log level, which is different\n" -"from the global log level. This allows you to enable the debug logs just for\n" -"the code you are debugging.\n" +"## fn Gui.draw\n" +"\n" +"```\n" +"fn (this: ^Gui) draw*(layout: LayoutFn) {\n" +"```\n" "\n" -"This library offers following loggin backends:\n" -"* `ConsoleBackend` - log to `stdout`\n" -"* `FileBackend` - log to file\n" +"Runs the draw phase on `layout`.\n" "\n" "\n" -"## interface Backend\n" +"## enum BoxGrow\n" "\n" "```\n" -"type Backend* = interface {\n" +"type BoxGrow* = uint\n" +"const (\n" +"\t// Increments by an amount set by the user.\n" +"\tBoxGrowDimension* = BoxGrow(0)\n" +"\t// Divides the container into `n` equal parts.\n" +"\tBoxGrowSubdivision* = BoxGrow(1)\n" +")\n" "```\n" "\n" -"Defines a logging backend.\n" +"The different types of \"growing\" the box can do.\n" "\n" "\n" -"## enum LogLevel\n" +"## enum BoxDirection\n" "\n" "```\n" -"type LogLevel* = int\n" +"type BoxDirection* = uint\n" "const (\n" -"\tLogLevelDbg* = LogLevel(0)\n" -"\tLogLevelInf* = LogLevel(1)\n" -"\tLogLevelWrn* = LogLevel(2)\n" -"\tLogLevelSus* = LogLevel(3)\n" -"\tLogLevelErr* = LogLevel(4)\n" +"\tBoxDirectionDown* = BoxDirection(0)\n" +"\tBoxDirectionRight* = BoxDirection(1)\n" +"\tBoxDirectionUp* = BoxDirection(2)\n" +"\tBoxDirectionLeft* = BoxDirection(3)\n" ")\n" "```\n" "\n" +"Direction in which the box will grow.\n" "\n" "\n" -"## struct ConsoleBackend\n" +"## struct BoxConfig\n" "\n" "```\n" -"type ConsoleBackend* = struct { }\n" +"type BoxConfig* = struct {\n" +"\t// dimension to grow by if `BoxGrowDimension` is used\n" +"\tdimension: th.fu\n" +"\t// number of subdivisions if `BoxGrowSubdivisions` is used\n" +"\tsubdivisions: uint\n" +"\t// the grow type\n" +"\tgrowType: BoxGrow\n" +"\t// the grow direction\n" +"\tdir: BoxDirection\n" +"\t// rect passed to the current container\n" +"\trect: rect.Rect\n" +"\t// padding inserted after each element\n" +"\tpadding: th.fu\n" +"}\n" "```\n" "\n" -"Backend which logs to the console. This is the default backend.\n" +"Configuration of the `Box` container.\n" "\n" "\n" -"## struct FileBackend\n" +"## struct Box\n" "\n" "```\n" -"type FileBackend* = struct {\n" -"\t// Contains private fields\n" +"type Box* = struct {\n" +"\tgrow: th.fu\n" +"\tdm: rect.Rect\n" +"\tcfg: BoxConfig\n" +"}\n" "```\n" "\n" -"Backend which logs to a file. Created using `mkFileBackend`.\n" +"`Box` is the main layout. It puts the elements next to each other,\n" +"according to the config.\n" +"\n" +"If the dimensions of the rect passed to `pushRect` are non zero, they will\n" +"be kept. Position is always forced.\n" "\n" "\n" -"## fn FileBackend.close\n" +"## fn Gui.box\n" "\n" "```\n" -"fn (this: ^FileBackend) close*() {\n" +"fn (gui: ^Gui) box*(cfg: BoxConfig = {\n" +"\tdimension: 30,\n" +"\tgrowType: BoxGrowDimension,\n" +"\tdir: BoxDirectionDown }) {\n" "```\n" "\n" -"Closes the internal file.\n" +"Adds the `Box` container to the gui.\n" "\n" "\n" -"## fn mkFileBackend\n" +"## struct StackConfig\n" "\n" "```\n" -"fn mkFileBackend*(path: str, rewrite: bool = false): FileBackend {\n" +"type StackConfig* = struct {\n" +"\trect: rect.Rect\n" +"\tpadding: th.fu\n" +"}\n" "```\n" "\n" -"Creates a `FileBackend`. If `rewrite` is false, the file will be appended.\n" +"Configuration for the `Stack` container.\n" "\n" "\n" -"## fn init\n" +"## struct Stack\n" "\n" "```\n" -"fn init*() {\n" +"type Stack* = struct {\n" +"\tdm: rect.Rect\n" +"\tcfg: StackConfig\n" +"}\n" "```\n" "\n" -"Initialize `logs.um`. You need to call this before using any other functions.\n" +"The stack container puts elements on top of each other.\n" +"If a property of the rect passed to `pushRect` is zero, it will be changed\n" +"to an equivalent property of the containers\' dimensions (minus the padding),\n" +"else it will stay the same. This means stack can be used either to put\n" +"multiple elements/containers on top of each other, or for absolutely\n" +"positioned elements.\n" "\n" "\n" -"## fn setBackend\n" +"## fn Gui.stack\n" "\n" "```\n" -"fn setBackend*(b: Backend) {\n" +"fn (gui: ^Gui) stack*(cfg: StackConfig = {}) {\n" "```\n" "\n" -"Set the logging backend.\n" +"Adds the `Stack` container to the gui.\n" "\n" "\n" -"## fn setGlobalLogLevel\n" +"## struct ScrollAreaConfig\n" "\n" "```\n" -"fn setGlobalLogLevel*(level: LogLevel) {\n" +"type ScrollAreaConfig* = struct {\n" +"\trect: rect.Rect\n" +"\t// scroll speed. Default is 1\n" +"\tspeed: real32\n" +"\t// if true, scrolling will be horizontal\n" +"\thorizontal: bool\n" +"}\n" "```\n" "\n" -"Set the global log level.\n" +"Configuration for the scroll area.\n" "\n" "\n" -"## fn setTagLogLevel\n" +"## struct ScrollArea\n" "\n" "```\n" -"fn setTagLogLevel*(tag: str, level: LogLevel) {\n" +"type ScrollArea* = struct {\n" +"\tdm: rect.Rect\n" +"\tcfg: ScrollAreaConfig\n" +"\tscroll: ^real32\n" +"\tmaxScroll: real32\n" +"}\n" "```\n" "\n" -"Set the tag specific log level.\n" +"Scroll area is a container which allows the user to scroll. It acts as a\n" +"stack container, but all the elements are shifted by the scroll.\n" "\n" "\n" -"## fn dbg\n" +"## fn Gui.scrollArea\n" "\n" "```\n" -"fn dbg*(tag: str, fmt: str, args: ..any) {\n" +"fn (gui: ^Gui) scrollArea*(scroll: ^real32, maxScroll: real32, cfg: ScrollAreaConfig = {}) {\n" "```\n" "\n" +"Pushes a scroll area. `scroll` is both input and output value. Both `scroll`\n" +"and `maxScroll` are in pixels.\n" "\n" "\n" -"## fn inf\n" +"## struct ButtonConfig\n" "\n" "```\n" -"fn inf*(tag: str, fmt: str, args: ..any) {\n" +"type ButtonConfig* = struct {\n" +"\trect: rect.Rect\n" +"}\n" "```\n" "\n" +"Configuration for the button.\n" "\n" "\n" -"## fn wrn\n" +"## fn Gui.button\n" "\n" "```\n" -"fn wrn*(tag: str, fmt: str, args: ..any) {\n" +"fn (gui: ^Gui) button*(cfg: ButtonConfig = {}): bool {\n" "```\n" "\n" +"Adds a button to the gui. The button acts like a `Stack` container, but it\n" +"is drawn using the pos/nexBox styles and handles clicks. If the button is\n" +"pressed and the gui is in the eval phase, the return value will be true.\n" "\n" "\n" -"## fn sus\n" +"## struct LabelConfig\n" "\n" "```\n" -"fn sus*(tag: str, fmt: str, args: ..any) {\n" +"type LabelConfig* = struct {\n" +"\t// centers the label along the X axis, enables `stretchX`\n" +"\tcenterX: bool\n" +"\t// centers the label along the Y axis, enables `stretchY`\n" +"\tcenterY: bool\n" +"\t// if false, the rect passed to `pushRect` will have the width of\n" +"\t// the text, else it will be 0\n" +"\tstretchX: bool\n" +"\t// if false, the rect passed to `pushRect` will have the height of\n" +"\t// the text, else it will be 0\n" +"\tstretchY: bool\n" +"\t// forces the rectangle the label will use\n" +"\trect: rect.Rect\n" +"}\n" "```\n" "\n" "\n" "\n" -"## fn err\n" +"## fn Gui.label\n" "\n" "```\n" -"fn err*(tag: str, fmt: str, args: ..any) {\n" +"fn (gui: ^Gui) label*(text: str, cfg: LabelConfig = {\n" "```\n" "\n" +"Draws a label using the current font style.\n" "\n" "\n" -"", -"## \n" +"## fn Gui.qbutton\n" "\n" "```\n" -"type Arr* = interface {\n" -"\tlen(): int\n" -"\tswap(i, j: int)\n" -"}\n" -"\n" -"type CmpFn* = fn(a: Arr, i, j: int): bool\n" +"fn (gui: ^Gui) qbutton*(text: str, cfg: ButtonConfig = {}): bool {\n" "```\n" "\n" +"Adds a button with a label to gui.\n" "\n" "\n" -"## fn sort\n" +"## struct TextBoxConfig\n" "\n" "```\n" -"fn sort*(a: Arr, f: CmpFn) {\n" +"type TextBoxConfig* = struct {\n" +"\t// force the rect of the text box\n" +"\trect: rect.Rect\n" +"}\n" "```\n" "\n" "\n" "\n" -"## \n" +"## struct TextBox\n" "\n" "```\n" -"type IntArr* = []int\n" -"\n" -"fn (this: ^IntArr) len(): int {\n" -"\treturn len(this^)\n" +"type TextBox* = struct {\n" +"\t// the content of the textbox\n" +"\tbuffer: str\n" +"\t// index of the cursor\n" +"\tcursor: int\n" "}\n" +"```\n" "\n" -"fn (this: ^IntArr) swap(i, j: int) {\n" -"\tt := this[i]\n" -"\tthis[i] = this[j]\n" -"\tthis[j] = t\n" -"}\n" "\n" -"fn sortInt*(a: []int) {\n" -"\tsort(IntArr(a), CmpFn{\n" -"\t\tia := []int(a)\n" -"\t\treturn ia[i] < ia[j]\n" -"\t})\n" -"}\n" "\n" -"fn main() {\n" -"\tnums := []int{ 3, 1, 4, 1, 5, 9, 2 }\n" -"\tprintf(\"nums: %s\\n\", repr(nums))\n" -"\tsortInt(nums)\n" -"\tprintf(\"nums: %s\\n\", repr(nums))\n" +"## fn TextBox.clear\n" +"\n" +"```\n" +"fn (this: ^TextBox) clear*() {\n" +"\tthis.buffer = \"\"\n" +"\tthis.cursor = 0\n" "}\n" "```\n" "\n" +"Clears the textbox\n" "\n" "\n" -"", -"## fn contains\n" +"## \n" "\n" "```\n" -"fn contains*(inp, check: str): bool {\n" -"```\n" +"\tgui.idx++\n" "\n" -"returns true, if string is contained in another string\n" +"\tr := gui.pushRect(cfg.rect)\n" "\n" +"\thover := gui.hover(r)\n" "\n" -"## fn join\n" +"\tif gui.isEval {\n" +"\t\tif input.isJustPressed(input.mouse1) && hover {\n" +"\t\t\tgui.selection = gui.idx\n" +"\t\t}\n" "\n" -"```\n" -"fn join*(inp: []str, joiner: str): str {\n" -"```\n" +"\t\tif input.isJustPressed(input.mouse1) && !hover &&\n" +"\t\t\tgui.selection == gui.idx {\n" +"\t\t\t\tgui.selection = 0\n" +"\t\t}\n" +"\t\t\n" +"\t\tif input.isJustPressed(input.key_escape) && gui.selection == gui.idx {\n" +"\t\t\tgui.selection = 0\n" +"\t\t}\n" "\n" -"joins an array of string into one and adds a joiner between them\n" +"\t\tif gui.selection != gui.idx {\n" +"\t\t\treturn\n" +"\t\t}\n" "\n" +"\t\tif input.isJustPressed(input.key_left) ||\n" +"\t\t\tinput.isPressedRepeat(input.key_left) {\n" +"\t\t\tif tb.cursor > 0 { tb.cursor-- }\n" +"\t\t}\n" "\n" -"## fn has_prefix\n" +"\t\tif input.isJustPressed(input.key_right) ||\n" +"\t\t\tinput.isPressedRepeat(input.key_right) {\n" +"\t\t\tif tb.cursor < len(tb.buffer) { tb.cursor++ }\n" +"\t\t}\n" "\n" -"```\n" -"fn has_prefix*(s, p: str): bool {\n" -"```\n" +"\t\tif input.isJustPressed(input.key_backspace) ||\n" +"\t\t\tinput.isPressedRepeat(input.key_backspace) {\n" "\n" -"Returns true if `s` starts with `p`\n" +"\t\t\tif tb.cursor > 0 {\n" +"\t\t\t\ttb.buffer = slice(tb.buffer, 0, tb.cursor - 1) +\n" +"\t\t\t\t\tslice(tb.buffer, tb.cursor)\n" +"\t\t\t\ttb.cursor--\n" +"\t\t\t}\n" +"\t\t}\n" "\n" +"\t\tv := true\n" "\n" -"## fn split\n" +"\t\tif input.isPressed(input.key_ctrl) && input.isJustPressedc(\'u\') {\n" +"\t\t\ttb.clear()\n" +"\t\t\tv = false\n" +"\t\t}\n" "\n" -"```\n" -"fn split*(s, p: str): []str {\n" -"```\n" +"\t\ts := input.getStr()\n" +"\t\tfor i in s {\n" +"\t\t\tif int(s[i]) < int(\' \') || int(s[i]) == int(\'z\') + 1 {\n" +"\t\t\t\tv = false\n" +"\t\t\t}\n" +"\t\t}\n" +"\t\tif len(s) > 0 && v {\n" +"\t\t\ttb.buffer = slice(tb.buffer, 0, tb.cursor) + s +\n" +"\t\t\t\tslice(tb.buffer, tb.cursor)\n" +"\t\t\ttb.cursor += len(s)\n" +"\t\t}\n" "\n" -"Splits the string by a pattern\n" +"\t\treturn\n" +"\t}\n" "\n" "\n" -"## fn replace\n" +"\tstyle := gui.getStyle()\n" "\n" -"```\n" -"fn replace*(inp, pattern, replacer: str): str {\n" -"```\n" +"\tstyle.negBox.draw(r)\n" +"\tcanvas.beginScissorRect(r)\n" "\n" -"replaces an pattern with a string\n" +"\tdm := style.ft.measure(tb.buffer).mulf(style.ftScale)\n" "\n" +"\tp := th.Vf2{}\n" +"\tp.y = r.y + r.h/2 - dm.y/2\n" +"\tc := th.Vf2{r.x, p.y}\n" "\n" -"## fn toupper\n" +"\tcdmx := style.ft.measure(slice(tb.buffer, 0, tb.cursor)).x * style.ftScale\n" +"\tif cdmx < r.w - 2 {\n" +"\t\tp.x = r.x + 1\n" +"\t\tc.x = p.x + cdmx\n" +"\t} else {\n" +"\t\tc.x = r.x + r.w - 1\n" +"\t\tp.x = c.x - cdmx\n" +"\t}\n" +"\t\n" +"\taW := style.ft.measure(\"A\").x * style.ftScale\n" "\n" -"```\n" -"fn toupper*(inp: str): str {\n" +"\tstyle.ft.draw(tb.buffer, p, style.ftColor, style.ftScale)\n" +"\tif gui.selection == gui.idx {\n" +"\t\tcanvas.drawRect(style.ftColor, rect.mk(c.x, c.y, aW / 4, dm.y))\n" +"\t}\n" +"\n" +"\tcanvas.endScissor()\n" +"}\n" "```\n" "\n" -"returns the same string, but characters are upper case\n" "\n" "\n" -"## fn tolower\n" +"## \n" "\n" "```\n" -"fn tolower*(inp: str): str {\n" "```\n" "\n" -"returns the same string, but all characters are lower case\n" "\n" "\n" -"## fn repeat\n" +"## \n" "\n" "```\n" -"fn repeat*(inp: str, count: int): str {\n" -"```\n" "\n" -"repeats string count number of times\n" +"\tif cfg.centerX { cfg.stretchX = true }\n" +"\tif cfg.centerY { cfg.stretchY = true }\n" "\n" +"\tr := cfg.rect\n" +"\tdm := i.getDims().mul(cfg.scale)\n" +"\tif r.w == 0 { r.w = dm.x }\n" +"\tif r.h == 0 { r.h = dm.y }\n" "\n" -"## fn trimspaces\n" +"\tif cfg.stretchX { r.w = 0 }\n" +"\tif cfg.stretchY { r.h = 0 }\n" "\n" -"```\n" -"fn trimspaces*(inp: str): str {\n" -"```\n" +"\tr = gui.pushRect(r)\n" "\n" -"trims whitespaces from the start and end of a string\n" +"\tif gui.isEval { return }\n" "\n" +"\tx := r.x\n" +"\ty := r.y\n" +"\tif cfg.centerX {\n" +"\t\tx += (r.w - dm.x) / 2\n" +"\t}\n" "\n" -"## fn trimprefix\n" +"\tif cfg.centerY {\n" +"\t\ty += (r.h - dm.y) / 2\n" +"\t}\n" "\n" -"```\n" -"fn trimprefix*(inp: str, prefix: str): str {\n" +"\ti.draw(th.Transform{\n" +"\t\tp: { x, y },\n" +"\t\ts: cfg.scale }, cfg.color)\n" +"}\n" "```\n" "\n" -"trims a prefix of a string\n" "\n" "\n" -"## fn trimsuffix\n" +"## \n" "\n" "```\n" -"fn trimsuffix*(inp: str, suffix: str): str {\n" "```\n" "\n" -"trims a suffix of a string\n" "\n" "\n" "", diff --git a/src/tophat.h b/src/tophat.h index a66998cc..d5ea267d 100644 --- a/src/tophat.h +++ b/src/tophat.h @@ -471,7 +471,7 @@ th_print_umka_error_and_quit(); void th_navmesh_add_quad(th_navmesh *m, th_quad *q); void -th_navmesh_nav(th_vf2s *cameFrom, th_navmesh *m, th_vf2 p1, th_vf2 p2); +th_navmesh_nav(th_vf2s *cameFrom, void *cameFromType, th_navmesh *m, th_vf2 p1, th_vf2 p2); void th_nav_init(void); diff --git a/umka/nav.um b/umka/nav.um index 61085d2d..40eb3231 100644 --- a/umka/nav.um +++ b/umka/nav.um @@ -59,17 +59,15 @@ fn (m: ^Mesh) addQuad*(q: th.Quad) { umth_nav_mesh_add_quad(m, &q) } -type Vf2s* = []th.Vf2 - -fn umth_nav_mesh_nav(cameFrom: ^Vf2s, m: ^Mesh, p1, p2: th.Vf2) +fn umth_nav_mesh_nav(cameFrom: ^[]th.Vf2, cameFromType: ^void, m: ^Mesh, p1, p2: th.Vf2) //~~fn Mesh.nav // Navigates between `p1` and `p2`. Returns the path as an array of `th.Vf2`s. // If it doesn't find any path, or one of the points is outside of the mask, // returns an empty array. fn (m: ^Mesh) nav*(p1, p2: th.Vf2): []th.Vf2 { //~~ - var cameFrom: Vf2s - umth_nav_mesh_nav(&cameFrom, m, p1, p2) + var cameFrom: []th.Vf2 + umth_nav_mesh_nav(&cameFrom, typeptr([]th.Vf2), m, p1, p2) path := []th.Vf2{p2} p := p2