├── .github └── workflows │ └── publish.yml ├── .gitignore ├── LICENSE ├── README.md ├── bindings ├── README.md ├── bindings.ts ├── generator.ts └── raylib.h ├── blobs ├── README.md ├── libraylib.dylib ├── libraylib.so └── raylib.dll ├── deno.jsonc ├── deno.lock ├── examples ├── basic.ts ├── filedrop.ts └── transparent.ts ├── mod.ts └── src ├── README.md ├── _helper.ts ├── _util.ts ├── audio.ts ├── audio_stream.ts ├── automation_events.ts ├── camera3d.ts ├── collision.ts ├── color.ts ├── cursor.ts ├── drawing.ts ├── file_drop.ts ├── font.ts ├── gamepad.ts ├── gesture.ts ├── image.ts ├── keyboard.ts ├── material.ts ├── mesh.ts ├── model.ts ├── model_animations.ts ├── mouse.ts ├── music.ts ├── screen_space.ts ├── shader.ts ├── shapes.ts ├── shapes3d.ts ├── sound.ts ├── splines.ts ├── text.ts ├── texture.ts ├── timing.ts ├── touch.ts ├── vr.ts └── window.ts /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | publish: 10 | runs-on: ubuntu-latest 11 | permissions: 12 | contents: read 13 | id-token: write # The OIDC ID token is used for authentication with JSR. 14 | steps: 15 | - uses: actions/checkout@v4 16 | - run: npx jsr publish 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Lino Le Van 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Raylib Deno 2 | 3 | Deno bindings for [raylib](https://github.com/raysan5/raylib). This is currently 4 | aligned to raylib v5.0. 5 | 6 | ## Usage 7 | 8 | ```typescript 9 | import { 10 | Drawing, 11 | LIGHTGRAY, 12 | RAYWHITE, 13 | Text, 14 | Window, 15 | } from "https://deno.land/x/raylib"; 16 | 17 | Window.init(800, 450, "Raylib - Basic Window"); 18 | 19 | while (!Window.shouldClose()) { 20 | Drawing.beginDrawing(); 21 | Drawing.clearBackground(RAYWHITE); 22 | Text.drawText( 23 | "Congrats! You created your first window!", 24 | 190, 25 | 200, 26 | 20, 27 | LIGHTGRAY, 28 | ); 29 | Drawing.endDrawing(); 30 | } 31 | 32 | Window.close(); 33 | ``` 34 | -------------------------------------------------------------------------------- /bindings/README.md: -------------------------------------------------------------------------------- 1 | # Raylib Bindings 2 | 3 | This submodule contains the binding generator for raylib. It's really scuffed, 4 | and won't work for any other libraries. It's also not very well documented, so 5 | good luck soldier. 6 | -------------------------------------------------------------------------------- /bindings/generator.ts: -------------------------------------------------------------------------------- 1 | let result = "// This file is generated by generator.ts\n\n"; 2 | const source = Deno.readTextFileSync("./raylib.h").split("\n"); 3 | 4 | // Generate the version constants 5 | result += `// --- Version constants ---\n`; 6 | result += `export const RAYLIB_VERSION_MAJOR = ${ 7 | source[83].split(" ").pop() 8 | };\n`; 9 | result += `export const RAYLIB_VERSION_MINOR = ${ 10 | source[84].split(" ").pop() 11 | };\n`; 12 | result += `export const RAYLIB_VERSION_PATCH = ${ 13 | source[85].split(" ").pop() 14 | };\n`; 15 | result += `export const RAYLIB_VERSION = ${source[86].split(" ").pop()};\n\n`; 16 | 17 | // Generate the function definitions 18 | result += "// --- bindings ---\n"; 19 | result += 'import { dlopen } from "https://deno.land/x/plug@1.0.3/mod.ts";\n\n'; 20 | result += 21 | 'export const lib = await dlopen({\n\tname: "raylib",\n\turl: import.meta.resolve("../blobs")\n}, {\n'; 22 | 23 | function extract(core: string) { 24 | return { 25 | name: core.split(" ").pop()!.slice(core.split("*").length - 1), 26 | type: core.split(" ").slice(0, -1).join(" ") + 27 | (core.split("*").length > 1 28 | ? " " + new Array(core.split("*").length - 1).fill("*").join("") 29 | : ""), 30 | }; 31 | } 32 | 33 | const raw_type_map: Record = { 34 | "void": "void", 35 | "void *": "pointer", 36 | "bool": "u8", 37 | "char": "i8", 38 | "unsigned int": "u32", 39 | "int": "i32", 40 | "long": "i64", 41 | "int *": "pointer", 42 | "const int *": "pointer", 43 | "const char *": "buffer", 44 | "const char **": "pointer", 45 | "unsigned char *": "pointer", 46 | "const unsigned char *": "pointer", 47 | "const void *": "pointer", 48 | "char *": "buffer", 49 | "float *": "pointer", 50 | "float": "f32", 51 | "double": "f64", 52 | // Custom types 53 | "Color": { struct: ["u8", "u8", "u8", "u8"] }, 54 | "Image": { struct: ["pointer", "i32", "i32", "i32", "i32"] }, 55 | "Font": { 56 | struct: [ 57 | "i32", 58 | "i32", 59 | "i32", 60 | "u32", 61 | "i32", 62 | "i32", 63 | "i32", 64 | "i32", 65 | "pointer", 66 | "pointer", 67 | ], 68 | }, 69 | "Rectangle": { struct: ["f32", "f32", "f32", "f32"] }, 70 | "BoundingBox": { struct: ["f32", "f32", "f32", "f32", "f32", "f32"] }, 71 | "Matrix": { 72 | struct: [ 73 | "f32", 74 | "f32", 75 | "f32", 76 | "f32", 77 | "f32", 78 | "f32", 79 | "f32", 80 | "f32", 81 | "f32", 82 | "f32", 83 | "f32", 84 | "f32", 85 | "f32", 86 | "f32", 87 | "f32", 88 | "f32", 89 | "f32", 90 | "f32", 91 | "f32", 92 | "f32", 93 | ], 94 | }, 95 | "Vector2": { struct: ["f32", "f32"] }, 96 | "Vector3": { struct: ["f32", "f32", "f32"] }, 97 | "Vector4": { struct: ["f32", "f32", "f32", "f32"] }, 98 | "Ray": { struct: ["f32", "f32", "f32", "f32", "f32", "f32"] }, 99 | "RayCollision": { 100 | struct: ["u8", "f32", "f32", "f32", "f32", "f32", "f32", "f32"], 101 | }, 102 | "Model": { 103 | struct: [ 104 | "f32", 105 | "f32", 106 | "f32", 107 | "f32", 108 | "f32", 109 | "f32", 110 | "f32", 111 | "f32", 112 | "f32", 113 | "f32", 114 | "f32", 115 | "f32", 116 | "f32", 117 | "f32", 118 | "f32", 119 | "f32", 120 | "f32", 121 | "f32", 122 | "f32", 123 | "f32", 124 | "i32", 125 | "i32", 126 | "pointer", 127 | "pointer", 128 | "pointer", 129 | "i32", 130 | "pointer", 131 | "pointer", 132 | ], 133 | }, 134 | "Mesh": { 135 | struct: [ 136 | "i32", 137 | "i32", 138 | "pointer", 139 | "pointer", 140 | "pointer", 141 | "pointer", 142 | "pointer", 143 | "pointer", 144 | "pointer", 145 | "pointer", 146 | "pointer", 147 | "pointer", 148 | "pointer", 149 | "u32", 150 | "pointer", 151 | ], 152 | }, 153 | "Material": { 154 | struct: ["u32", "pointer", "pointer", "f32", "f32", "f32", "f32"], 155 | }, 156 | "ModelAnimation": { 157 | struct: ["i32", "i32", "pointer", "pointer", "u64", "u64", "u64", "u64"], 158 | }, 159 | "Texture2D": { struct: ["u32", "i32", "i32", "i32", "i32"] }, 160 | "TextureCubemap": { struct: ["u32", "i32", "i32", "i32", "i32"] }, 161 | "RenderTexture2D": { 162 | struct: [ 163 | "u32", 164 | "u32", 165 | "i32", 166 | "i32", 167 | "i32", 168 | "i32", 169 | "u32", 170 | "i32", 171 | "i32", 172 | "i32", 173 | "i32", 174 | ], 175 | }, 176 | "Camera": { 177 | struct: [ 178 | "f32", 179 | "f32", 180 | "f32", 181 | "f32", 182 | "f32", 183 | "f32", 184 | "f32", 185 | "f32", 186 | "f32", 187 | "f32", 188 | "i32", 189 | ], 190 | }, 191 | "Camera2D": { struct: ["f32", "f32", "f32", "f32", "f32", "f32"] }, 192 | "Camera3D": { 193 | struct: [ 194 | "f32", 195 | "f32", 196 | "f32", 197 | "f32", 198 | "f32", 199 | "f32", 200 | "f32", 201 | "f32", 202 | "f32", 203 | "f32", 204 | "i32", 205 | ], 206 | }, 207 | "Shader": { struct: ["u32", "pointer"] }, 208 | "Sound": { struct: ["pointer", "pointer", "u32", "u32", "u32", "u32"] }, 209 | "Wave": { struct: ["u32", "u32", "u32", "u32", "pointer"] }, 210 | "Music": { 211 | struct: [ 212 | "pointer", 213 | "pointer", 214 | "u32", 215 | "u32", 216 | "u32", 217 | "u32", 218 | "u8", 219 | "i32", 220 | "pointer", 221 | ], 222 | }, 223 | "AudioStream": { struct: ["pointer", "pointer", "u32", "u32", "u32"] }, 224 | "FilePathList": { struct: ["u32", "u32", "pointer"] }, 225 | "AutomationEvent": { struct: ["u32", "u32", "i32", "i32", "i32", "i32"] }, 226 | "AutomationEventList": { struct: ["u32", "u32", "pointer"] }, 227 | "NPatchInfo": { 228 | struct: ["f32", "f32", "f32", "f32", "i32", "i32", "i32", "i32", "i32"], 229 | }, 230 | "GlyphInfo": { 231 | struct: ["i32", "i32", "i32", "i32", "pointer", "i32", "i32", "i32", "i32"], 232 | }, 233 | "VrStereoConfig": { 234 | struct: [ 235 | "f32", 236 | "f32", 237 | "f32", 238 | "f32", 239 | "f32", 240 | "f32", 241 | "f32", 242 | "f32", 243 | "f32", 244 | "f32", 245 | "f32", 246 | "f32", 247 | "f32", 248 | "f32", 249 | "f32", 250 | "f32", 251 | "f32", 252 | "f32", 253 | "f32", 254 | "f32", 255 | "f32", 256 | "f32", 257 | "f32", 258 | "f32", 259 | "f32", 260 | "f32", 261 | "f32", 262 | "f32", 263 | "f32", 264 | "f32", 265 | "f32", 266 | "f32", 267 | "f32", 268 | "f32", 269 | "f32", 270 | "f32", 271 | "f32", 272 | "f32", 273 | "f32", 274 | "f32", 275 | "f32", 276 | "f32", 277 | "f32", 278 | "f32", 279 | "f32", 280 | "f32", 281 | "f32", 282 | "f32", 283 | "f32", 284 | "f32", 285 | "f32", 286 | "f32", 287 | "f32", 288 | "f32", 289 | "f32", 290 | "f32", 291 | "f32", 292 | "f32", 293 | "f32", 294 | "f32", 295 | "f32", 296 | "f32", 297 | "f32", 298 | "f32", 299 | "f32", 300 | "f32", 301 | "f32", 302 | "f32", 303 | "f32", 304 | "f32", 305 | "f32", 306 | "f32", 307 | "f32", 308 | "f32", 309 | "f32", 310 | "f32", 311 | "f32", 312 | "f32", 313 | "f32", 314 | "f32", 315 | "f32", 316 | "f32", 317 | "f32", 318 | "f32", 319 | "f32", 320 | "f32", 321 | "f32", 322 | "f32", 323 | "f32", 324 | "f32", 325 | "f32", 326 | "f32", 327 | ], 328 | }, 329 | "VrDeviceInfo": { 330 | struct: [ 331 | "i32", 332 | "i32", 333 | "f32", 334 | "f32", 335 | "f32", 336 | "f32", 337 | "f32", 338 | "f32", 339 | "f32", 340 | "f32", 341 | "f32", 342 | "f32", 343 | "f32", 344 | "f32", 345 | "f32", 346 | "f32", 347 | ], 348 | }, 349 | // Custom types pointers, 350 | "Color *": "pointer", 351 | "Image *": "pointer", 352 | "Vector2 *": "pointer", 353 | "Vector3 *": "pointer", 354 | "Wave *": "pointer", 355 | "ModelAnimation *": "pointer", 356 | "Mesh *": "pointer", 357 | "Model *": "pointer", 358 | "Material *": "pointer", 359 | "Camera *": "pointer", 360 | "AutomationEventList *": "pointer", 361 | "Texture2D *": "pointer", 362 | "GlyphInfo *": "pointer", 363 | "const GlyphInfo *": "pointer", 364 | "Rectangle **": "pointer", 365 | "const Matrix *": "pointer", 366 | // Function pointers 367 | "AudioCallback": "function", 368 | "TraceLogCallback": "function", 369 | "LoadFileDataCallback": "function", 370 | "SaveFileDataCallback": "function", 371 | "LoadFileTextCallback": "function", 372 | "SaveFileTextCallback": "function", 373 | }; 374 | 375 | for (let i = 953; i < 1656; i++) { 376 | if (!source[i].startsWith("RLAPI")) continue; 377 | if (source[i].includes(", ...")) continue; 378 | const comment = source[i].split("//")[1].trim(); 379 | const { name: functionName, type: returnType } = extract( 380 | source[i].split("(")[0].split(" ").slice(1).join(" "), 381 | ); 382 | const parameters = source[i].split("(")[1].split(")")[0] === "void" 383 | ? [] 384 | : source[i].split("(")[1].split(")")[0].split(",").map((v) => 385 | extract(v.trim()) 386 | ); 387 | 388 | result += `\t// ${comment}\n`; 389 | result += `\t${functionName}: { parameters: [${ 390 | parameters.map((param) => JSON.stringify(raw_type_map[param.type])).join( 391 | ", ", 392 | ) 393 | }], result: ${JSON.stringify(raw_type_map[returnType])} },\n`; 394 | } 395 | 396 | result += "});\n\n"; 397 | 398 | // Write the result to the bindings file 399 | Deno.writeTextFileSync("./bindings.ts", result); 400 | -------------------------------------------------------------------------------- /blobs/README.md: -------------------------------------------------------------------------------- 1 | # Raylib Blobs 2 | 3 | These are the blobs for the raylib Deno bindings. They are downloaded from the 4 | releases page of the raylib repository. If you don't trust me, you can download 5 | them yourself and compare the checksums. 6 | -------------------------------------------------------------------------------- /blobs/libraylib.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lino-levan/raylib-deno/b6886faeb483c6e41dbada05fd188a8c8fb2b5c6/blobs/libraylib.dylib -------------------------------------------------------------------------------- /blobs/libraylib.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lino-levan/raylib-deno/b6886faeb483c6e41dbada05fd188a8c8fb2b5c6/blobs/libraylib.so -------------------------------------------------------------------------------- /blobs/raylib.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lino-levan/raylib-deno/b6886faeb483c6e41dbada05fd188a8c8fb2b5c6/blobs/raylib.dll -------------------------------------------------------------------------------- /deno.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lino/raylib", 3 | "version": "0.1.0", 4 | "exports": "./mod.ts", 5 | "tasks": { 6 | "generate": "cd bindings && deno run --allow-read --allow-write generator.ts && deno fmt" 7 | }, 8 | "imports": { 9 | "raylib": "./mod.ts" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /deno.lock: -------------------------------------------------------------------------------- 1 | { 2 | "version": "5", 3 | "specifiers": { 4 | "jsr:@denosaurs/plug@1.0.6": "1.0.6", 5 | "jsr:@std/assert@0.221": "0.221.0", 6 | "jsr:@std/encoding@0.221": "0.221.0", 7 | "jsr:@std/fmt@0.221": "0.221.0", 8 | "jsr:@std/fs@0.221": "0.221.0", 9 | "jsr:@std/path@0.221": "0.221.0" 10 | }, 11 | "jsr": { 12 | "@denosaurs/plug@1.0.6": { 13 | "integrity": "6cf5b9daba7799837b9ffbe89f3450510f588fafef8115ddab1ff0be9cb7c1a7", 14 | "dependencies": [ 15 | "jsr:@std/encoding", 16 | "jsr:@std/fmt", 17 | "jsr:@std/fs", 18 | "jsr:@std/path" 19 | ] 20 | }, 21 | "@std/assert@0.221.0": { 22 | "integrity": "a5f1aa6e7909dbea271754fd4ab3f4e687aeff4873b4cef9a320af813adb489a" 23 | }, 24 | "@std/encoding@0.221.0": { 25 | "integrity": "d1dd76ef0dc5d14088411e6dc1dede53bf8308c95d1537df1214c97137208e45" 26 | }, 27 | "@std/fmt@0.221.0": { 28 | "integrity": "379fed69bdd9731110f26b9085aeb740606b20428ce6af31ef6bd45ef8efa62a" 29 | }, 30 | "@std/fs@0.221.0": { 31 | "integrity": "028044450299de8ed5a716ade4e6d524399f035513b85913794f4e81f07da286", 32 | "dependencies": [ 33 | "jsr:@std/assert", 34 | "jsr:@std/path" 35 | ] 36 | }, 37 | "@std/path@0.221.0": { 38 | "integrity": "0a36f6b17314ef653a3a1649740cc8db51b25a133ecfe838f20b79a56ebe0095", 39 | "dependencies": [ 40 | "jsr:@std/assert" 41 | ] 42 | } 43 | }, 44 | "remote": { 45 | "https://deno.land/std@0.203.0/assert/assert.ts": "9a97dad6d98c238938e7540736b826440ad8c1c1e54430ca4c4e623e585607ee", 46 | "https://deno.land/std@0.203.0/assert/assertion_error.ts": "4d0bde9b374dfbcbe8ac23f54f567b77024fb67dbb1906a852d67fe050d42f56", 47 | "https://deno.land/std@0.203.0/encoding/_util.ts": "f368920189c4fe6592ab2e93bd7ded8f3065b84f95cd3e036a4a10a75649dcba", 48 | "https://deno.land/std@0.203.0/encoding/hex.ts": "d41e9c3f7dd9d4738c40c2b9e6db5eb32e9dc103360291aff63a5c3fccdb45a6", 49 | "https://deno.land/std@0.203.0/fmt/colors.ts": "c51c4642678eb690dcf5ffee5918b675bf01a33fba82acf303701ae1a4f8c8d9", 50 | "https://deno.land/std@0.203.0/fs/_util.ts": "fbf57dcdc9f7bc8128d60301eece608246971a7836a3bb1e78da75314f08b978", 51 | "https://deno.land/std@0.203.0/fs/copy.ts": "23cc1c465babe5ca4d69778821e2f8addc44593e30a5ca0b902b3784eed75bb6", 52 | "https://deno.land/std@0.203.0/fs/empty_dir.ts": "2e52cd4674d18e2e007175c80449fc3d263786a1361e858d9dfa9360a6581b47", 53 | "https://deno.land/std@0.203.0/fs/ensure_dir.ts": "dc64c4c75c64721d4e3fb681f1382f803ff3d2868f08563ff923fdd20d071c40", 54 | "https://deno.land/std@0.203.0/fs/ensure_file.ts": "39ac83cc283a20ec2735e956adf5de3e8a3334e0b6820547b5772f71c49ae083", 55 | "https://deno.land/std@0.203.0/fs/ensure_link.ts": "c15e69c48556d78aae31b83e0c0ece04b7b8bc0951412f5b759aceb6fde7f0ac", 56 | "https://deno.land/std@0.203.0/fs/ensure_symlink.ts": "b389c8568f0656d145ac7ece472afe710815cccbb2ebfd19da7978379ae143fe", 57 | "https://deno.land/std@0.203.0/fs/eol.ts": "f1f2eb348a750c34500741987b21d65607f352cf7205f48f4319d417fff42842", 58 | "https://deno.land/std@0.203.0/fs/exists.ts": "cb59a853d84871d87acab0e7936a4dac11282957f8e195102c5a7acb42546bb8", 59 | "https://deno.land/std@0.203.0/fs/expand_glob.ts": "52b8b6f5b1fa585c348250da1c80ce5d820746cb4a75d874b3599646f677d3a7", 60 | "https://deno.land/std@0.203.0/fs/mod.ts": "bc3d0acd488cc7b42627044caf47d72019846d459279544e1934418955ba4898", 61 | "https://deno.land/std@0.203.0/fs/move.ts": "b4f8f46730b40c32ea3c0bc8eb0fd0e8139249a698883c7b3756424cf19785c9", 62 | "https://deno.land/std@0.203.0/fs/walk.ts": "a16146724a6aaf9efdb92023a74e9805195c3469900744ce5de4113b07b29779", 63 | "https://deno.land/std@0.203.0/path/_basename.ts": "057d420c9049821f983f784fd87fa73ac471901fb628920b67972b0f44319343", 64 | "https://deno.land/std@0.203.0/path/_constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0", 65 | "https://deno.land/std@0.203.0/path/_dirname.ts": "355e297236b2218600aee7a5301b937204c62e12da9db4b0b044993d9e658395", 66 | "https://deno.land/std@0.203.0/path/_extname.ts": "eaaa5aae1acf1f03254d681bd6a8ce42a9cb5b7ff2213a9d4740e8ab31283664", 67 | "https://deno.land/std@0.203.0/path/_format.ts": "4a99270d6810f082e614309164fad75d6f1a483b68eed97c830a506cc589f8b4", 68 | "https://deno.land/std@0.203.0/path/_from_file_url.ts": "6eadfae2e6f63ad9ee46b26db4a1b16583055c0392acedfb50ed2fc694b6f581", 69 | "https://deno.land/std@0.203.0/path/_interface.ts": "6471159dfbbc357e03882c2266d21ef9afdb1e4aa771b0545e90db58a0ba314b", 70 | "https://deno.land/std@0.203.0/path/_is_absolute.ts": "05dac10b5e93c63198b92e3687baa2be178df5321c527dc555266c0f4f51558c", 71 | "https://deno.land/std@0.203.0/path/_join.ts": "815f5e85b042285175b1492dd5781240ce126c23bd97bad6b8211fe7129c538e", 72 | "https://deno.land/std@0.203.0/path/_normalize.ts": "a19ec8706b2707f9dd974662a5cd89fad438e62ab1857e08b314a8eb49a34d81", 73 | "https://deno.land/std@0.203.0/path/_os.ts": "30b0c2875f360c9296dbe6b7f2d528f0f9c741cecad2e97f803f5219e91b40a2", 74 | "https://deno.land/std@0.203.0/path/_parse.ts": "0f9b0ff43682dd9964eb1c4398610c4e165d8db9d3ac9d594220217adf480cfa", 75 | "https://deno.land/std@0.203.0/path/_relative.ts": "27bdeffb5311a47d85be26d37ad1969979359f7636c5cd9fcf05dcd0d5099dc5", 76 | "https://deno.land/std@0.203.0/path/_resolve.ts": "7a3616f1093735ed327e758313b79c3c04ea921808ca5f19ddf240cb68d0adf6", 77 | "https://deno.land/std@0.203.0/path/_to_file_url.ts": "a141e4a525303e1a3a0c0571fd024552b5f3553a2af7d75d1ff3a503dcbb66d8", 78 | "https://deno.land/std@0.203.0/path/_to_namespaced_path.ts": "0d5f4caa2ed98ef7a8786286df6af804b50e38859ae897b5b5b4c8c5930a75c8", 79 | "https://deno.land/std@0.203.0/path/_util.ts": "4e191b1bac6b3bf0c31aab42e5ca2e01a86ab5a0d2e08b75acf8585047a86221", 80 | "https://deno.land/std@0.203.0/path/basename.ts": "bdfa5a624c6a45564dc6758ef2077f2822978a6dbe77b0a3514f7d1f81362930", 81 | "https://deno.land/std@0.203.0/path/common.ts": "ee7505ab01fd22de3963b64e46cff31f40de34f9f8de1fff6a1bd2fe79380000", 82 | "https://deno.land/std@0.203.0/path/dirname.ts": "b6533f4ee4174a526dec50c279534df5345836dfdc15318400b08c62a62a39dd", 83 | "https://deno.land/std@0.203.0/path/extname.ts": "62c4b376300795342fe1e4746c0de518b4dc9c4b0b4617bfee62a2973a9555cf", 84 | "https://deno.land/std@0.203.0/path/format.ts": "110270b238514dd68455a4c54956215a1aff7e37e22e4427b7771cefe1920aa5", 85 | "https://deno.land/std@0.203.0/path/from_file_url.ts": "9f5cb58d58be14c775ec2e57fc70029ac8b17ed3bd7fe93e475b07280adde0ac", 86 | "https://deno.land/std@0.203.0/path/glob.ts": "593e2c3573883225c25c5a21aaa8e9382a696b8e175ea20a3b6a1471ad17aaed", 87 | "https://deno.land/std@0.203.0/path/is_absolute.ts": "0b92eb35a0a8780e9f16f16bb23655b67dace6a8e0d92d42039e518ee38103c1", 88 | "https://deno.land/std@0.203.0/path/join.ts": "31c5419f23d91655b08ec7aec403f4e4cd1a63d39e28f6e42642ea207c2734f8", 89 | "https://deno.land/std@0.203.0/path/mod.ts": "6e1efb0b13121463aedb53ea51dabf5639a3172ab58c89900bbb72b486872532", 90 | "https://deno.land/std@0.203.0/path/normalize.ts": "6ea523e0040979dd7ae2f1be5bf2083941881a252554c0f32566a18b03021955", 91 | "https://deno.land/std@0.203.0/path/parse.ts": "be8de342bb9e1924d78dc4d93c45215c152db7bf738ec32475560424b119b394", 92 | "https://deno.land/std@0.203.0/path/posix.ts": "0a1c1952d132323a88736d03e92bd236f3ed5f9f079e5823fae07c8d978ee61b", 93 | "https://deno.land/std@0.203.0/path/relative.ts": "8bedac226afd360afc45d451a6c29fabceaf32978526bcb38e0c852661f66c61", 94 | "https://deno.land/std@0.203.0/path/resolve.ts": "133161e4949fc97f9ca67988d51376b0f5eef8968a6372325ab84d39d30b80dc", 95 | "https://deno.land/std@0.203.0/path/separator.ts": "40a3e9a4ad10bef23bc2cd6c610291b6c502a06237c2c4cd034a15ca78dedc1f", 96 | "https://deno.land/std@0.203.0/path/to_file_url.ts": "00e6322373dd51ad109956b775e4e72e5f9fa68ce2c6b04e4af2a6eed3825d31", 97 | "https://deno.land/std@0.203.0/path/to_namespaced_path.ts": "1b1db3055c343ab389901adfbda34e82b7386bcd1c744d54f9c1496ee0fd0c3d", 98 | "https://deno.land/std@0.203.0/path/win32.ts": "8b3f80ef7a462511d5e8020ff490edcaa0a0d118f1b1e9da50e2916bdd73f9dd", 99 | "https://deno.land/x/plug@1.0.3/deps.ts": "91d5b264dd7374bf6f4f544fa0ddef12f1c6fddc10840314f5fb6aeeadb64396", 100 | "https://deno.land/x/plug@1.0.3/download.ts": "b92bc1c1ae35fdb75828847f1ebfc7e51bf462f339729740e1cffe78384e1509", 101 | "https://deno.land/x/plug@1.0.3/mod.ts": "5dec80ee7a3a325be45c03439558531bce7707ac118f4376cebbd6740ff24bfb", 102 | "https://deno.land/x/plug@1.0.3/types.ts": "0490359117c53783138f2b6692a34f85bca9237314ba8cdef8ad682d81218d21", 103 | "https://deno.land/x/plug@1.0.3/util.ts": "ded3db6e9bb16b8003899d9073fb310e13231ca617b35d6b7dfd53f38762cc76" 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /examples/basic.ts: -------------------------------------------------------------------------------- 1 | import { Drawing, LIGHTGRAY, RAYWHITE, Text, Window } from "raylib"; 2 | 3 | Window.init(800, 450, "Raylib - Basic Window"); 4 | 5 | while (!Window.shouldClose()) { 6 | Drawing.beginDrawing(); 7 | Drawing.clearBackground(RAYWHITE); 8 | Text.drawText( 9 | "Congrats! You created your first window!", 10 | 190, 11 | 200, 12 | 20, 13 | LIGHTGRAY, 14 | ); 15 | console.log(Window.getPosition()); 16 | Drawing.endDrawing(); 17 | } 18 | 19 | Window.close(); 20 | -------------------------------------------------------------------------------- /examples/filedrop.ts: -------------------------------------------------------------------------------- 1 | import { Drawing, FileDrop, LIGHTGRAY, RAYWHITE, Text, Window } from "raylib"; 2 | 3 | Window.init(800, 450, "Raylib - File Drop"); 4 | 5 | while (!Window.shouldClose()) { 6 | Drawing.beginDrawing(); 7 | Drawing.clearBackground(RAYWHITE); 8 | Text.drawText( 9 | "Try dropping a file here, then read the console.", 10 | 190, 11 | 200, 12 | 20, 13 | LIGHTGRAY, 14 | ); 15 | 16 | if (FileDrop.isFileDropped()) { 17 | const files = FileDrop.loadDroppedFiles(); 18 | console.log(files); 19 | } 20 | 21 | Drawing.endDrawing(); 22 | } 23 | 24 | Window.close(); 25 | -------------------------------------------------------------------------------- /examples/transparent.ts: -------------------------------------------------------------------------------- 1 | import { BLACK, BLANK, Drawing, Shapes, Timing, Vector2, Window } from "raylib"; 2 | 3 | Timing.setTargetFPS(60); 4 | Window.init(100, 100, "Hey", { 5 | transparent: true, 6 | undecorated: true, 7 | topmost: true, 8 | mousePassthrough: true, 9 | }); 10 | Window.setPosition(0, 0); 11 | 12 | let height = 50; 13 | let frame = 0; 14 | 15 | while (!Window.shouldClose()) { 16 | frame++; 17 | Drawing.beginDrawing(); 18 | Drawing.clearBackground(BLANK); 19 | Window.setSize(100, Math.round(height)); 20 | 21 | Shapes.drawLineEx(new Vector2(0, 0), new Vector2(100, height), 10, BLACK); 22 | 23 | height = Math.round(Math.sin(frame / 10) * 25 + 50); 24 | 25 | Drawing.endDrawing(); 26 | } 27 | 28 | Window.close(); 29 | -------------------------------------------------------------------------------- /mod.ts: -------------------------------------------------------------------------------- 1 | // TODO: Check if numbers are correct (integers) 2 | 3 | // Utility stuff shared between bindings 4 | export * from "./src/_util.ts"; 5 | 6 | // Bindings 7 | export * from "./src/audio.ts"; 8 | export * from "./src/audio_stream.ts"; 9 | export * from "./src/automation_events.ts"; 10 | export * from "./src/camera3d.ts"; 11 | export * from "./src/collision.ts"; 12 | export * from "./src/color.ts"; 13 | export * from "./src/cursor.ts"; 14 | export * from "./src/drawing.ts"; 15 | export * from "./src/file_drop.ts"; 16 | export * from "./src/font.ts"; 17 | export * from "./src/gamepad.ts"; 18 | export * from "./src/gesture.ts"; 19 | export * from "./src/image.ts"; 20 | export * from "./src/keyboard.ts"; 21 | export * from "./src/material.ts"; 22 | export * from "./src/mesh.ts"; 23 | export * from "./src/model.ts"; 24 | export * from "./src/model_animations.ts"; 25 | export * from "./src/mouse.ts"; 26 | export * from "./src/music.ts"; 27 | export * from "./src/screen_space.ts"; 28 | export * from "./src/shader.ts"; 29 | export * from "./src/shapes.ts"; 30 | export * from "./src/shapes3d.ts"; 31 | export * from "./src/sound.ts"; 32 | export * from "./src/splines.ts"; 33 | export * from "./src/text.ts"; 34 | export * from "./src/texture.ts"; 35 | export * from "./src/timing.ts"; 36 | export * from "./src/touch.ts"; 37 | export * from "./src/vr.ts"; 38 | export * from "./src/window.ts"; 39 | -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | # Raylib Wrapper API 2 | 3 | This is the core of the raylib wrapper. 4 | 5 | ## Philosophy 6 | 7 | The goal of this wrapper is to provide a simple, easy to use, and safe API for 8 | raylib. It is not intended to be a 1:1 mapping of the raylib API. Instead, it is 9 | intended to be a more idiomatic and ergonomic API for raylib. 10 | 11 | There are several APIs which exist in Raylib that are not exposed in this 12 | wrapper. This is intentional. They are either not idiomatic or should really 13 | just be done in Javascript instead of through FFI. They are the following: 14 | 15 | ### Requires custom build 16 | 17 | - `SwapScreenBuffer` 18 | - `PollInputEvents` 19 | 20 | ### Not clear how to implement 21 | 22 | - `TraceLog` 23 | 24 | ### Not idiomatic 25 | 26 | - `WaitTime` 27 | - `SetRandomSeed` 28 | - `GetRandomValue` 29 | - `LoadRandomSequence` 30 | - `UnloadRandomSequence` 31 | - `OpenURL` 32 | - `SetLoadFileDataCallback` 33 | - `SetSaveFileDataCallback` 34 | - `SetLoadFileTextCallback` 35 | - `SetSaveFileTextCallback` 36 | - `LoadFileData` 37 | - `UnloadFileData` 38 | - `SaveFileData` 39 | - `ExportDataAsCode` 40 | - `LoadFileText` 41 | - `UnloadFileText` 42 | - `SaveFileText` 43 | - `FileExists` 44 | - `DirectoryExists` 45 | - `IsFileExtension` 46 | - `GetFileLength` 47 | - `GetFileExtension` 48 | - `GetFileName` 49 | - `GetFileNameWithoutExt` 50 | - `GetDirectoryPath` 51 | - `GetPrevDirectoryPath` 52 | - `GetWorkingDirectory` 53 | - `GetApplicationDirectory` 54 | - `ChangeDirectory` 55 | - `IsPathFile` 56 | - `LoadDirectoryFiles` 57 | - `LoadDirectoryFilesEx` 58 | - `UnloadDirectoryFiles` 59 | - `CompressData` 60 | - `DecompressData` 61 | - `EncodeDataBase64` 62 | - `DecodeDataBase64` 63 | - `LoadUTF8` 64 | - `UnloadUTF8` 65 | - `LoadCodepoints` 66 | - `UnloadCodepoints` 67 | - `GetCodepointsCount` 68 | - `GetCodepoint` 69 | - `GetCodepointNext` 70 | - `GetCodepointPrevious` 71 | - `CodepointToUTF8` 72 | - `SetTraceLogLevel` (Useless without `TraceLog`) 73 | - `MemAlloc` 74 | - `MemRealloc` 75 | - `MemFree` 76 | - `SetTraceLogCallback` (Useless without `TraceLog`) 77 | - `TextCopy` 78 | - `TextIsEqual` 79 | - `TextLength` 80 | - `TextFormat` 81 | - `TextSubtext` 82 | - `TextReplace` 83 | - `TextInsert` 84 | - `TextJoin` 85 | - `TextSplit` 86 | - `TextAppend` 87 | - `TextFindIndex` 88 | - `TextToUpper` 89 | - `TextToLower` 90 | - `TextToPascal` 91 | - `TextToInteger` 92 | -------------------------------------------------------------------------------- /src/_helper.ts: -------------------------------------------------------------------------------- 1 | import type { Vector2 } from "./_util.ts"; 2 | 3 | /** Returns buffer of Vector2 array */ 4 | export function concatVector2s(points: Vector2[]): ArrayBuffer { 5 | const result = new Float32Array(points.length * 2); 6 | for (let i = 0; i < points.length; i++) { 7 | const point = points[i]; 8 | result[i * 2] = point.x; 9 | result[i * 2 + 1] = point.y; 10 | } 11 | return result.buffer; 12 | } 13 | 14 | /** Whether or not this computer is little or big endian */ 15 | export const littleEndian = (() => { 16 | // Stolen from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView 17 | const buffer = new ArrayBuffer(2); 18 | new DataView(buffer).setInt16(0, 256, true); 19 | return new Int16Array(buffer)[0] === 256; 20 | })(); 21 | -------------------------------------------------------------------------------- /src/_util.ts: -------------------------------------------------------------------------------- 1 | import { littleEndian } from "./_helper.ts"; 2 | 3 | export class Vector2 { 4 | constructor(public x: number, public y: number) {} 5 | 6 | static fromBuffer(buffer: ArrayBuffer): Vector2 { 7 | const view = new DataView(buffer); 8 | return new Vector2( 9 | view.getFloat32(0, littleEndian), 10 | view.getFloat32(4, littleEndian), 11 | ); 12 | } 13 | 14 | get buffer(): ArrayBuffer { 15 | return new Float32Array([this.x, this.y]).buffer; 16 | } 17 | } 18 | 19 | export class Vector3 { 20 | constructor(public x: number, public y: number, public z: number) {} 21 | 22 | static fromBuffer(buffer: Uint8Array): Vector3 { 23 | const view = new DataView(buffer.buffer); 24 | return new Vector3( 25 | view.getFloat32(0, littleEndian), 26 | view.getFloat32(4, littleEndian), 27 | view.getFloat32(8, littleEndian), 28 | ); 29 | } 30 | 31 | get buffer(): ArrayBuffer { 32 | return new Float32Array([this.x, this.y, this.z]).buffer; 33 | } 34 | } 35 | 36 | export class Vector4 { 37 | constructor( 38 | public x: number, 39 | public y: number, 40 | public z: number, 41 | public w: number, 42 | ) {} 43 | 44 | static fromBuffer(buffer: ArrayBuffer): Vector4 { 45 | const view = new DataView(buffer); 46 | return new Vector4( 47 | view.getFloat32(0, littleEndian), 48 | view.getFloat32(4, littleEndian), 49 | view.getFloat32(8, littleEndian), 50 | view.getFloat32(12, littleEndian), 51 | ); 52 | } 53 | 54 | get buffer(): ArrayBuffer { 55 | return new Float32Array([this.x, this.y, this.z, this.w]).buffer; 56 | } 57 | } 58 | 59 | export class Rectangle { 60 | constructor( 61 | public x: number, 62 | public y: number, 63 | public width: number, 64 | public height: number, 65 | ) {} 66 | 67 | static fromBuffer(buffer: ArrayBuffer): Rectangle { 68 | const view = new DataView(buffer); 69 | return new Rectangle( 70 | view.getFloat32(0, littleEndian), 71 | view.getFloat32(4, littleEndian), 72 | view.getFloat32(8, littleEndian), 73 | view.getFloat32(12, littleEndian), 74 | ); 75 | } 76 | 77 | get buffer(): ArrayBuffer { 78 | return new Float32Array([this.x, this.y, this.width, this.height]).buffer; 79 | } 80 | } 81 | 82 | export class Ray { 83 | constructor(public position: Vector3, public direction: Vector3) {} 84 | 85 | static fromBuffer(buffer: ArrayBuffer): Ray { 86 | const view = new DataView(buffer); 87 | return new Ray( 88 | new Vector3( 89 | view.getFloat32(0, littleEndian), 90 | view.getFloat32(4, littleEndian), 91 | view.getFloat32(8, littleEndian), 92 | ), 93 | new Vector3( 94 | view.getFloat32(12, littleEndian), 95 | view.getFloat32(16, littleEndian), 96 | view.getFloat32(24, littleEndian), 97 | ), 98 | ); 99 | } 100 | 101 | get buffer(): ArrayBuffer { 102 | return new Float32Array([ 103 | this.position.x, 104 | this.position.y, 105 | this.position.z, 106 | this.direction.x, 107 | this.direction.y, 108 | this.direction.z, 109 | ]).buffer; 110 | } 111 | } 112 | 113 | export class BoundingBox { 114 | constructor(public min: Vector3, public max: Vector3) {} 115 | 116 | static fromBuffer(buffer: ArrayBuffer): BoundingBox { 117 | const view = new DataView(buffer); 118 | return new BoundingBox( 119 | new Vector3( 120 | view.getFloat32(0, littleEndian), 121 | view.getFloat32(4, littleEndian), 122 | view.getFloat32(8, littleEndian), 123 | ), 124 | new Vector3( 125 | view.getFloat32(12, littleEndian), 126 | view.getFloat32(16, littleEndian), 127 | view.getFloat32(24, littleEndian), 128 | ), 129 | ); 130 | } 131 | 132 | get buffer(): ArrayBuffer { 133 | return new Float32Array([ 134 | this.min.x, 135 | this.min.y, 136 | this.min.z, 137 | this.max.x, 138 | this.max.y, 139 | this.max.z, 140 | ]).buffer; 141 | } 142 | } 143 | 144 | export class Camera2D { 145 | /** Camera offset (displacement from target) */ 146 | offset: Vector2; 147 | /** Camera target (rotation and zoom origin) */ 148 | target: Vector2; 149 | /** Camera rotation in degrees */ 150 | rotation: number; 151 | /** Camera zoom (scaling), 1.0f by default */ 152 | zoom: number; 153 | 154 | constructor( 155 | options?: { 156 | /** Camera offset (displacement from target) */ 157 | offset?: Vector2; 158 | /** Camera target (rotation and zoom origin) */ 159 | target?: Vector2; 160 | /** Camera rotation in degrees */ 161 | rotation?: number; 162 | /** Camera zoom (scaling), 1.0f by default */ 163 | zoom?: number; 164 | }, 165 | ) { 166 | this.offset = options?.offset ?? new Vector2(0, 0); 167 | this.target = options?.target ?? new Vector2(0, 0); 168 | this.rotation = options?.rotation ?? 0; 169 | this.zoom = options?.zoom ?? 1; 170 | } 171 | 172 | get buffer(): ArrayBuffer { 173 | return new Float32Array([ 174 | this.offset.x, 175 | this.offset.y, 176 | this.target.x, 177 | this.target.y, 178 | this.rotation, 179 | this.zoom, 180 | ]).buffer; 181 | } 182 | } 183 | 184 | export class Matrix { 185 | constructor( 186 | public m0: number, 187 | public m1: number, 188 | public m2: number, 189 | public m3: number, 190 | public m4: number, 191 | public m5: number, 192 | public m6: number, 193 | public m7: number, 194 | public m8: number, 195 | public m9: number, 196 | public m10: number, 197 | public m11: number, 198 | public m12: number, 199 | public m13: number, 200 | public m14: number, 201 | public m15: number, 202 | ) {} 203 | 204 | static fromBuffer(buffer: ArrayBuffer): Matrix { 205 | const view = new DataView(buffer); 206 | return new Matrix( 207 | view.getFloat32(0, littleEndian), 208 | view.getFloat32(4, littleEndian), 209 | view.getFloat32(8, littleEndian), 210 | view.getFloat32(12, littleEndian), 211 | view.getFloat32(16, littleEndian), 212 | view.getFloat32(20, littleEndian), 213 | view.getFloat32(24, littleEndian), 214 | view.getFloat32(28, littleEndian), 215 | view.getFloat32(32, littleEndian), 216 | view.getFloat32(36, littleEndian), 217 | view.getFloat32(40, littleEndian), 218 | view.getFloat32(44, littleEndian), 219 | view.getFloat32(48, littleEndian), 220 | view.getFloat32(52, littleEndian), 221 | view.getFloat32(56, littleEndian), 222 | view.getFloat32(60, littleEndian), 223 | ); 224 | } 225 | 226 | get buffer(): ArrayBuffer { 227 | return new Float32Array([ 228 | this.m0, 229 | this.m1, 230 | this.m2, 231 | this.m3, 232 | this.m4, 233 | this.m5, 234 | this.m6, 235 | this.m7, 236 | this.m8, 237 | this.m9, 238 | this.m10, 239 | this.m11, 240 | this.m12, 241 | this.m13, 242 | this.m14, 243 | this.m15, 244 | ]).buffer; 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /src/audio.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Audio device functions 3 | * @module 4 | */ 5 | import { lib } from "../bindings/bindings.ts"; 6 | 7 | /** Class for interacting with an Audio Device */ 8 | export class AudioDevice { 9 | /** Initialize audio device and context */ 10 | static init() { 11 | lib.symbols.InitAudioDevice(); 12 | } 13 | 14 | /** Close the audio device and context */ 15 | static close() { 16 | lib.symbols.CloseAudioDevice(); 17 | } 18 | 19 | /** Check if audio device has been initialized successfully */ 20 | static isReady(): boolean { 21 | return !!lib.symbols.IsAudioDeviceReady(); 22 | } 23 | 24 | /** Set master volume (listener) */ 25 | static setMasterVolume(volume: number) { 26 | lib.symbols.SetMasterVolume(volume); 27 | } 28 | 29 | /** Get master volume (listener) */ 30 | static getMasterVolume(): number { 31 | return lib.symbols.GetMasterVolume(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/audio_stream.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Audio stream functions 3 | * @module 4 | */ 5 | import { lib } from "../bindings/bindings.ts"; 6 | 7 | /** Class for interacting with an Audio Stream */ 8 | export class AudioStream { 9 | #buffer: ArrayBuffer; 10 | 11 | /** Load audio stream (to stream raw audio pcm data) */ 12 | constructor(sampleRate: number, sampleSize: number, channels: number) { 13 | this.#buffer = 14 | lib.symbols.LoadAudioStream(sampleRate, sampleSize, channels).buffer; 15 | } 16 | 17 | /** Checks if an audio stream is ready */ 18 | isReady(): boolean { 19 | return !!lib.symbols.IsAudioStreamReady(this.#buffer); 20 | } 21 | 22 | /** Unload audio stream and free memory */ 23 | unload() { 24 | lib.symbols.UnloadAudioStream(this.#buffer); 25 | } 26 | 27 | /** Update audio stream buffers with data */ 28 | update(data: ArrayBuffer, frameCount: number) { 29 | lib.symbols.UpdateAudioStream( 30 | this.#buffer, 31 | Deno.UnsafePointer.of(data), 32 | frameCount, 33 | ); 34 | } 35 | 36 | /** Check if any audio stream buffers requires refill */ 37 | isProcessed(): boolean { 38 | return !!lib.symbols.IsAudioStreamProcessed(this.#buffer); 39 | } 40 | 41 | /** Play audio stream */ 42 | play() { 43 | lib.symbols.PlayAudioStream(this.#buffer); 44 | } 45 | 46 | /** Pause audio stream */ 47 | pause() { 48 | lib.symbols.PauseAudioStream(this.#buffer); 49 | } 50 | 51 | /** Resume audio stream */ 52 | resume() { 53 | lib.symbols.ResumeAudioStream(this.#buffer); 54 | } 55 | 56 | /** Check if audio stream is playing */ 57 | isPlaying(): boolean { 58 | return !!lib.symbols.IsAudioStreamPlaying(this.#buffer); 59 | } 60 | 61 | /** Stop audio stream */ 62 | stop() { 63 | lib.symbols.StopAudioStream(this.#buffer); 64 | } 65 | 66 | /** Set volume for audio stream (1.0 is max level) */ 67 | setVolume(volume: number) { 68 | lib.symbols.SetAudioStreamVolume(this.#buffer, volume); 69 | } 70 | 71 | /** Set pitch for audio stream (1.0 is base level) */ 72 | setPitch(pitch: number) { 73 | lib.symbols.SetAudioStreamPitch(this.#buffer, pitch); 74 | } 75 | 76 | /** Set pan for audio stream (0.5 is centered) */ 77 | setPan(pan: number) { 78 | lib.symbols.SetAudioStreamPan(this.#buffer, pan); 79 | } 80 | 81 | /** Default size for new audio streams */ 82 | static setBufferSizeDefault(size: number) { 83 | lib.symbols.SetAudioStreamBufferSizeDefault(size); 84 | } 85 | } 86 | 87 | // TODO 88 | // RLAPI void SetAudioStreamCallback(AudioStream stream, AudioCallback callback); // Audio thread callback to request new data 89 | 90 | // RLAPI void AttachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Attach audio stream processor to stream, receives the samples as s 91 | // RLAPI void DetachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Detach audio stream processor from stream 92 | 93 | // RLAPI void AttachAudioMixedProcessor(AudioCallback processor); // Attach audio stream processor to the entire audio pipeline, receives the samples as s 94 | // RLAPI void DetachAudioMixedProcessor(AudioCallback processor); // Detach audio stream processor from the entire audio pipeline 95 | -------------------------------------------------------------------------------- /src/automation_events.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Automation event related functions 3 | * @module 4 | */ 5 | import { lib } from "../bindings/bindings.ts"; 6 | import { littleEndian } from "./_helper.ts"; 7 | 8 | /** Automation event functions */ 9 | export class AutomationEvent { 10 | #buffer: ArrayBuffer; 11 | /** Avoid using if at all possible */ 12 | constructor(buffer: ArrayBuffer) { 13 | this.#buffer = buffer; 14 | } 15 | 16 | play() { 17 | lib.symbols.PlayAutomationEvent(this.#buffer); 18 | } 19 | } 20 | 21 | /** Automation event list functions */ 22 | export class AutomationEventList { 23 | #buffer: Uint8Array; 24 | /** Load automation events list from file (supply nothing for an empty list) */ 25 | constructor(fileName?: string) { 26 | if (fileName) { 27 | this.#buffer = lib.symbols.LoadAutomationEventList( 28 | new TextEncoder().encode(fileName + "\0"), 29 | ); 30 | } else { 31 | this.#buffer = lib.symbols.LoadAutomationEventList(null); 32 | } 33 | } 34 | 35 | // TODO(lino-levan): Validate that this works 36 | get events(): AutomationEvent[] { 37 | const view = new DataView(this.#buffer.buffer); 38 | const count = view.getUint32(4, littleEndian); 39 | const elementView = new Deno.UnsafePointerView( 40 | Deno.UnsafePointer.create(view.getBigUint64(8)!)!, 41 | ); 42 | const events: AutomationEvent[] = []; 43 | for (let i = 0; i < count; i++) { 44 | events.push(new AutomationEvent(elementView.getArrayBuffer(24, 24 * i))); 45 | } 46 | return events; 47 | } 48 | 49 | /** Unload automation events list from file */ 50 | unload() { 51 | lib.symbols.UnloadAutomationEventList(Deno.UnsafePointer.of(this.#buffer)); 52 | } 53 | 54 | /** Export automation events list as text file. Returns true on success */ 55 | export(fileName: string): boolean { 56 | return !!lib.symbols.ExportAutomationEventList( 57 | this.#buffer, 58 | new TextEncoder().encode(fileName + "\0"), 59 | ); 60 | } 61 | 62 | /** Set automation event list to record to */ 63 | set() { 64 | lib.symbols.SetAutomationEventList(Deno.UnsafePointer.of(this.#buffer)); 65 | } 66 | 67 | /** Set automation event internal base frame to start recording */ 68 | static setBaseFrame(frame: number) { 69 | lib.symbols.SetAutomationEventBaseFrame(frame); 70 | } 71 | 72 | /** Start recording automation events (AutomationEventList must be set) */ 73 | static startRecording() { 74 | lib.symbols.StartAutomationEventRecording(); 75 | } 76 | 77 | /** Start recording automation events (AutomationEventList must be set) */ 78 | static stopRecording() { 79 | lib.symbols.StopAutomationEventRecording(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/camera3d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 3D Camera related functions 3 | * @module 4 | */ 5 | 6 | /** Automation event functions */ 7 | import { littleEndian } from "./_helper.ts"; 8 | import { Vector3 } from "./_util.ts"; 9 | 10 | /** A class to interact with a 3D camera */ 11 | export class Camera3D { 12 | position: Vector3; 13 | target: Vector3; 14 | up: Vector3; 15 | fovY: number; 16 | type: "PERSPECTIVE" | "ORTHOGRAPHIC"; 17 | constructor( 18 | options?: { 19 | /** Camera position */ 20 | position?: Vector3; 21 | /** Camera target (what it looks at) */ 22 | target?: Vector3; 23 | /** Camera up vector (rotation over its axis) */ 24 | up?: Vector3; 25 | /** Camera field-of-view aperture in Y (degrees) */ 26 | fovY?: number; 27 | /** Camera type, defines projection type */ 28 | type?: "PERSPECTIVE" | "ORTHOGRAPHIC"; 29 | }, 30 | ) { 31 | this.position = options?.position ?? new Vector3(0, 0, 0); 32 | this.target = options?.target ?? new Vector3(0, 1, 0); 33 | this.up = options?.up ?? new Vector3(0, 0, 1); 34 | this.fovY = options?.fovY ?? 90; 35 | this.type = options?.type ?? "PERSPECTIVE"; 36 | } 37 | 38 | get buffer(): ArrayBuffer { 39 | const view = new DataView(new ArrayBuffer(44)); 40 | view.setFloat32(0, this.position.x, littleEndian); 41 | view.setFloat32(4, this.position.y, littleEndian); 42 | view.setFloat32(8, this.position.z, littleEndian); 43 | view.setFloat32(12, this.target.x, littleEndian); 44 | view.setFloat32(16, this.target.y, littleEndian); 45 | view.setFloat32(20, this.target.z, littleEndian); 46 | view.setFloat32(24, this.up.x, littleEndian); 47 | view.setFloat32(28, this.up.y, littleEndian); 48 | view.setFloat32(32, this.up.z, littleEndian); 49 | view.setFloat32(36, this.fovY, littleEndian); 50 | view.setUint8(40, this.type === "PERSPECTIVE" ? 0 : 1); 51 | 52 | return view.buffer; 53 | } 54 | } 55 | 56 | // TODO(lino-levan): Consider if these are useful 57 | // RLAPI void UpdateCamera(Camera *camera, int mode); // Update camera position for selected mode 58 | // RLAPI void UpdateCameraPro(Camera *camera, Vector3 movement, Vector3 rotation, float zoom); // Update camera movement/rotation 59 | -------------------------------------------------------------------------------- /src/collision.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Collision related functions 3 | * @module 4 | */ 5 | import { lib } from "../bindings/bindings.ts"; 6 | 7 | import { 8 | type BoundingBox, 9 | type Matrix, 10 | type Ray, 11 | Rectangle, 12 | Vector2, 13 | Vector3, 14 | } from "./_util.ts"; 15 | import { concatVector2s, littleEndian } from "./_helper.ts"; 16 | import type { Mesh } from "./mesh.ts"; 17 | 18 | /** A class to simplift collision calculations */ 19 | export class Collision { 20 | /** Check collision between two rectangles */ 21 | static checkRectangles(rect1: Rectangle, rect2: Rectangle): boolean { 22 | return !!lib.symbols.CheckCollisionRecs(rect1.buffer, rect2.buffer); 23 | } 24 | 25 | /** Check collision between two circles */ 26 | static checkCircles( 27 | center1: Vector2, 28 | radius1: number, 29 | center2: Vector2, 30 | radius2: number, 31 | ): boolean { 32 | return !!lib.symbols.CheckCollisionCircles( 33 | center1.buffer, 34 | radius1, 35 | center2.buffer, 36 | radius2, 37 | ); 38 | } 39 | 40 | /** Check collision between circle and rectangle */ 41 | static checkCircleRectangle( 42 | center: Vector2, 43 | radius: number, 44 | rect: Rectangle, 45 | ): boolean { 46 | return !!lib.symbols.CheckCollisionCircleRec( 47 | center.buffer, 48 | radius, 49 | rect.buffer, 50 | ); 51 | } 52 | 53 | /** Check if point is inside rectangle */ 54 | static checkPointRectangle(point: Vector2, rect: Rectangle): boolean { 55 | return !!lib.symbols.CheckCollisionPointRec(point.buffer, rect.buffer); 56 | } 57 | 58 | /** Check if point is inside circle */ 59 | static checkPointCircle( 60 | point: Vector2, 61 | center: Vector2, 62 | radius: number, 63 | ): boolean { 64 | return !!lib.symbols.CheckCollisionPointCircle( 65 | point.buffer, 66 | center.buffer, 67 | radius, 68 | ); 69 | } 70 | 71 | /** Check if point is inside a triangle */ 72 | static checkPointTriangle( 73 | point: Vector2, 74 | p1: Vector2, 75 | p2: Vector2, 76 | p3: Vector2, 77 | ): boolean { 78 | return !!lib.symbols.CheckCollisionPointTriangle( 79 | point.buffer, 80 | p1.buffer, 81 | p2.buffer, 82 | p3.buffer, 83 | ); 84 | } 85 | 86 | /** Check if point is within a polygon described by array of vertices */ 87 | static checkPointPoly(point: Vector2, points: Vector2[]): boolean { 88 | const pointsBuffer = concatVector2s(points); 89 | return !!lib.symbols.CheckCollisionPointPoly( 90 | point.buffer, 91 | Deno.UnsafePointer.of(pointsBuffer), 92 | points.length, 93 | ); 94 | } 95 | 96 | /** Check the collision between two lines defined by two points each, returns collision point if found otherwise null */ 97 | static checkLines( 98 | startPos1: Vector2, 99 | endPos1: Vector2, 100 | startPos2: Vector2, 101 | endPos2: Vector2, 102 | ): Vector2 | null { 103 | const buffer = new Vector2(0, 0).buffer; 104 | 105 | if ( 106 | !lib.symbols.CheckCollisionLines( 107 | startPos1.buffer, 108 | endPos1.buffer, 109 | startPos2.buffer, 110 | endPos2.buffer, 111 | Deno.UnsafePointer.of(buffer), 112 | ) 113 | ) { 114 | return null; 115 | } 116 | 117 | return Vector2.fromBuffer(buffer); 118 | } 119 | 120 | /** Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold] */ 121 | static checkPointLine( 122 | point: Vector2, 123 | p1: Vector2, 124 | p2: Vector2, 125 | threshold: number, 126 | ): boolean { 127 | return !!lib.symbols.CheckCollisionPointLine( 128 | point.buffer, 129 | p1.buffer, 130 | p2.buffer, 131 | threshold, 132 | ); 133 | } 134 | 135 | /** Get collision rectangle for two rectangles collision */ 136 | static getRectangle(rect1: Rectangle, rect2: Rectangle): Rectangle { 137 | return Rectangle.fromBuffer( 138 | lib.symbols.GetCollisionRec(rect1.buffer, rect2.buffer).buffer, 139 | ); 140 | } 141 | 142 | /** Check collision between two spheres */ 143 | static checkSpheres( 144 | center1: Vector3, 145 | radius1: number, 146 | center2: Vector3, 147 | radius2: number, 148 | ): boolean { 149 | return !!lib.symbols.CheckCollisionSpheres( 150 | center1.buffer, 151 | radius1, 152 | center2.buffer, 153 | radius2, 154 | ); 155 | } 156 | 157 | /** Check collision between two bounding boxes */ 158 | static checkBoxes(box1: BoundingBox, box2: BoundingBox): boolean { 159 | return !!lib.symbols.CheckCollisionBoxes(box1.buffer, box2.buffer); 160 | } 161 | 162 | /** Check collision between box and sphere */ 163 | static checkBoxSphere( 164 | box: BoundingBox, 165 | center: Vector3, 166 | radius: number, 167 | ): boolean { 168 | return !!lib.symbols.CheckCollisionBoxSphere( 169 | box.buffer, 170 | center.buffer, 171 | radius, 172 | ); 173 | } 174 | 175 | /** Get collision info between ray and sphere */ 176 | static getRayCollisionSphere( 177 | ray: Ray, 178 | center: Vector3, 179 | radius: number, 180 | ): RayCollision { 181 | return new RayCollision( 182 | lib.symbols.GetRayCollisionSphere(ray.buffer, center.buffer, radius), 183 | ); 184 | } 185 | 186 | /** Get collision info between ray and box */ 187 | static getRayCollisionBox(ray: Ray, box: BoundingBox): RayCollision { 188 | return new RayCollision( 189 | lib.symbols.GetRayCollisionBox(ray.buffer, box.buffer), 190 | ); 191 | } 192 | 193 | /** Get collision info between ray and mesh */ 194 | static getRayCollisionMesh( 195 | ray: Ray, 196 | mesh: Mesh, 197 | transform: Matrix, 198 | ): RayCollision { 199 | return new RayCollision( 200 | lib.symbols.GetRayCollisionMesh( 201 | ray.buffer, 202 | mesh.buffer, 203 | transform.buffer, 204 | ), 205 | ); 206 | } 207 | 208 | /** Get collision info between ray and triangle */ 209 | static getRayCollisionTriangle( 210 | ray: Ray, 211 | p1: Vector3, 212 | p2: Vector3, 213 | p3: Vector3, 214 | ): RayCollision { 215 | return new RayCollision( 216 | lib.symbols.GetRayCollisionTriangle( 217 | ray.buffer, 218 | p1.buffer, 219 | p2.buffer, 220 | p3.buffer, 221 | ), 222 | ); 223 | } 224 | 225 | /** Get collision info between ray and quad */ 226 | static getRayCollisionQuad( 227 | ray: Ray, 228 | p1: Vector3, 229 | p2: Vector3, 230 | p3: Vector3, 231 | p4: Vector3, 232 | ): RayCollision { 233 | return new RayCollision( 234 | lib.symbols.GetRayCollisionQuad( 235 | ray.buffer, 236 | p1.buffer, 237 | p2.buffer, 238 | p3.buffer, 239 | p4.buffer, 240 | ), 241 | ); 242 | } 243 | } 244 | 245 | /** The result of a ray collision with something */ 246 | export class RayCollision { 247 | #buffer: Uint8Array; 248 | 249 | /** Avoid using this constructor directly. */ 250 | constructor(buffer: Uint8Array) { 251 | this.#buffer = buffer; 252 | } 253 | 254 | get buffer(): Uint8Array { 255 | return this.#buffer; 256 | } 257 | 258 | get hit(): boolean { 259 | return !!(new Uint8Array(this.#buffer)[0]); 260 | } 261 | 262 | get distance(): number { 263 | const view = new DataView(this.#buffer.buffer); 264 | return view.getFloat32(4, littleEndian); 265 | } 266 | 267 | get point(): Vector3 { 268 | return Vector3.fromBuffer(this.#buffer.slice(8, 20)); 269 | } 270 | 271 | get normal(): Vector3 { 272 | return Vector3.fromBuffer(this.#buffer.slice(20)); 273 | } 274 | } 275 | -------------------------------------------------------------------------------- /src/color.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Color-related functions 3 | * @module 4 | */ 5 | 6 | import { lib } from "../bindings/bindings.ts"; 7 | 8 | import { Vector3, Vector4 } from "./_util.ts"; 9 | 10 | export class Color { 11 | #buffer: Uint8Array; 12 | 13 | constructor(r: number, g: number, b: number, a: number) { 14 | this.#buffer = new Uint8Array([r, g, b, a]); 15 | } 16 | 17 | /** Unstable: only used internally */ 18 | get buffer(): Uint8Array { 19 | return this.#buffer; 20 | } 21 | 22 | /** Unstable: only used internally */ 23 | static fromBuffer(view: Uint8Array): Color { 24 | return new Color(view[0], view[1], view[2], view[3]); 25 | } 26 | 27 | /** Get Color from normalized values [0..1] */ 28 | static fromNormalized(normalized: Vector4): Color { 29 | return Color.fromBuffer( 30 | lib.symbols.ColorFromNormalized(normalized.buffer), 31 | ); 32 | } 33 | 34 | /** Get a Color from HSV values, hue [0..360], saturation/value [0..1] */ 35 | static fromHSV(hue: number, saturation: number, value: number): Color { 36 | return Color.fromBuffer( 37 | lib.symbols.ColorFromHSV(hue, saturation, value), 38 | ); 39 | } 40 | 41 | /** Get hexadecimal value for a Color */ 42 | toInt(): number { 43 | return lib.symbols.ColorToInt(this.#buffer); 44 | } 45 | 46 | /** Get HSV values for a Color, hue [0..360], saturation/value [0..1] */ 47 | toHSV(): Vector3 { 48 | return Vector3.fromBuffer(lib.symbols.ColorToHSV(this.#buffer)); 49 | } 50 | 51 | /** Get color with alpha applied, alpha goes from 0.0f to 1.0f */ 52 | fade(alpha: number): Color { 53 | return Color.fromBuffer(lib.symbols.Fade(this.#buffer, alpha)); 54 | } 55 | 56 | /** Get Color normalized as float [0..1] */ 57 | normalize(): Vector4 { 58 | return Vector4.fromBuffer(lib.symbols.ColorNormalize(this.#buffer).buffer); 59 | } 60 | 61 | /** Get color multiplied with another color */ 62 | tint(tint: Color): Color { 63 | return Color.fromBuffer( 64 | lib.symbols.ColorTint(this.#buffer, tint.#buffer), 65 | ); 66 | } 67 | 68 | /** Get color with brightness correction, brightness factor goes from -1.0f to 1.0f */ 69 | brightness(factor: number): Color { 70 | return Color.fromBuffer( 71 | lib.symbols.ColorBrightness(this.#buffer, factor), 72 | ); 73 | } 74 | 75 | /** Get color with contrast correction, contrast values between -1.0f and 1.0f */ 76 | contrast(factor: number): Color { 77 | return Color.fromBuffer( 78 | lib.symbols.ColorContrast(this.#buffer, factor), 79 | ); 80 | } 81 | 82 | /** Get color with alpha applied, alpha goes from 0.0f to 1.0f */ 83 | alpha(alpha: number): Color { 84 | return Color.fromBuffer(lib.symbols.ColorAlpha(this.#buffer, alpha)); 85 | } 86 | 87 | /** Get src alpha-blended into dst color with tint */ 88 | alphaBlend(src: Color, tint: Color): Color { 89 | return Color.fromBuffer( 90 | lib.symbols.ColorAlphaBlend(this.#buffer, src.#buffer, tint.#buffer), 91 | ); 92 | } 93 | } 94 | 95 | // TODO 96 | // RLAPI Color GetPixelColor(void *srcPtr, int format); // Get Color from a source pixel pointer of certain format 97 | // RLAPI void SetPixelColor(void *dstPtr, Color color, int format); // Set color formatted into destination pixel pointer 98 | // RLAPI int GetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes for certain format 99 | 100 | export const LIGHTGRAY: Color = new Color(200, 200, 200, 255); 101 | export const GRAY: Color = new Color(130, 130, 130, 255); 102 | export const DARKGRAY: Color = new Color(80, 80, 80, 255); 103 | export const YELLOW: Color = new Color(253, 249, 0, 255); 104 | export const GOLD: Color = new Color(255, 203, 0, 255); 105 | export const ORANGE: Color = new Color(255, 161, 0, 255); 106 | export const PINK: Color = new Color(255, 109, 194, 255); 107 | export const RED: Color = new Color(230, 41, 55, 255); 108 | export const MAROON: Color = new Color(190, 33, 55, 255); 109 | export const GREEN: Color = new Color(0, 228, 48, 255); 110 | export const LIME: Color = new Color(0, 158, 47, 255); 111 | export const DARKGREEN: Color = new Color(0, 117, 44, 255); 112 | export const SKYBLUE: Color = new Color(102, 191, 255, 255); 113 | export const BLUE: Color = new Color(0, 121, 241, 255); 114 | export const DARKBLUE: Color = new Color(0, 82, 172, 255); 115 | export const PURPLE: Color = new Color(200, 122, 255, 255); 116 | export const VIOLET: Color = new Color(135, 60, 190, 255); 117 | export const DARKPURPLE: Color = new Color(112, 31, 126, 255); 118 | export const BEIGE: Color = new Color(211, 176, 131, 255); 119 | export const BROWN: Color = new Color(127, 106, 79, 255); 120 | export const DARKBROWN: Color = new Color(76, 63, 47, 255); 121 | export const WHITE: Color = new Color(255, 255, 255, 255); 122 | export const BLACK: Color = new Color(0, 0, 0, 255); 123 | export const BLANK: Color = new Color(0, 0, 0, 0); 124 | export const MAGENTA: Color = new Color(255, 0, 255, 255); 125 | export const RAYWHITE: Color = new Color(245, 245, 245, 255); 126 | -------------------------------------------------------------------------------- /src/cursor.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Cursor-related functions 3 | * @module 4 | */ 5 | 6 | import { lib } from "../bindings/bindings.ts"; 7 | 8 | /** A simple class for interacting with the cursor */ 9 | export class Cursor { 10 | /** Shows cursor */ 11 | static show() { 12 | lib.symbols.ShowCursor(); 13 | } 14 | 15 | /** Hides cursor */ 16 | static hide() { 17 | lib.symbols.HideCursor(); 18 | } 19 | 20 | /** Check if cursor is not visible */ 21 | static isHidden(): boolean { 22 | return !!lib.symbols.IsCursorHidden(); 23 | } 24 | 25 | /** Enables cursor (unlock cursor) */ 26 | static enable() { 27 | lib.symbols.EnableCursor(); 28 | } 29 | 30 | /** Disables cursor (lock cursor) */ 31 | static disable() { 32 | lib.symbols.DisableCursor(); 33 | } 34 | 35 | /** Check if cursor is on the current screen. */ 36 | static isOnScreen(): boolean { 37 | return !!lib.symbols.IsCursorOnScreen(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/drawing.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Drawing-related functions 3 | * @module 4 | */ 5 | 6 | import { lib } from "../bindings/bindings.ts"; 7 | import type { Color } from "./color.ts"; 8 | import type { Camera3D } from "./camera3d.ts"; 9 | import type { Camera2D } from "./_util.ts"; 10 | 11 | export class Drawing { 12 | /** Set background color (framebuffer clear color) */ 13 | static clearBackground(color: Color) { 14 | lib.symbols.ClearBackground(color.buffer); 15 | } 16 | 17 | /** Setup canvas (framebuffer) to start drawing */ 18 | static beginDrawing() { 19 | lib.symbols.BeginDrawing(); 20 | } 21 | 22 | /** End canvas drawing and swap buffers (double buffering) */ 23 | static endDrawing() { 24 | lib.symbols.EndDrawing(); 25 | } 26 | 27 | /** Initialize 2D mode with custom camera (2D) */ 28 | static beginMode2D(camera: Camera2D) { 29 | lib.symbols.BeginMode2D(camera.buffer); 30 | } 31 | 32 | /** Ends 2D mode with custom camera */ 33 | static endMode2D() { 34 | lib.symbols.EndMode2D(); 35 | } 36 | 37 | /** Initializes 3D mode with custom camera (3D) */ 38 | static beginMode3D(camera: Camera3D) { 39 | lib.symbols.BeginMode3D(camera.buffer); 40 | } 41 | 42 | /** Ends 3D mode and returns to default 2D orthographic mode */ 43 | static endMode3D() { 44 | lib.symbols.EndMode3D(); 45 | } 46 | } 47 | 48 | // TODO(lino-levan): The rest of these 49 | // RLAPI void BeginTextureMode(RenderTexture2D target); // Begin drawing to render texture 50 | // RLAPI void EndTextureMode(void); // Ends drawing to render texture 51 | // RLAPI void BeginShaderMode(Shader shader); // Begin custom shader drawing 52 | // RLAPI void EndShaderMode(void); // End custom shader drawing (use default shader) 53 | // RLAPI void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied, subtract, custom) 54 | // RLAPI void EndBlendMode(void); // End blending mode (reset to default: alpha blending) 55 | // RLAPI void BeginScissorMode(int x, int y, int width, int height); // Begin scissor mode (define screen area for following drawing) 56 | // RLAPI void EndScissorMode(void); // End scissor mode 57 | // RLAPI void BeginVrStereoMode(VrStereoConfig config); // Begin stereo rendering (requires VR simulator) 58 | // RLAPI void EndVrStereoMode(void); // End stereo rendering (requires VR simulator) 59 | -------------------------------------------------------------------------------- /src/file_drop.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * File drop functions 3 | * @module 4 | */ 5 | import { lib } from "../bindings/bindings.ts"; 6 | import { littleEndian } from "./_helper.ts"; 7 | 8 | export class FileDrop { 9 | static isFileDropped(): boolean { 10 | return !!lib.symbols.IsFileDropped(); 11 | } 12 | 13 | static loadDroppedFiles(): string[] { 14 | const result = lib.symbols.LoadDroppedFiles(); 15 | const view = new DataView(result.buffer); 16 | const length = view.getUint32(4, littleEndian); 17 | const pointer = Deno.UnsafePointer.create( 18 | view.getBigInt64(8, littleEndian), 19 | ); 20 | const pointerView = new Deno.UnsafePointerView(pointer!); 21 | 22 | const list: string[] = []; 23 | for (let i = 0; i < length; i++) { 24 | const stringPointer = pointerView.getPointer(i * 8); 25 | const stringView = new Deno.UnsafePointerView(stringPointer!); 26 | list.push(stringView.getCString()); 27 | } 28 | 29 | lib.symbols.UnloadDroppedFiles(result); // Clean up memory 30 | 31 | return list; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/font.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Font utility functions 3 | * @module 4 | */ 5 | import { lib } from "../bindings/bindings.ts"; 6 | 7 | /** Font loading/unloading functions */ 8 | export class Font { 9 | #buffer: Uint8Array; 10 | 11 | /** Avoid using this constructor directly. */ 12 | constructor(buffer: Uint8Array) { 13 | this.#buffer = buffer; 14 | } 15 | 16 | get buffer(): Uint8Array { 17 | return this.#buffer; 18 | } 19 | 20 | /** Get the default Font */ 21 | static getDefault(): Font { 22 | return new Font(lib.symbols.GetFontDefault()); 23 | } 24 | 25 | /** Load font from file into GPU memory (VRAM) */ 26 | static load(fileName: string): Font { 27 | const encodedFileName = new TextEncoder().encode(fileName + "\0"); 28 | return new Font(lib.symbols.LoadFont(encodedFileName)); 29 | } 30 | 31 | /** Load font from file with extended parameters, use null for codepoints and 0 for codepointCount to load the default character set */ 32 | static loadEx( 33 | fileName: string, 34 | fontSize: number, 35 | options?: { codepoints: number[] }, 36 | ): Font { 37 | const codepoints = options?.codepoints 38 | ? Deno.UnsafePointer.of(new Uint32Array(options.codepoints)) 39 | : null; 40 | const encodedFileName = new TextEncoder().encode(fileName + "\0"); 41 | return new Font( 42 | lib.symbols.LoadFontEx( 43 | encodedFileName, 44 | fontSize, 45 | codepoints, 46 | options?.codepoints?.length ?? 0, 47 | ), 48 | ); 49 | } 50 | 51 | /** Check if a font is ready */ 52 | isReady(): boolean { 53 | return !!lib.symbols.IsFontReady(this.#buffer); 54 | } 55 | 56 | /** Unload Font from GPU memory (VRAM) */ 57 | unload(): void { 58 | lib.symbols.UnloadFont(this.#buffer); 59 | } 60 | 61 | /** Export font as code file, returns true on success */ 62 | exportAsCode(fileName: string): boolean { 63 | const encodedFileName = new TextEncoder().encode(fileName + "\0"); 64 | return !!lib.symbols.ExportFontAsCode(this.#buffer, encodedFileName); 65 | } 66 | } 67 | 68 | // TODO 69 | // RLAPI Font LoadFontFromImage(Image image, Color key, int firstChar); // Load font from Image (XNA style) 70 | // RLAPI Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *codepoints, int codepointCount); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf' 71 | // RLAPI GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *codepoints, int codepointCount, int type); // Load font data for further use 72 | // RLAPI Image GenImageFontAtlas(const GlyphInfo *glyphs, Rectangle **glyphRecs, int glyphCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info 73 | // RLAPI void UnloadFontData(GlyphInfo *glyphs, int glyphCount); // Unload font chars info data (RAM) 74 | -------------------------------------------------------------------------------- /src/gamepad.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Gamepad utility functions 3 | * @module 4 | */ 5 | import { lib } from "../bindings/bindings.ts"; 6 | 7 | /** Gamepad functions */ 8 | export class Gamepad { 9 | /** Check if a gamepad is available */ 10 | static isAvailable(gamepad: number): boolean { 11 | return !!lib.symbols.IsGamepadAvailable(gamepad); 12 | } 13 | 14 | /** Get gamepad internal name id */ 15 | static getName(gamepad: number): string { 16 | return new Deno.UnsafePointerView(lib.symbols.GetGamepadName(gamepad)!) 17 | .getCString(); 18 | } 19 | 20 | /** Check if a gamepad button has been pressed once */ 21 | static isButtonPressed(gamepad: number, button: number): boolean { 22 | return !!lib.symbols.IsGamepadButtonPressed(gamepad, button); 23 | } 24 | 25 | /** Check if a gamepad button is being pressed */ 26 | static isButtonDown(gamepad: number, button: number): boolean { 27 | return !!lib.symbols.IsGamepadButtonDown(gamepad, button); 28 | } 29 | 30 | /** Check if a gamepad button has been released once */ 31 | static isButtonReleased(gamepad: number, button: number): boolean { 32 | return !!lib.symbols.IsGamepadButtonReleased(gamepad, button); 33 | } 34 | 35 | /** Check if a gamepad button is being pressed */ 36 | static isButtonUp(gamepad: number, button: number): boolean { 37 | return !!lib.symbols.IsGamepadButtonUp(gamepad, button); 38 | } 39 | 40 | /** Get the last gamepad button pressed */ 41 | static getButtonPressed(): number { 42 | return lib.symbols.GetGamepadButtonPressed(); 43 | } 44 | 45 | /** Get gamepad axis count for a gamepad */ 46 | static getAxisCount(gamepad: number): number { 47 | return lib.symbols.GetGamepadAxisCount(gamepad); 48 | } 49 | 50 | /** Get gamepad axis count for a gamepad */ 51 | static getAxisMovement(gamepad: number, axis: number): number { 52 | return lib.symbols.GetGamepadAxisMovement(gamepad, axis); 53 | } 54 | 55 | /** Set internal gamepad mappings (SDL_GameControllerDB) */ 56 | static setMappings(mappings: string): number { 57 | return lib.symbols.SetGamepadMappings( 58 | new TextEncoder().encode(mappings + "\0"), 59 | ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/gesture.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Gesture functions 3 | * @module 4 | */ 5 | import { lib } from "../bindings/bindings.ts"; 6 | import { Vector2 } from "./_util.ts"; 7 | 8 | const gestureFlags = { 9 | none: 0, 10 | tap: 1, 11 | doubleTap: 2, 12 | hold: 4, 13 | drag: 8, 14 | swipeRight: 16, 15 | swipeLeft: 32, 16 | swipeUp: 64, 17 | swipeDown: 128, 18 | pinchIn: 256, 19 | pinchOut: 512, 20 | }; 21 | 22 | /** Different gestures to be enabled or disabled */ 23 | export interface GestureFlags { 24 | /** No gesture */ 25 | none?: boolean; 26 | /** Tap gesture */ 27 | tap?: boolean; 28 | /** Double tap gesture */ 29 | doubleTap?: boolean; 30 | /** Hold gesture */ 31 | hold?: boolean; 32 | /** Drag gesture */ 33 | drag?: boolean; 34 | /** Swipe right gesture */ 35 | swipeRight?: boolean; 36 | /** Swipe left gesture */ 37 | swipeLeft?: boolean; 38 | /** Swipe up gesture */ 39 | swipeUp?: boolean; 40 | /** Swipe down gesture */ 41 | swipeDown?: boolean; 42 | /** Pinch in gesture */ 43 | pinchIn?: boolean; 44 | /** Pinch out gesture */ 45 | pinchOut?: boolean; 46 | } 47 | 48 | /** A simple class for interacting with gestures */ 49 | export class Gesture { 50 | /** Enable a set of gestures using flags */ 51 | static setEnabled(flags: GestureFlags) { 52 | const flag = Object.keys(flags).reduce((acc, key) => { 53 | return acc | gestureFlags[key as keyof GestureFlags]; 54 | }, 0); 55 | lib.symbols.SetGesturesEnabled(flag); 56 | } 57 | 58 | /** Check if a gesture have been detected */ 59 | isDetected(gesture: keyof GestureFlags): boolean { 60 | return !!lib.symbols.IsGestureDetected(gestureFlags[gesture]); 61 | } 62 | 63 | /** Get latest detected gesture */ 64 | getDetected(): keyof GestureFlags { 65 | const result = lib.symbols.GetGestureDetected(); 66 | for (const [key, value] of Object.entries(gestureFlags)) { 67 | if (result === value) { 68 | return key as keyof GestureFlags; 69 | } 70 | } 71 | 72 | // TODO(lino-levan): verify this is the correct behavior 73 | throw new Error("Unreachable"); 74 | } 75 | 76 | /** Get gesture hold time in milliseconds */ 77 | getHoldDuration(): number { 78 | return lib.symbols.GetGestureHoldDuration(); 79 | } 80 | 81 | /** Get gesture drag vector */ 82 | getDragVector(): Vector2 { 83 | return Vector2.fromBuffer(lib.symbols.GetGestureDragVector().buffer); 84 | } 85 | 86 | /** Get gesture drag angle */ 87 | getDragAngle(): number { 88 | return lib.symbols.GetGestureDragAngle(); 89 | } 90 | 91 | /** Get gesture pinch delta */ 92 | getPinchVector(): Vector2 { 93 | return Vector2.fromBuffer(lib.symbols.GetGesturePinchVector().buffer); 94 | } 95 | 96 | /** Get gesture pinch angle */ 97 | getPinchingAngle(): number { 98 | return lib.symbols.GetGesturePinchAngle(); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/image.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Image utility functions 3 | * @module 4 | */ 5 | import { lib } from "../bindings/bindings.ts"; 6 | import type { Font } from "./font.ts"; 7 | import { Color } from "./color.ts"; 8 | import { Rectangle, type Vector2 } from "./_util.ts"; 9 | import type { Texture2D } from "./texture.ts"; 10 | import { littleEndian } from "./_helper.ts"; 11 | 12 | /** Image functions */ 13 | export class Image { 14 | #buffer: Uint8Array; 15 | 16 | /** Avoid using if possible */ 17 | constructor(buffer: Uint8Array) { 18 | this.#buffer = buffer; 19 | } 20 | 21 | get buffer(): Uint8Array { 22 | return this.#buffer; 23 | } 24 | 25 | get width(): number { 26 | const view = new DataView(this.#buffer.buffer); 27 | return view.getInt32(8, littleEndian); 28 | } 29 | 30 | get height(): number { 31 | const view = new DataView(this.#buffer.buffer); 32 | return view.getInt32(12, littleEndian); 33 | } 34 | 35 | /** Load image from file into CPU memory (RAM) */ 36 | static load(fileName: string): Image { 37 | const encodedFileName = new TextEncoder().encode(fileName + "\0"); 38 | return new Image(lib.symbols.LoadImage(encodedFileName)); 39 | } 40 | 41 | /** Load image from RAW file data */ 42 | static loadRaw( 43 | fileName: string, 44 | width: number, 45 | height: number, 46 | format: number, 47 | headerSize: number, 48 | ): Image { 49 | const encodedFileName = new TextEncoder().encode(fileName + "\0"); 50 | return new Image( 51 | lib.symbols.LoadImageRaw( 52 | encodedFileName, 53 | width, 54 | height, 55 | format, 56 | headerSize, 57 | ), 58 | ); 59 | } 60 | 61 | /** Load image from SVG file data or string with specified size */ 62 | static loadSvg( 63 | fileNameOrString: string, 64 | width: number, 65 | height: number, 66 | ): Image { 67 | const encodedFileNameOrString = new TextEncoder().encode( 68 | fileNameOrString + "\0", 69 | ); 70 | return new Image( 71 | lib.symbols.LoadImageSvg( 72 | encodedFileNameOrString, 73 | width, 74 | height, 75 | ), 76 | ); 77 | } 78 | 79 | /** Load image from memory buffer, fileType refers to extension: i.e. '.png' */ 80 | static loadFromMemory(fileType: string, fileData: Uint8Array): Image { 81 | const encodedFileType = new TextEncoder().encode(fileType + "\0"); 82 | return new Image( 83 | lib.symbols.LoadImageFromMemory( 84 | encodedFileType, 85 | Deno.UnsafePointer.of(fileData), 86 | fileData.length, 87 | ), 88 | ); 89 | } 90 | 91 | /** Load image from GPU texture data */ 92 | static loadFromTexture(texture: Texture2D): Image { 93 | return new Image(lib.symbols.LoadImageFromTexture(texture.buffer)); 94 | } 95 | 96 | /** Load image from screen buffer and (screenshot) */ 97 | static loadFromScreen(): Image { 98 | return new Image(lib.symbols.LoadImageFromScreen()); 99 | } 100 | 101 | /** Check if an image is ready */ 102 | isReady(): boolean { 103 | return !!lib.symbols.IsImageReady(this.#buffer); 104 | } 105 | 106 | /** Unload image from CPU memory (RAM) */ 107 | unload(): void { 108 | lib.symbols.UnloadImage(this.#buffer); 109 | } 110 | 111 | /** Export image data to file, returns true on success */ 112 | export(fileName: string): boolean { 113 | const encodedFileName = new TextEncoder().encode(fileName + "\0"); 114 | return !!lib.symbols.ExportImage(this.#buffer, encodedFileName); 115 | } 116 | 117 | /** Export image as code file defining an array of bytes, returns true on success */ 118 | exportAsCode(fileName: string): boolean { 119 | const encodedFileName = new TextEncoder().encode(fileName + "\0"); 120 | return !!lib.symbols.ExportImageAsCode(this.#buffer, encodedFileName); 121 | } 122 | 123 | /** Generate image: plain color */ 124 | static genColor(width: number, height: number, color: Color): Image { 125 | return new Image(lib.symbols.GenImageColor(width, height, color.buffer)); 126 | } 127 | 128 | /** Generate image: linear gradient, direction in degrees [0..360], 0=Vertical gradient */ 129 | static genGradientLinear( 130 | width: number, 131 | height: number, 132 | direction: number, 133 | start: Color, 134 | end: Color, 135 | ): Image { 136 | return new Image( 137 | lib.symbols.GenImageGradientLinear( 138 | width, 139 | height, 140 | direction, 141 | start.buffer, 142 | end.buffer, 143 | ), 144 | ); 145 | } 146 | 147 | /** Generate image: radial gradient */ 148 | static genGradientRadial( 149 | width: number, 150 | height: number, 151 | density: number, 152 | inner: Color, 153 | outer: Color, 154 | ): Image { 155 | return new Image( 156 | lib.symbols.GenImageGradientRadial( 157 | width, 158 | height, 159 | density, 160 | inner.buffer, 161 | outer.buffer, 162 | ), 163 | ); 164 | } 165 | 166 | /** Generate image: square gradient */ 167 | static genGradientSquare( 168 | width: number, 169 | height: number, 170 | density: number, 171 | inner: Color, 172 | outer: Color, 173 | ): Image { 174 | return new Image( 175 | lib.symbols.GenImageGradientSquare( 176 | width, 177 | height, 178 | density, 179 | inner.buffer, 180 | outer.buffer, 181 | ), 182 | ); 183 | } 184 | 185 | /** Generate image: checked */ 186 | static genChecked( 187 | width: number, 188 | height: number, 189 | checksX: number, 190 | checksY: number, 191 | col1: Color, 192 | col2: Color, 193 | ): Image { 194 | return new Image( 195 | lib.symbols.GenImageChecked( 196 | width, 197 | height, 198 | checksX, 199 | checksY, 200 | col1.buffer, 201 | col2.buffer, 202 | ), 203 | ); 204 | } 205 | 206 | /** Generate image: white noise */ 207 | static genWhiteNoise(width: number, height: number, factor: number): Image { 208 | return new Image(lib.symbols.GenImageWhiteNoise(width, height, factor)); 209 | } 210 | 211 | /** Generate image: perlin noise */ 212 | static genPerlinNoise( 213 | width: number, 214 | height: number, 215 | offsetX: number, 216 | offsetY: number, 217 | scale: number, 218 | ): Image { 219 | return new Image( 220 | lib.symbols.GenImagePerlinNoise(width, height, offsetX, offsetY, scale), 221 | ); 222 | } 223 | 224 | /** Generate image: cellular algorithm. Bigger tileSize means bigger cells */ 225 | static genCellular(width: number, height: number, tileSize: number): Image { 226 | return new Image(lib.symbols.GenImageCellular(width, height, tileSize)); 227 | } 228 | 229 | /** Generate image: grayscale image from text data */ 230 | static genText(width: number, height: number, text: string): Image { 231 | const encodedText = new TextEncoder().encode(text + "\0"); 232 | return new Image(lib.symbols.GenImageText(width, height, encodedText)); 233 | } 234 | 235 | /** Create an image duplicate (useful for transformations) */ 236 | copy(): Image { 237 | return new Image(lib.symbols.ImageCopy(this.#buffer)); 238 | } 239 | 240 | /** Create an image from another image piece */ 241 | fromImage(rect: Rectangle): Image { 242 | return new Image(lib.symbols.ImageFromImage(this.#buffer, rect.buffer)); 243 | } 244 | 245 | /** Create an image from text (default font) */ 246 | static text(text: string, fontSize: number, color: Color): Image { 247 | const encodedText = new TextEncoder().encode(text + "\0"); 248 | return new Image( 249 | lib.symbols.ImageText(encodedText, fontSize, color.buffer), 250 | ); 251 | } 252 | 253 | /** Create an image from text (custom sprite font) */ 254 | static textEx( 255 | font: Font, 256 | text: string, 257 | fontSize: number, 258 | spacing: number, 259 | tint: Color, 260 | ): Image { 261 | const encodedText = new TextEncoder().encode(text + "\0"); 262 | return new Image( 263 | lib.symbols.ImageTextEx( 264 | font.buffer, 265 | encodedText, 266 | fontSize, 267 | spacing, 268 | tint.buffer, 269 | ), 270 | ); 271 | } 272 | 273 | /** Draw a source image within a destination image */ 274 | format(newFormat: number): void { 275 | lib.symbols.ImageFormat(Deno.UnsafePointer.of(this.#buffer), newFormat); 276 | } 277 | 278 | /** Convert image to POT (power-of-two) */ 279 | toPOT(fill: Color): void { 280 | lib.symbols.ImageToPOT(Deno.UnsafePointer.of(this.#buffer), fill.buffer); 281 | } 282 | 283 | /** Crop an image to a defined rectangle */ 284 | crop(rect: Rectangle): void { 285 | lib.symbols.ImageCrop(Deno.UnsafePointer.of(this.#buffer), rect.buffer); 286 | } 287 | 288 | /** Crop image depending on alpha value */ 289 | alphaCrop(threshold: number): void { 290 | lib.symbols.ImageAlphaCrop(Deno.UnsafePointer.of(this.#buffer), threshold); 291 | } 292 | 293 | /** Clear alpha channel to desired color */ 294 | alphaClear(color: Color, threshold: number): void { 295 | lib.symbols.ImageAlphaClear( 296 | Deno.UnsafePointer.of(this.#buffer), 297 | color.buffer, 298 | threshold, 299 | ); 300 | } 301 | 302 | /** Apply alpha mask to image */ 303 | alphaMask(alphaMask: Image): void { 304 | lib.symbols.ImageAlphaMask( 305 | Deno.UnsafePointer.of(this.#buffer), 306 | alphaMask.buffer, 307 | ); 308 | } 309 | 310 | /** Premultiply alpha channel */ 311 | alphaPremultiply(): void { 312 | lib.symbols.ImageAlphaPremultiply(Deno.UnsafePointer.of(this.#buffer)); 313 | } 314 | 315 | /** Apply Gaussian blur using a box blur approximation */ 316 | blurGaussian(blurSize: number): void { 317 | lib.symbols.ImageBlurGaussian( 318 | Deno.UnsafePointer.of(this.#buffer), 319 | blurSize, 320 | ); 321 | } 322 | 323 | /** Resize image (Bicubic scaling algorithm) */ 324 | resize(newWidth: number, newHeight: number): void { 325 | lib.symbols.ImageResize( 326 | Deno.UnsafePointer.of(this.#buffer), 327 | newWidth, 328 | newHeight, 329 | ); 330 | } 331 | 332 | /** Resize image (Nearest-Neighbor scaling algorithm) */ 333 | resizeNN(newWidth: number, newHeight: number): void { 334 | lib.symbols.ImageResizeNN( 335 | Deno.UnsafePointer.of(this.#buffer), 336 | newWidth, 337 | newHeight, 338 | ); 339 | } 340 | 341 | /** Resize canvas and fill with color */ 342 | resizeCanvas( 343 | newWidth: number, 344 | newHeight: number, 345 | offsetX: number, 346 | offsetY: number, 347 | fill: Color, 348 | ): void { 349 | lib.symbols.ImageResizeCanvas( 350 | Deno.UnsafePointer.of(this.#buffer), 351 | newWidth, 352 | newHeight, 353 | offsetX, 354 | offsetY, 355 | fill.buffer, 356 | ); 357 | } 358 | 359 | /** Generate all mipmap levels for a provided image */ 360 | mipmaps(): void { 361 | lib.symbols.ImageMipmaps(Deno.UnsafePointer.of(this.#buffer)); 362 | } 363 | 364 | /** Dither image data to 16bpp or lower (Floyd-Steinberg dithering) */ 365 | dither(rBpp: number, gBpp: number, bBpp: number, aBpp: number): void { 366 | lib.symbols.ImageDither( 367 | Deno.UnsafePointer.of(this.#buffer), 368 | rBpp, 369 | gBpp, 370 | bBpp, 371 | aBpp, 372 | ); 373 | } 374 | 375 | /** Flip image vertically */ 376 | flipVertical(): void { 377 | lib.symbols.ImageFlipVertical(Deno.UnsafePointer.of(this.#buffer)); 378 | } 379 | 380 | /** Flip image horizontally */ 381 | flipHorizontal(): void { 382 | lib.symbols.ImageFlipHorizontal(Deno.UnsafePointer.of(this.#buffer)); 383 | } 384 | 385 | /** Rotate image by input angle in degrees (-359 to 359) */ 386 | rotate(degrees: number): void { 387 | lib.symbols.ImageRotate(Deno.UnsafePointer.of(this.#buffer), degrees); 388 | } 389 | 390 | /** Rotate image clockwise 90deg */ 391 | rotateCW(): void { 392 | lib.symbols.ImageRotateCW(Deno.UnsafePointer.of(this.#buffer)); 393 | } 394 | 395 | /** Rotate image counter-clockwise 90deg */ 396 | rotateCCW(): void { 397 | lib.symbols.ImageRotateCCW(Deno.UnsafePointer.of(this.#buffer)); 398 | } 399 | 400 | /** Modify image color: tint */ 401 | colorTint(color: Color): void { 402 | lib.symbols.ImageColorTint( 403 | Deno.UnsafePointer.of(this.#buffer), 404 | color.buffer, 405 | ); 406 | } 407 | 408 | /** Modify image color: invert */ 409 | colorInvert(): void { 410 | lib.symbols.ImageColorInvert(Deno.UnsafePointer.of(this.#buffer)); 411 | } 412 | 413 | /** Modify image color: grayscale */ 414 | colorGrayscale(): void { 415 | lib.symbols.ImageColorGrayscale(Deno.UnsafePointer.of(this.#buffer)); 416 | } 417 | 418 | /** Modify image color: contrast (-100 to 100) */ 419 | colorContrast(contrast: number): void { 420 | lib.symbols.ImageColorContrast( 421 | Deno.UnsafePointer.of(this.#buffer), 422 | contrast, 423 | ); 424 | } 425 | 426 | /** Modify image color: brightness (-255 to 255) */ 427 | colorBrightness(brightness: number): void { 428 | lib.symbols.ImageColorBrightness( 429 | Deno.UnsafePointer.of(this.#buffer), 430 | brightness, 431 | ); 432 | } 433 | 434 | /** Modify image color: replace color */ 435 | colorReplace(color: Color, replace: Color): void { 436 | lib.symbols.ImageColorReplace( 437 | Deno.UnsafePointer.of(this.#buffer), 438 | color.buffer, 439 | replace.buffer, 440 | ); 441 | } 442 | 443 | /** Load color data from image as a Color array (RGBA - 32bit) */ 444 | loadColors(): Color[] { 445 | const colors = lib.symbols.LoadImageColors(this.#buffer); 446 | const colorsView = new Deno.UnsafePointerView(colors!); 447 | const result: Color[] = []; 448 | for (let i = 0; i < this.width * this.height; i++) { 449 | result.push( 450 | new Color( 451 | colorsView.getUint8(i * 4), 452 | colorsView.getUint8(i * 4 + 1), 453 | colorsView.getUint8(i * 4 + 2), 454 | colorsView.getUint8(i * 4 + 3), 455 | ), 456 | ); 457 | } 458 | lib.symbols.UnloadImageColors(colors); 459 | return result; 460 | } 461 | 462 | /** Load colors palette from image as a Color array (RGBA - 32bit) */ 463 | loadPalette(maxPaletteSize: number): Color[] { 464 | const colorCount = new Uint32Array(1); 465 | const colors = lib.symbols.LoadImagePalette( 466 | this.#buffer, 467 | maxPaletteSize, 468 | Deno.UnsafePointer.of(colorCount), 469 | ); 470 | const colorsView = new Deno.UnsafePointerView(colors!); 471 | const result: Color[] = []; 472 | for (let i = 0; i < colorCount[0]; i++) { 473 | result.push( 474 | new Color( 475 | colorsView.getUint8(i * 4), 476 | colorsView.getUint8(i * 4 + 1), 477 | colorsView.getUint8(i * 4 + 2), 478 | colorsView.getUint8(i * 4 + 3), 479 | ), 480 | ); 481 | } 482 | lib.symbols.UnloadImagePalette(colors); 483 | return result; 484 | } 485 | 486 | /** Get image alpha border rectangle */ 487 | getAlphaBorder(threshold: number): Rectangle { 488 | return Rectangle.fromBuffer( 489 | lib.symbols.GetImageAlphaBorder(this.#buffer, threshold).buffer, 490 | ); 491 | } 492 | 493 | /** Get image color at pixel position */ 494 | getColor(x: number, y: number): Color { 495 | return Color.fromBuffer( 496 | lib.symbols.GetImageColor(this.#buffer, x, y), 497 | ); 498 | } 499 | 500 | /** Clear image background with given color */ 501 | clearBackground(color: Color): void { 502 | lib.symbols.ImageClearBackground( 503 | Deno.UnsafePointer.of(this.#buffer), 504 | color.buffer, 505 | ); 506 | } 507 | 508 | /** Draw pixel within an image */ 509 | drawPixel(posX: number, posY: number, color: Color): void { 510 | lib.symbols.ImageDrawPixel( 511 | Deno.UnsafePointer.of(this.#buffer), 512 | posX, 513 | posY, 514 | color.buffer, 515 | ); 516 | } 517 | 518 | /** Draw pixel within an image (Vector version) */ 519 | drawPixelV(position: Vector2, color: Color): void { 520 | lib.symbols.ImageDrawPixelV( 521 | Deno.UnsafePointer.of(this.#buffer), 522 | position.buffer, 523 | color.buffer, 524 | ); 525 | } 526 | 527 | /** Draw line within an image */ 528 | drawLine( 529 | startPosX: number, 530 | startPosY: number, 531 | endPosX: number, 532 | endPosY: number, 533 | color: Color, 534 | ): void { 535 | lib.symbols.ImageDrawLine( 536 | Deno.UnsafePointer.of(this.#buffer), 537 | startPosX, 538 | startPosY, 539 | endPosX, 540 | endPosY, 541 | color.buffer, 542 | ); 543 | } 544 | 545 | /** Draw line within an image (Vector version) */ 546 | drawLineV(start: Vector2, end: Vector2, color: Color): void { 547 | lib.symbols.ImageDrawLineV( 548 | Deno.UnsafePointer.of(this.#buffer), 549 | start.buffer, 550 | end.buffer, 551 | color.buffer, 552 | ); 553 | } 554 | 555 | /** Draw circle within an image */ 556 | drawCircle( 557 | centerX: number, 558 | centerY: number, 559 | radius: number, 560 | color: Color, 561 | ): void { 562 | lib.symbols.ImageDrawCircle( 563 | Deno.UnsafePointer.of(this.#buffer), 564 | centerX, 565 | centerY, 566 | radius, 567 | color.buffer, 568 | ); 569 | } 570 | 571 | /** Draw circle within an image (Vector version) */ 572 | drawCircleV(center: Vector2, radius: number, color: Color): void { 573 | lib.symbols.ImageDrawCircleV( 574 | Deno.UnsafePointer.of(this.#buffer), 575 | center.buffer, 576 | radius, 577 | color.buffer, 578 | ); 579 | } 580 | 581 | /** Draw circle outline within an image */ 582 | drawCircleLines( 583 | centerX: number, 584 | centerY: number, 585 | radius: number, 586 | color: Color, 587 | ): void { 588 | lib.symbols.ImageDrawCircleLines( 589 | Deno.UnsafePointer.of(this.#buffer), 590 | centerX, 591 | centerY, 592 | radius, 593 | color.buffer, 594 | ); 595 | } 596 | 597 | /** Draw circle outline within an image (Vector version) */ 598 | drawCircleLinesV(center: Vector2, radius: number, color: Color): void { 599 | lib.symbols.ImageDrawCircleLinesV( 600 | Deno.UnsafePointer.of(this.#buffer), 601 | center.buffer, 602 | radius, 603 | color.buffer, 604 | ); 605 | } 606 | 607 | /** Draw rectangle within an image */ 608 | drawRectangle( 609 | posX: number, 610 | posY: number, 611 | width: number, 612 | height: number, 613 | color: Color, 614 | ): void { 615 | lib.symbols.ImageDrawRectangle( 616 | Deno.UnsafePointer.of(this.#buffer), 617 | posX, 618 | posY, 619 | width, 620 | height, 621 | color.buffer, 622 | ); 623 | } 624 | 625 | /** Draw rectangle within an image (Vector version) */ 626 | drawRectangleV(position: Vector2, size: Vector2, color: Color): void { 627 | lib.symbols.ImageDrawRectangleV( 628 | Deno.UnsafePointer.of(this.#buffer), 629 | position.buffer, 630 | size.buffer, 631 | color.buffer, 632 | ); 633 | } 634 | 635 | /** Draw rectangle within an image */ 636 | drawRectangleRec(rec: Rectangle, color: Color): void { 637 | lib.symbols.ImageDrawRectangleRec( 638 | Deno.UnsafePointer.of(this.#buffer), 639 | rec.buffer, 640 | color.buffer, 641 | ); 642 | } 643 | 644 | /** Draw rectangle lines within an image */ 645 | drawRectangleLines(rec: Rectangle, thick: number, color: Color): void { 646 | lib.symbols.ImageDrawRectangleLines( 647 | Deno.UnsafePointer.of(this.#buffer), 648 | rec.buffer, 649 | thick, 650 | color.buffer, 651 | ); 652 | } 653 | 654 | /** Draw a source image within a destination image (tint applied to source) */ 655 | draw(src: Image, srcRec: Rectangle, dstRec: Rectangle, tint: Color): void { 656 | lib.symbols.ImageDraw( 657 | Deno.UnsafePointer.of(this.#buffer), 658 | src.buffer, 659 | srcRec.buffer, 660 | dstRec.buffer, 661 | tint.buffer, 662 | ); 663 | } 664 | 665 | /** Draw text (using default font) within an image (destination) */ 666 | drawText( 667 | text: string, 668 | posX: number, 669 | posY: number, 670 | fontSize: number, 671 | color: Color, 672 | ): void { 673 | const encodedText = new TextEncoder().encode(text + "\0"); 674 | lib.symbols.ImageDrawText( 675 | Deno.UnsafePointer.of(this.#buffer), 676 | encodedText, 677 | posX, 678 | posY, 679 | fontSize, 680 | color.buffer, 681 | ); 682 | } 683 | 684 | /** Draw text (custom sprite font) within an image (destination) */ 685 | drawTextEx( 686 | font: Font, 687 | text: string, 688 | position: Vector2, 689 | fontSize: number, 690 | spacing: number, 691 | tint: Color, 692 | ): void { 693 | const encodedText = new TextEncoder().encode(text + "\0"); 694 | lib.symbols.ImageDrawTextEx( 695 | Deno.UnsafePointer.of(this.#buffer), 696 | font.buffer, 697 | encodedText, 698 | position.buffer, 699 | fontSize, 700 | spacing, 701 | tint.buffer, 702 | ); 703 | } 704 | } 705 | 706 | // TODO 707 | // RLAPI Image LoadImageAnim(const char *fileName, int *frames); // Load image sequence from file (frames appended to image.data) 708 | // RLAPI unsigned char *ExportImageToMemory(Image image, const char *fileType, int *fileSize); // Export image to memory buffer 709 | -------------------------------------------------------------------------------- /src/keyboard.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Keyboard functions 3 | * @module 4 | */ 5 | import { lib } from "../bindings/bindings.ts"; 6 | 7 | // Keyboard keys (US keyboard layout) 8 | // NOTE: Use GetKeyPressed() to allow redefining 9 | // required keys for alternative layouts 10 | const keyboardKey = { 11 | apostrophe: 39, 12 | comma: 44, 13 | minus: 45, 14 | period: 46, 15 | slash: 47, 16 | zero: 48, 17 | one: 49, 18 | two: 50, 19 | three: 51, 20 | four: 52, 21 | five: 53, 22 | six: 54, 23 | seven: 55, 24 | eight: 56, 25 | nine: 57, 26 | semicolon: 59, 27 | equal: 61, 28 | a: 65, 29 | b: 66, 30 | c: 67, 31 | d: 68, 32 | e: 69, 33 | f: 70, 34 | g: 71, 35 | h: 72, 36 | i: 73, 37 | j: 74, 38 | k: 75, 39 | l: 76, 40 | m: 77, 41 | n: 78, 42 | o: 79, 43 | p: 80, 44 | q: 81, 45 | r: 82, 46 | s: 83, 47 | t: 84, 48 | u: 85, 49 | v: 86, 50 | w: 87, 51 | x: 88, 52 | y: 89, 53 | z: 90, 54 | leftBracket: 91, 55 | backslash: 92, 56 | rightBracket: 93, 57 | grave: 96, 58 | space: 32, 59 | escape: 256, 60 | enter: 257, 61 | tab: 258, 62 | backspace: 259, 63 | insert: 260, 64 | delete: 261, 65 | right: 262, 66 | left: 263, 67 | down: 264, 68 | up: 265, 69 | pageUp: 266, 70 | pageDown: 267, 71 | home: 268, 72 | end: 269, 73 | capsLock: 280, 74 | scrollLock: 281, 75 | numLock: 282, 76 | printScreen: 283, 77 | pause: 284, 78 | f1: 290, 79 | f2: 291, 80 | f3: 292, 81 | f4: 293, 82 | f5: 294, 83 | f6: 295, 84 | f7: 296, 85 | f8: 297, 86 | f9: 298, 87 | f10: 299, 88 | f11: 300, 89 | f12: 301, 90 | leftShift: 340, 91 | leftControl: 341, 92 | leftAlt: 342, 93 | leftSuper: 343, 94 | rightShift: 344, 95 | rightControl: 345, 96 | rightAlt: 346, 97 | rightSuper: 347, 98 | kbMenu: 348, 99 | kp0: 320, 100 | kp1: 321, 101 | kp2: 322, 102 | kp3: 323, 103 | kp4: 324, 104 | kp5: 325, 105 | kp6: 326, 106 | kp7: 327, 107 | kp8: 328, 108 | kp9: 329, 109 | kpDecimal: 330, 110 | kpDivide: 331, 111 | kpMultiply: 332, 112 | kpSubtract: 333, 113 | kpAdd: 334, 114 | kpEnter: 335, 115 | kpEqual: 336, 116 | back: 4, 117 | menu: 82, 118 | volumeUp: 24, 119 | volumeDown: 25, 120 | }; 121 | 122 | export type KeyboardKey = keyof typeof keyboardKey; 123 | 124 | /** A simple class for interacting with the keyboard */ 125 | export class Keyboard { 126 | /** Check if a key has been pressed once */ 127 | static isKeyPressed(key: KeyboardKey): boolean { 128 | return !!lib.symbols.IsKeyPressed(keyboardKey[key]); 129 | } 130 | 131 | /** Check if a key has been pressed again */ 132 | static isKeyPressedRepeat(key: KeyboardKey): boolean { 133 | return !!lib.symbols.IsKeyPressedRepeat(keyboardKey[key]); 134 | } 135 | 136 | /** Check if a key is being pressed */ 137 | static isKeyDown(key: KeyboardKey): boolean { 138 | return !!lib.symbols.IsKeyDown(keyboardKey[key]); 139 | } 140 | 141 | /** Check if a key has been released once */ 142 | static isKeyReleased(key: KeyboardKey): boolean { 143 | return !!lib.symbols.IsKeyReleased(keyboardKey[key]); 144 | } 145 | 146 | /** Check if a key is NOT being pressed */ 147 | static isKeyUp(key: KeyboardKey): boolean { 148 | return !!lib.symbols.IsKeyUp(keyboardKey[key]); 149 | } 150 | 151 | /** Get key pressed (keycode), call it multiple times for keys queued, returns null when the queue is empty */ 152 | static getKeyPressed(): number | null { 153 | return lib.symbols.GetKeyPressed() ?? null; 154 | } 155 | 156 | /** Get char pressed (unicode), call it multiple times for chars queued, returns null when the queue is empty */ 157 | static getCharPressed(): number | null { 158 | return lib.symbols.GetCharPressed() ?? null; 159 | } 160 | 161 | /** Set a custom key to exit program (default is ESC) */ 162 | static setExitKey(key: KeyboardKey) { 163 | lib.symbols.SetExitKey(keyboardKey[key]); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/material.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Mesh functions 3 | * @module 4 | */ 5 | import { lib } from "../bindings/bindings.ts"; 6 | import type { Model } from "./model.ts"; 7 | import type { Texture2D } from "./texture.ts"; 8 | 9 | const materialMapIndex = { 10 | albedo: 0, 11 | metalness: 1, 12 | normal: 2, 13 | roughness: 3, 14 | occlusion: 4, 15 | emission: 5, 16 | height: 6, 17 | cubemap: 7, 18 | irradiance: 8, 19 | prefilter: 9, 20 | brdf: 10, 21 | }; 22 | 23 | export type MaterialMapIndex = keyof typeof materialMapIndex; 24 | 25 | /** Class for creating, loading, and drawing materials */ 26 | export class Material { 27 | #buffer: Uint8Array; 28 | /** Avoid using if at all possible */ 29 | constructor(buffer: Uint8Array) { 30 | this.#buffer = buffer; 31 | } 32 | 33 | get buffer(): Uint8Array { 34 | return this.#buffer; 35 | } 36 | 37 | /** Load materials from model file */ 38 | static load(fileName: string): Material[] { 39 | const encoded = new TextEncoder().encode(fileName + "\0"); 40 | const count = new Int32Array(1); 41 | const _pointer = lib.symbols.LoadMaterials( 42 | encoded, 43 | Deno.UnsafePointer.of(count), 44 | ); 45 | const materials: Material[] = []; 46 | 47 | // TODO: read data from pointer and load it into materials array 48 | 49 | return materials; 50 | } 51 | 52 | /** Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) */ 53 | static loadDefault(): Material { 54 | return new Material(lib.symbols.LoadMaterialDefault()); 55 | } 56 | 57 | /** Check if a material is ready */ 58 | isReady(): boolean { 59 | return !!lib.symbols.IsMaterialReady(this.#buffer); 60 | } 61 | 62 | /** Unload material from GPU memory (VRAM) */ 63 | unload() { 64 | lib.symbols.UnloadMaterial(this.#buffer); 65 | } 66 | 67 | /** Set texture for a material map type */ 68 | setTexture(mapType: MaterialMapIndex, texture: Texture2D) { 69 | lib.symbols.SetMaterialTexture( 70 | Deno.UnsafePointer.of(this.#buffer), 71 | materialMapIndex[mapType], 72 | texture.buffer, 73 | ); 74 | } 75 | 76 | /** Set material for a mesh */ 77 | static setModelMeshMaterial( 78 | model: Model, 79 | meshId: number, 80 | materialId: number, 81 | ) { 82 | lib.symbols.SetModelMeshMaterial( 83 | Deno.UnsafePointer.of(model.buffer), 84 | meshId, 85 | materialId, 86 | ); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/mesh.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Mesh functions 3 | * @module 4 | */ 5 | import { lib } from "../bindings/bindings.ts"; 6 | import { BoundingBox, type Matrix, type Vector3 } from "./_util.ts"; 7 | import type { Image } from "./image.ts"; 8 | import type { Material } from "./material.ts"; 9 | 10 | /** Class for creating, loading, and drawing meshes */ 11 | export class Mesh { 12 | #buffer: Uint8Array; 13 | /** Avoid using if at all possible */ 14 | constructor(buffer: Uint8Array) { 15 | this.#buffer = buffer; 16 | } 17 | 18 | get buffer(): Uint8Array { 19 | return this.#buffer; 20 | } 21 | 22 | /** Upload mesh vertex data in GPU and provide VAO/VBO ids */ 23 | upload(dynamic: boolean) { 24 | lib.symbols.UploadMesh(Deno.UnsafePointer.of(this.#buffer), +dynamic); 25 | } 26 | 27 | /** Update mesh vertex data in GPU for a specific buffer index */ 28 | updateBuffer(index: number, data: ArrayBuffer, offset: number) { 29 | lib.symbols.UpdateMeshBuffer( 30 | this.#buffer, 31 | index, 32 | Deno.UnsafePointer.of(data), 33 | data.byteLength, 34 | offset, 35 | ); 36 | } 37 | 38 | /** Unload mesh data from CPU and GPU */ 39 | unload() { 40 | lib.symbols.UnloadMesh(this.#buffer); 41 | } 42 | 43 | /** Draw a 3d mesh with material and transform */ 44 | draw(material: Material, transform: Matrix) { 45 | lib.symbols.DrawMesh(this.#buffer, material.buffer, transform.buffer); 46 | } 47 | 48 | /** Draw multiple mesh instances with material and different transforms */ 49 | drawInstanced(material: Material, transforms: Matrix[]) { 50 | const buffer = new Float32Array(16 * transforms.length); 51 | for (let i = 0; i < transforms.length; i++) { 52 | buffer.set(new Float32Array(transforms[i].buffer), i * 16); 53 | } 54 | lib.symbols.DrawMeshInstanced( 55 | this.#buffer, 56 | material.buffer, 57 | Deno.UnsafePointer.of(buffer), 58 | transforms.length, 59 | ); 60 | } 61 | 62 | /** Export mesh data to file, returns true on success */ 63 | export(fileName: string): boolean { 64 | const encoded = new TextEncoder().encode(fileName + "\0"); 65 | return !!lib.symbols.ExportMesh(this.#buffer, encoded); 66 | } 67 | 68 | /** Compute mesh bounding box limits */ 69 | getBoundingBox(): BoundingBox { 70 | return BoundingBox.fromBuffer( 71 | lib.symbols.GetMeshBoundingBox(this.#buffer).buffer, 72 | ); 73 | } 74 | 75 | /** Compute mesh tangents */ 76 | GenMeshTangents() { 77 | lib.symbols.GenMeshTangents(Deno.UnsafePointer.of(this.#buffer)); 78 | } 79 | 80 | /** Generate polygonal mesh */ 81 | static genPoly(sides: number, radius: number): Mesh { 82 | return new Mesh(lib.symbols.GenMeshPoly(sides, radius)); 83 | } 84 | 85 | /** Generate plane mesh (with subdivisions) */ 86 | static genPlane( 87 | width: number, 88 | length: number, 89 | resX: number, 90 | resZ: number, 91 | ): Mesh { 92 | return new Mesh(lib.symbols.GenMeshPlane(width, length, resX, resZ)); 93 | } 94 | 95 | /** Generate cuboid mesh */ 96 | static genCube(width: number, height: number, length: number): Mesh { 97 | return new Mesh(lib.symbols.GenMeshCube(width, height, length)); 98 | } 99 | 100 | /** Generate sphere mesh (standard sphere) */ 101 | static genSphere(radius: number, rings: number, slices: number): Mesh { 102 | return new Mesh(lib.symbols.GenMeshSphere(radius, rings, slices)); 103 | } 104 | 105 | /** Generate half-sphere mesh (no bottom cap) */ 106 | static genHemiSphere(radius: number, rings: number, slices: number): Mesh { 107 | return new Mesh(lib.symbols.GenMeshHemiSphere(radius, rings, slices)); 108 | } 109 | 110 | /** Generate cylinder mesh */ 111 | static genCylinder(radius: number, height: number, slices: number): Mesh { 112 | return new Mesh(lib.symbols.GenMeshCylinder(radius, height, slices)); 113 | } 114 | 115 | /** Generate cone/pyramid mesh */ 116 | static genCone(radius: number, height: number, slices: number): Mesh { 117 | return new Mesh(lib.symbols.GenMeshCone(radius, height, slices)); 118 | } 119 | 120 | /** Generate torus mesh */ 121 | static genTorus( 122 | radius: number, 123 | size: number, 124 | radSeg: number, 125 | sides: number, 126 | ): Mesh { 127 | return new Mesh(lib.symbols.GenMeshTorus(radius, size, radSeg, sides)); 128 | } 129 | 130 | /** Generate trefoil knot mesh */ 131 | static genKnot( 132 | radius: number, 133 | size: number, 134 | radSeg: number, 135 | sides: number, 136 | ): Mesh { 137 | return new Mesh(lib.symbols.GenMeshKnot(radius, size, radSeg, sides)); 138 | } 139 | 140 | /** Generate heightmap mesh from image data */ 141 | static genHeightmap(heightmap: Image, size: Vector3): Mesh { 142 | return new Mesh( 143 | lib.symbols.GenMeshHeightmap(heightmap.buffer, size.buffer), 144 | ); 145 | } 146 | 147 | /** Generate cubes-based map mesh from image data */ 148 | static genCubicmap(cubicmap: Image, cubeSize: Vector3): Mesh { 149 | return new Mesh( 150 | lib.symbols.GenMeshCubicmap(cubicmap.buffer, cubeSize.buffer), 151 | ); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/model.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Model functions 3 | * @module 4 | */ 5 | import { lib } from "../bindings/bindings.ts"; 6 | import { 7 | BoundingBox, 8 | type Rectangle, 9 | type Vector2, 10 | type Vector3, 11 | } from "./_util.ts"; 12 | import type { Camera3D } from "./camera3d.ts"; 13 | import type { Color } from "./color.ts"; 14 | import type { Texture2D } from "./texture.ts"; 15 | import type { Mesh } from "./mesh.ts"; 16 | 17 | /** Class for creating, loading, and drawing models */ 18 | export class Model { 19 | #buffer: Uint8Array; 20 | /** Avoid using if at all possible */ 21 | constructor(buffer: Uint8Array) { 22 | this.#buffer = buffer; 23 | } 24 | 25 | get buffer(): Uint8Array { 26 | return this.#buffer; 27 | } 28 | 29 | /** Load model from files (meshes and materials) */ 30 | static load(fileName: string): Model { 31 | const encoded = new TextEncoder().encode(fileName + "\0"); 32 | return new Model(lib.symbols.LoadModel(encoded)); 33 | } 34 | 35 | /** Load model from generated mesh (default material) */ 36 | static loadFromMesh(mesh: Mesh): Model { 37 | return new Model(lib.symbols.LoadModelFromMesh(mesh.buffer)); 38 | } 39 | 40 | /** Check if a model is ready */ 41 | isReady(): boolean { 42 | return !!lib.symbols.IsModelReady(this.#buffer); 43 | } 44 | 45 | /** Unload model (including meshes) from memory (RAM and/or VRAM) */ 46 | unload() { 47 | lib.symbols.UnloadModel(this.#buffer); 48 | } 49 | 50 | /** Compute model bounding box limits (considers all meshes) */ 51 | getBoundingBox(): BoundingBox { 52 | return BoundingBox.fromBuffer( 53 | lib.symbols.GetModelBoundingBox(this.#buffer).buffer, 54 | ); 55 | } 56 | 57 | /** Draw a model (with texture if set) */ 58 | draw(position: Vector3, scale: number, tint: Color) { 59 | lib.symbols.DrawModel(this.#buffer, position.buffer, scale, tint.buffer); 60 | } 61 | 62 | /** Draw a model with extended parameters */ 63 | drawEx( 64 | position: Vector3, 65 | rotationAxis: Vector3, 66 | rotationAngle: number, 67 | scale: Vector3, 68 | tint: Color, 69 | ) { 70 | lib.symbols.DrawModelEx( 71 | this.#buffer, 72 | position.buffer, 73 | rotationAxis.buffer, 74 | rotationAngle, 75 | scale.buffer, 76 | tint.buffer, 77 | ); 78 | } 79 | 80 | /** Draw a model wires (with texture if set) */ 81 | drawWires(position: Vector3, scale: number, tint: Color) { 82 | lib.symbols.DrawModelWires( 83 | this.#buffer, 84 | position.buffer, 85 | scale, 86 | tint.buffer, 87 | ); 88 | } 89 | 90 | /** Draw a model wires (with texture if set) with extended parameters */ 91 | drawWiresEx( 92 | position: Vector3, 93 | rotationAxis: Vector3, 94 | rotationAngle: number, 95 | scale: Vector3, 96 | tint: Color, 97 | ) { 98 | lib.symbols.DrawModelWiresEx( 99 | this.#buffer, 100 | position.buffer, 101 | rotationAxis.buffer, 102 | rotationAngle, 103 | scale.buffer, 104 | tint.buffer, 105 | ); 106 | } 107 | 108 | /** Draw bounding box (wires) */ 109 | static drawBoundingBox(box: BoundingBox, color: Color) { 110 | lib.symbols.DrawBoundingBox(box.buffer, color.buffer); 111 | } 112 | 113 | /** Draw a billboard texture */ 114 | static drawBillboard( 115 | camera: Camera3D, 116 | texture: Texture2D, 117 | position: Vector3, 118 | size: number, 119 | tint: Color, 120 | ) { 121 | lib.symbols.DrawBillboard( 122 | camera.buffer, 123 | texture.buffer, 124 | position.buffer, 125 | size, 126 | tint.buffer, 127 | ); 128 | } 129 | 130 | /** Draw a billboard texture defined by source */ 131 | static drawBillboardRect( 132 | camera: Camera3D, 133 | texture: Texture2D, 134 | source: Rectangle, 135 | position: Vector3, 136 | size: Vector2, 137 | tint: Color, 138 | ) { 139 | lib.symbols.DrawBillboardRec( 140 | camera.buffer, 141 | texture.buffer, 142 | source.buffer, 143 | position.buffer, 144 | size.buffer, 145 | tint.buffer, 146 | ); 147 | } 148 | 149 | /** Draw a billboard texture defined by source and rotation */ 150 | static drawBillboardPro( 151 | camera: Camera3D, 152 | texture: Texture2D, 153 | source: Rectangle, 154 | position: Vector3, 155 | up: Vector3, 156 | size: Vector2, 157 | origin: Vector2, 158 | rotation: number, 159 | color: Color, 160 | ) { 161 | lib.symbols.DrawBillboardPro( 162 | camera.buffer, 163 | texture.buffer, 164 | source.buffer, 165 | position.buffer, 166 | up.buffer, 167 | size.buffer, 168 | origin.buffer, 169 | rotation, 170 | color.buffer, 171 | ); 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /src/model_animations.ts: -------------------------------------------------------------------------------- 1 | // TODO 2 | // RLAPI ModelAnimation *LoadModelAnimations(const char *fileName, int *animCount); // Load model animations from file 3 | // RLAPI void UpdateModelAnimation(Model model, ModelAnimation anim, int frame); // Update model animation pose 4 | // RLAPI void UnloadModelAnimation(ModelAnimation anim); // Unload animation data 5 | // RLAPI void UnloadModelAnimations(ModelAnimation *animations, int animCount); // Unload animation array data 6 | // RLAPI bool IsModelAnimationValid(Model model, ModelAnimation anim); // Check model animation skeleton match 7 | -------------------------------------------------------------------------------- /src/mouse.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Mouse functions 3 | * @module 4 | */ 5 | import { lib } from "../bindings/bindings.ts"; 6 | import { Vector2 } from "./_util.ts"; 7 | 8 | const cursorShapes = { 9 | default: 0, 10 | arrow: 1, 11 | ibeam: 2, 12 | crosshair: 3, 13 | pointingHand: 4, 14 | resizeEW: 5, 15 | resizeNS: 6, 16 | resizeNWSE: 7, 17 | resizeNESW: 8, 18 | resizeAll: 9, 19 | notAllowed: 10, 20 | }; 21 | 22 | export type CursorShape = keyof typeof cursorShapes; 23 | 24 | /** A simple class for interacting with the mouse */ 25 | export class Mouse { 26 | /** Check if a mouse button has been pressed once */ 27 | static isButtonPressed(button: number): boolean { 28 | return !!lib.symbols.IsMouseButtonPressed(button); 29 | } 30 | 31 | /** Check if a mouse button is being pressed */ 32 | static isButtonDown(button: number): boolean { 33 | return !!lib.symbols.IsMouseButtonDown(button); 34 | } 35 | 36 | /** Check if a mouse button has been released once */ 37 | static isButtonReleased(button: number): boolean { 38 | return !!lib.symbols.IsMouseButtonReleased(button); 39 | } 40 | 41 | /** Check if a mouse button is NOT being pressed */ 42 | static isButtonUp(button: number): boolean { 43 | return !!lib.symbols.IsMouseButtonUp(button); 44 | } 45 | 46 | /** Get mouse position X */ 47 | static getX(): number { 48 | return lib.symbols.GetMouseX(); 49 | } 50 | 51 | /** Get mouse position Y */ 52 | static getY(): number { 53 | return lib.symbols.GetMouseY(); 54 | } 55 | 56 | /** Get mouse position XY */ 57 | static getPosition(): Vector2 { 58 | return Vector2.fromBuffer(lib.symbols.GetMousePosition().buffer); 59 | } 60 | 61 | /** Get mouse delta between frames */ 62 | static getDelta(): Vector2 { 63 | return Vector2.fromBuffer(lib.symbols.GetMouseDelta().buffer); 64 | } 65 | 66 | /** Set mouse position XY */ 67 | static setPosition(x: number, y: number) { 68 | lib.symbols.SetMousePosition(x, y); 69 | } 70 | 71 | /** Set mouse offset */ 72 | static setOffset(offsetX: number, offsetY: number) { 73 | lib.symbols.SetMouseOffset(offsetX, offsetY); 74 | } 75 | 76 | /** Set mouse scaling */ 77 | static setScale(scaleX: number, scaleY: number) { 78 | lib.symbols.SetMouseScale(scaleX, scaleY); 79 | } 80 | 81 | /** Get mouse wheel movement for X or Y, whichever is larger */ 82 | static getWheelMove(): number { 83 | return lib.symbols.GetMouseWheelMove(); 84 | } 85 | 86 | /** Get mouse wheel movement for both X and Y */ 87 | static getWheelMoveV(): Vector2 { 88 | return Vector2.fromBuffer(lib.symbols.GetMouseWheelMoveV().buffer); 89 | } 90 | 91 | /** Set mouse cursor */ 92 | static setCursor(cursor: CursorShape) { 93 | lib.symbols.SetMouseCursor(cursorShapes[cursor]); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/music.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Music functions 3 | * @module 4 | */ 5 | import { lib } from "../bindings/bindings.ts"; 6 | 7 | /** A simple class for interacting with music */ 8 | export class Music { 9 | #buffer: Uint8Array; 10 | /** Avoid using if at all possible */ 11 | constructor(buffer: Uint8Array) { 12 | this.#buffer = buffer; 13 | } 14 | 15 | /** Load music stream from file */ 16 | static loadStream(filename: string): Music { 17 | const encoded = new TextEncoder().encode(filename + "\0"); 18 | return new Music(lib.symbols.LoadMusicStream(encoded)); 19 | } 20 | 21 | /** Load music stream from data */ 22 | static loadStreamFromMemory( 23 | fileType: string, 24 | data: Uint8Array, 25 | ): Music { 26 | const encoded = new TextEncoder().encode(fileType + "\0"); 27 | return new Music( 28 | lib.symbols.LoadMusicStreamFromMemory( 29 | encoded, 30 | Deno.UnsafePointer.of(data), 31 | data.length, 32 | ), 33 | ); 34 | } 35 | 36 | /** Checks if a music stream is ready */ 37 | isReady(): boolean { 38 | return !!lib.symbols.IsMusicReady(this.#buffer); 39 | } 40 | 41 | /** Unload music stream */ 42 | unload() { 43 | lib.symbols.UnloadMusicStream(this.#buffer); 44 | } 45 | 46 | /** Start music playing */ 47 | play() { 48 | lib.symbols.PlayMusicStream(this.#buffer); 49 | } 50 | 51 | /** Check if music is playing */ 52 | isPlaying(): boolean { 53 | return !!lib.symbols.IsMusicStreamPlaying(this.#buffer); 54 | } 55 | 56 | /** Updates buffers for music streaming */ 57 | update() { 58 | lib.symbols.UpdateMusicStream(this.#buffer); 59 | } 60 | 61 | /** Stop music playing */ 62 | stop() { 63 | lib.symbols.StopMusicStream(this.#buffer); 64 | } 65 | 66 | /** Pause music playing */ 67 | pause() { 68 | lib.symbols.PauseMusicStream(this.#buffer); 69 | } 70 | 71 | /** Resume playing paused music */ 72 | resume() { 73 | lib.symbols.ResumeMusicStream(this.#buffer); 74 | } 75 | 76 | /** Seek music to a position (in seconds) */ 77 | seek(position: number) { 78 | lib.symbols.SeekMusicStream(this.#buffer, position); 79 | } 80 | 81 | /** Set volume for music (1.0 is max level) */ 82 | setVolume(volume: number) { 83 | lib.symbols.SetMusicVolume(this.#buffer, volume); 84 | } 85 | 86 | /** Set pitch for a music (1.0 is base level) */ 87 | setPitch(pitch: number) { 88 | lib.symbols.SetMusicPitch(this.#buffer, pitch); 89 | } 90 | 91 | /** Set pan for a music (0.5 is center) */ 92 | setPan(pan: number) { 93 | lib.symbols.SetMusicPan(this.#buffer, pan); 94 | } 95 | 96 | /** Get music time length (in seconds) */ 97 | getTimeLength(): number { 98 | return lib.symbols.GetMusicTimeLength(this.#buffer); 99 | } 100 | 101 | /** Get current music time played (in seconds) */ 102 | getTimePlayed(): number { 103 | return lib.symbols.GetMusicTimePlayed(this.#buffer); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/screen_space.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Screen-space related functions 3 | * @module 4 | */ 5 | import { lib } from "../bindings/bindings.ts"; 6 | import { type Camera2D, Matrix, Ray, Vector2, type Vector3 } from "./_util.ts"; 7 | import type { Camera3D } from "./camera3d.ts"; 8 | 9 | /** Helper methods for screenspace transformations */ 10 | export class ScreenSpace { 11 | /** Get a ray trace from mouse position */ 12 | static getMouseRay(mousePosition: Vector2, camera: Camera3D): Ray { 13 | return Ray.fromBuffer( 14 | lib.symbols.GetMouseRay(mousePosition.buffer, camera.buffer).buffer, 15 | ); 16 | } 17 | 18 | /** Get camera transform matrix (view matrix) */ 19 | static getCameraMatrix(camera: Camera3D): Matrix { 20 | return Matrix.fromBuffer(lib.symbols.GetCameraMatrix(camera.buffer).buffer); 21 | } 22 | 23 | /** Get camera 2d transform matrix */ 24 | static getCameraMatrix2D(camera: Camera2D): Matrix { 25 | return Matrix.fromBuffer( 26 | lib.symbols.GetCameraMatrix2D(camera.buffer).buffer, 27 | ); 28 | } 29 | 30 | /** Get the screen space position for a 3d world space position */ 31 | static getWorldToScreen(position: Vector3, camera: Camera3D): Vector2 { 32 | return Vector2.fromBuffer( 33 | lib.symbols.GetWorldToScreen(position.buffer, camera.buffer).buffer, 34 | ); 35 | } 36 | 37 | /** Get the world space position for a 2d camera screen space position */ 38 | static getScreenToWorld2D(position: Vector2, camera: Camera2D): Vector2 { 39 | return Vector2.fromBuffer( 40 | lib.symbols.GetScreenToWorld2D(position.buffer, camera.buffer).buffer, 41 | ); 42 | } 43 | 44 | /** Get size position for a 3d world space position */ 45 | static getWorldToScreenEx( 46 | position: Vector3, 47 | camera: Camera3D, 48 | width: number, 49 | height: number, 50 | ): Vector2 { 51 | return Vector2.fromBuffer( 52 | lib.symbols.GetWorldToScreenEx( 53 | position.buffer, 54 | camera.buffer, 55 | width, 56 | height, 57 | ).buffer, 58 | ); 59 | } 60 | 61 | /** Get the screen space position for a 2d camera world space position */ 62 | static getWorldToScreen2D(position: Vector2, camera: Camera2D): Vector2 { 63 | return Vector2.fromBuffer( 64 | lib.symbols.GetWorldToScreen2D(position.buffer, camera.buffer).buffer, 65 | ); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/shader.ts: -------------------------------------------------------------------------------- 1 | // TODO 2 | // RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName); // Load shader from files and bind default locations 3 | // RLAPI Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations 4 | // RLAPI bool IsShaderReady(Shader shader); // Check if a shader is ready 5 | // RLAPI int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location 6 | // RLAPI int GetShaderLocationAttrib(Shader shader, const char *attribName); // Get shader attribute location 7 | // RLAPI void SetShaderValue(Shader shader, int locIndex, const void *value, int uniformType); // Set shader uniform value 8 | // RLAPI void SetShaderValueV(Shader shader, int locIndex, const void *value, int uniformType, int count); // Set shader uniform value vector 9 | // RLAPI void SetShaderValueMatrix(Shader shader, int locIndex, Matrix mat); // Set shader uniform value (matrix 4x4) 10 | // RLAPI void SetShaderValueTexture(Shader shader, int locIndex, Texture2D texture); // Set shader uniform value for texture (sampler2d) 11 | // RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM) 12 | -------------------------------------------------------------------------------- /src/shapes.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Functions for drawing 2d shapes 3 | * @module 4 | */ 5 | import { lib } from "../bindings/bindings.ts"; 6 | import type { Color } from "./color.ts"; 7 | import type { Rectangle, Vector2 } from "./_util.ts"; 8 | import { concatVector2s } from "./_helper.ts"; 9 | 10 | /** Shape drawing functions */ 11 | export class Shapes { 12 | /** Draw a pixel */ 13 | static drawPixel(posX: number, posY: number, color: Color) { 14 | lib.symbols.DrawPixel(posX, posY, color.buffer); 15 | } 16 | 17 | /** Draw a pixel (Vector version) */ 18 | static drawPixelV(position: Vector2, color: Color) { 19 | lib.symbols.DrawPixelV(position.buffer, color.buffer); 20 | } 21 | 22 | /** Draw a line */ 23 | static drawLine( 24 | startPosX: number, 25 | startPosY: number, 26 | endPosX: number, 27 | endPosY: number, 28 | color: Color, 29 | ) { 30 | lib.symbols.DrawLine(startPosX, startPosY, endPosX, endPosY, color.buffer); 31 | } 32 | 33 | /** Draw a line (using gl lines) */ 34 | static drawLineV(startPos: Vector2, endPos: Vector2, color: Color) { 35 | lib.symbols.DrawLineV(startPos.buffer, endPos.buffer, color.buffer); 36 | } 37 | 38 | /** Draw a line (using triangles/quads) */ 39 | static drawLineEx( 40 | startPos: Vector2, 41 | endPos: Vector2, 42 | thick: number, 43 | color: Color, 44 | ) { 45 | lib.symbols.DrawLineEx(startPos.buffer, endPos.buffer, thick, color.buffer); 46 | } 47 | 48 | /** Draw lines sequence (using gl lines) */ 49 | static drawLineStrip(points: Vector2[], color: Color) { 50 | const buffer = concatVector2s(points); 51 | lib.symbols.DrawLineStrip( 52 | Deno.UnsafePointer.of(buffer), 53 | points.length, 54 | color.buffer, 55 | ); 56 | } 57 | 58 | /** Draw line segment cubic-bezier in-out interpolation */ 59 | static drawLineBezier( 60 | startPos: Vector2, 61 | endPos: Vector2, 62 | thick: number, 63 | color: Color, 64 | ) { 65 | lib.symbols.DrawLineBezier( 66 | startPos.buffer, 67 | endPos.buffer, 68 | thick, 69 | color.buffer, 70 | ); 71 | } 72 | 73 | /** Draw a color-filled circle */ 74 | static drawCircle( 75 | centerX: number, 76 | centerY: number, 77 | radius: number, 78 | color: Color, 79 | ) { 80 | lib.symbols.DrawCircle(centerX, centerY, radius, color.buffer); 81 | } 82 | 83 | /** Draw a piece of a circle */ 84 | static drawCircleSector( 85 | center: Vector2, 86 | radius: number, 87 | startAngle: number, 88 | endAngle: number, 89 | segments: number, 90 | color: Color, 91 | ) { 92 | lib.symbols.DrawCircleSector( 93 | center.buffer, 94 | radius, 95 | startAngle, 96 | endAngle, 97 | segments, 98 | color.buffer, 99 | ); 100 | } 101 | 102 | /** Draw circle sector outline */ 103 | static drawCircleSectorLines( 104 | center: Vector2, 105 | radius: number, 106 | startAngle: number, 107 | endAngle: number, 108 | segments: number, 109 | color: Color, 110 | ) { 111 | lib.symbols.DrawCircleSectorLines( 112 | center.buffer, 113 | radius, 114 | startAngle, 115 | endAngle, 116 | segments, 117 | color.buffer, 118 | ); 119 | } 120 | 121 | /** Draw a gradient-filled circle */ 122 | static drawCircleGradient( 123 | centerX: number, 124 | centerY: number, 125 | radius: number, 126 | color1: Color, 127 | color2: Color, 128 | ) { 129 | lib.symbols.DrawCircleGradient( 130 | centerX, 131 | centerY, 132 | radius, 133 | color1.buffer, 134 | color2.buffer, 135 | ); 136 | } 137 | 138 | /** Draw a color-filled circle (Vector version) */ 139 | static drawCircleV(center: Vector2, radius: number, color: Color) { 140 | lib.symbols.DrawCircleV(center.buffer, radius, color.buffer); 141 | } 142 | 143 | /** Draw circle outline */ 144 | static drawCircleLines( 145 | centerX: number, 146 | centerY: number, 147 | radius: number, 148 | color: Color, 149 | ) { 150 | lib.symbols.DrawCircleLines(centerX, centerY, radius, color.buffer); 151 | } 152 | 153 | /** Draw circle outline (Vector version) */ 154 | static drawCircleLinesV(center: Vector2, radius: number, color: Color) { 155 | lib.symbols.DrawCircleLinesV(center.buffer, radius, color.buffer); 156 | } 157 | 158 | /** Draw ellipse */ 159 | static drawEllipse( 160 | centerX: number, 161 | centerY: number, 162 | radiusH: number, 163 | radiusV: number, 164 | color: Color, 165 | ) { 166 | lib.symbols.DrawEllipse(centerX, centerY, radiusH, radiusV, color.buffer); 167 | } 168 | 169 | /** Draw ellipse outline */ 170 | static drawEllipseLines( 171 | centerX: number, 172 | centerY: number, 173 | radiusH: number, 174 | radiusV: number, 175 | color: Color, 176 | ) { 177 | lib.symbols.DrawEllipseLines( 178 | centerX, 179 | centerY, 180 | radiusH, 181 | radiusV, 182 | color.buffer, 183 | ); 184 | } 185 | 186 | /** Draw ring */ 187 | static drawRing( 188 | center: Vector2, 189 | innerRadius: number, 190 | outerRadius: number, 191 | startAngle: number, 192 | endAngle: number, 193 | segments: number, 194 | color: Color, 195 | ) { 196 | lib.symbols.DrawRing( 197 | center.buffer, 198 | innerRadius, 199 | outerRadius, 200 | startAngle, 201 | endAngle, 202 | segments, 203 | color.buffer, 204 | ); 205 | } 206 | 207 | /** Draw ring outline */ 208 | static drawRingLines( 209 | center: Vector2, 210 | innerRadius: number, 211 | outerRadius: number, 212 | startAngle: number, 213 | endAngle: number, 214 | segments: number, 215 | color: Color, 216 | ) { 217 | lib.symbols.DrawRingLines( 218 | center.buffer, 219 | innerRadius, 220 | outerRadius, 221 | startAngle, 222 | endAngle, 223 | segments, 224 | color.buffer, 225 | ); 226 | } 227 | 228 | /** Draw a color-filled rectangle */ 229 | static drawRectangle( 230 | posX: number, 231 | posY: number, 232 | width: number, 233 | height: number, 234 | color: Color, 235 | ) { 236 | lib.symbols.DrawRectangle(posX, posY, width, height, color.buffer); 237 | } 238 | 239 | /** Draw a color-filled rectangle (Vector version) */ 240 | static drawRectangleV(position: Vector2, size: Vector2, color: Color) { 241 | lib.symbols.DrawRectangleV(position.buffer, size.buffer, color.buffer); 242 | } 243 | 244 | /** Draw a color-filled rectangle */ 245 | static drawRectangleRect(rect: Rectangle, color: Color) { 246 | lib.symbols.DrawRectangleRec(rect.buffer, color.buffer); 247 | } 248 | 249 | /** Draw a color-filled rectangle with pro parameters */ 250 | static drawRectanglePro( 251 | rect: Rectangle, 252 | origin: Vector2, 253 | rotation: number, 254 | color: Color, 255 | ) { 256 | lib.symbols.DrawRectanglePro( 257 | rect.buffer, 258 | origin.buffer, 259 | rotation, 260 | color.buffer, 261 | ); 262 | } 263 | 264 | /** Draw a vertical-gradient-filled rectangle */ 265 | static drawRectangleGradientV( 266 | posX: number, 267 | posY: number, 268 | width: number, 269 | height: number, 270 | color1: Color, 271 | color2: Color, 272 | ) { 273 | lib.symbols.DrawRectangleGradientV( 274 | posX, 275 | posY, 276 | width, 277 | height, 278 | color1.buffer, 279 | color2.buffer, 280 | ); 281 | } 282 | 283 | /** Draw a horizontal-gradient-filled rectangle */ 284 | static drawRectangleGradientH( 285 | posX: number, 286 | posY: number, 287 | width: number, 288 | height: number, 289 | color1: Color, 290 | color2: Color, 291 | ) { 292 | lib.symbols.DrawRectangleGradientH( 293 | posX, 294 | posY, 295 | width, 296 | height, 297 | color1.buffer, 298 | color2.buffer, 299 | ); 300 | } 301 | 302 | /** Draw a gradient-filled rectangle with custom vertex colors */ 303 | static drawRectangleGradientEx( 304 | rect: Rectangle, 305 | col1: Color, 306 | col2: Color, 307 | col3: Color, 308 | col4: Color, 309 | ) { 310 | lib.symbols.DrawRectangleGradientEx( 311 | rect.buffer, 312 | col1.buffer, 313 | col2.buffer, 314 | col3.buffer, 315 | col4.buffer, 316 | ); 317 | } 318 | 319 | /** Draw rectangle outline */ 320 | static drawRectangleLines( 321 | posX: number, 322 | posY: number, 323 | width: number, 324 | height: number, 325 | color: Color, 326 | ) { 327 | lib.symbols.DrawRectangleLines(posX, posY, width, height, color.buffer); 328 | } 329 | 330 | /** Draw rectangle outline with extended parameters */ 331 | static drawRectangleLinesEx( 332 | rect: Rectangle, 333 | lineThick: number, 334 | color: Color, 335 | ) { 336 | lib.symbols.DrawRectangleLinesEx(rect.buffer, lineThick, color.buffer); 337 | } 338 | 339 | /** Draw rectangle with rounded edges */ 340 | static drawRectangleRounded( 341 | rect: Rectangle, 342 | roundness: number, 343 | segments: number, 344 | color: Color, 345 | ) { 346 | lib.symbols.DrawRectangleRounded( 347 | rect.buffer, 348 | roundness, 349 | segments, 350 | color.buffer, 351 | ); 352 | } 353 | 354 | /** Draw rectangle with rounded edges */ 355 | static drawRectangleRoundedLines( 356 | rect: Rectangle, 357 | roundness: number, 358 | segments: number, 359 | lineThick: number, 360 | color: Color, 361 | ) { 362 | lib.symbols.DrawRectangleRoundedLines( 363 | rect.buffer, 364 | roundness, 365 | segments, 366 | lineThick, 367 | color.buffer, 368 | ); 369 | } 370 | 371 | /** Draw a color-filled triangle (vertex in counter-clockwise order!) */ 372 | static drawTriangle( 373 | v1: Vector2, 374 | v2: Vector2, 375 | v3: Vector2, 376 | color: Color, 377 | ) { 378 | lib.symbols.DrawTriangle(v1.buffer, v2.buffer, v3.buffer, color.buffer); 379 | } 380 | 381 | /** Draw triangle outline (vertex in counter-clockwise order!) */ 382 | static drawTriangleLines( 383 | v1: Vector2, 384 | v2: Vector2, 385 | v3: Vector2, 386 | color: Color, 387 | ) { 388 | lib.symbols.DrawTriangleLines( 389 | v1.buffer, 390 | v2.buffer, 391 | v3.buffer, 392 | color.buffer, 393 | ); 394 | } 395 | 396 | /** Draw a triangle fan defined by points (first vertex is the center) */ 397 | static drawTriangleFan(points: Vector2[], color: Color) { 398 | const buffer = concatVector2s(points); 399 | lib.symbols.DrawTriangleFan( 400 | Deno.UnsafePointer.of(buffer), 401 | points.length, 402 | color.buffer, 403 | ); 404 | } 405 | 406 | /** Draw a triangle strip defined by points */ 407 | static drawTriangleStrip(points: Vector2[], color: Color) { 408 | const buffer = concatVector2s(points); 409 | lib.symbols.DrawTriangleStrip( 410 | Deno.UnsafePointer.of(buffer), 411 | points.length, 412 | color.buffer, 413 | ); 414 | } 415 | 416 | /** Draw a regular polygon (Vector version) */ 417 | static drawPoly( 418 | center: Vector2, 419 | sides: number, 420 | radius: number, 421 | rotation: number, 422 | color: Color, 423 | ) { 424 | lib.symbols.DrawPoly( 425 | center.buffer, 426 | sides, 427 | radius, 428 | rotation, 429 | color.buffer, 430 | ); 431 | } 432 | 433 | /** Draw a polygon outline of n sides */ 434 | static drawPolyLines( 435 | center: Vector2, 436 | sides: number, 437 | radius: number, 438 | rotation: number, 439 | color: Color, 440 | ) { 441 | lib.symbols.DrawPolyLines( 442 | center.buffer, 443 | sides, 444 | radius, 445 | rotation, 446 | color.buffer, 447 | ); 448 | } 449 | 450 | /** Draw a polygon outline of n sides with extended parameters */ 451 | static drawPolyLinesEx( 452 | center: Vector2, 453 | sides: number, 454 | radius: number, 455 | rotation: number, 456 | lineThick: number, 457 | color: Color, 458 | ) { 459 | lib.symbols.DrawPolyLinesEx( 460 | center.buffer, 461 | sides, 462 | radius, 463 | rotation, 464 | lineThick, 465 | color.buffer, 466 | ); 467 | } 468 | } 469 | 470 | // TODO 471 | // RLAPI void SetShapesTexture(Texture2D texture, Rectangle source); // Set texture and rectangle to be used on shapes drawing 472 | -------------------------------------------------------------------------------- /src/shapes3d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Functions for drawing 3d shapes 3 | * @module 4 | */ 5 | import { lib } from "../bindings/bindings.ts"; 6 | import type { Color } from "./color.ts"; 7 | import type { Ray, Vector2, Vector3 } from "./_util.ts"; 8 | 9 | /** Shape drawing functions */ 10 | export class Shapes3D { 11 | /** Draw a line in 3D world space */ 12 | static drawLine3D(startPos: Vector3, endPos: Vector3, color: Color) { 13 | lib.symbols.DrawLine3D(startPos.buffer, endPos.buffer, color.buffer); 14 | } 15 | 16 | /** Draw a point in 3D space, actually a small line */ 17 | static drawPoint3D(position: Vector3, color: Color) { 18 | lib.symbols.DrawPoint3D(position.buffer, color.buffer); 19 | } 20 | 21 | /** Draw a circle in 3D world space */ 22 | static drawCircle3D( 23 | center: Vector3, 24 | radius: number, 25 | rotationAxis: Vector3, 26 | rotationAngle: number, 27 | color: Color, 28 | ) { 29 | lib.symbols.DrawCircle3D( 30 | center.buffer, 31 | radius, 32 | rotationAxis.buffer, 33 | rotationAngle, 34 | color.buffer, 35 | ); 36 | } 37 | 38 | /** Draw a color-filled triangle (vertex in counter-clockwise order!) */ 39 | static drawTriangle3D(v1: Vector3, v2: Vector3, v3: Vector3, color: Color) { 40 | lib.symbols.DrawTriangle3D(v1.buffer, v2.buffer, v3.buffer, color.buffer); 41 | } 42 | 43 | // TODO 44 | // RLAPI void DrawTriangleStrip3D(Vector3 *points, int pointCount, Color color); // Draw a triangle strip defined by points 45 | 46 | /** Draw cube */ 47 | static drawCube( 48 | position: Vector3, 49 | width: number, 50 | height: number, 51 | length: number, 52 | color: Color, 53 | ) { 54 | lib.symbols.DrawCube(position.buffer, width, height, length, color.buffer); 55 | } 56 | 57 | /** Draw cube (Vector version) */ 58 | static drawCubeV(position: Vector3, size: Vector3, color: Color) { 59 | lib.symbols.DrawCubeV(position.buffer, size.buffer, color.buffer); 60 | } 61 | 62 | /** Draw cube wires */ 63 | static drawCubeWires( 64 | position: Vector3, 65 | width: number, 66 | height: number, 67 | length: number, 68 | color: Color, 69 | ) { 70 | lib.symbols.DrawCubeWires( 71 | position.buffer, 72 | width, 73 | height, 74 | length, 75 | color.buffer, 76 | ); 77 | } 78 | 79 | /** Draw cube wires (Vector version) */ 80 | static drawCubeWiresV(position: Vector3, size: Vector3, color: Color) { 81 | lib.symbols.DrawCubeWiresV(position.buffer, size.buffer, color.buffer); 82 | } 83 | 84 | /** Draw sphere */ 85 | static drawSphere(centerPos: Vector3, radius: number, color: Color) { 86 | lib.symbols.DrawSphere(centerPos.buffer, radius, color.buffer); 87 | } 88 | 89 | /** Draw sphere with extended parameters */ 90 | static drawSphereEx( 91 | centerPos: Vector3, 92 | radius: number, 93 | rings: number, 94 | slices: number, 95 | color: Color, 96 | ) { 97 | lib.symbols.DrawSphereEx( 98 | centerPos.buffer, 99 | radius, 100 | rings, 101 | slices, 102 | color.buffer, 103 | ); 104 | } 105 | 106 | /** Draw sphere wires */ 107 | static drawSphereWires( 108 | centerPos: Vector3, 109 | radius: number, 110 | rings: number, 111 | slices: number, 112 | color: Color, 113 | ) { 114 | lib.symbols.DrawSphereWires( 115 | centerPos.buffer, 116 | radius, 117 | rings, 118 | slices, 119 | color.buffer, 120 | ); 121 | } 122 | 123 | /** Draw a cylinder/cone */ 124 | static drawCylinder( 125 | position: Vector3, 126 | radiusTop: number, 127 | radiusBottom: number, 128 | height: number, 129 | slices: number, 130 | color: Color, 131 | ) { 132 | lib.symbols.DrawCylinder( 133 | position.buffer, 134 | radiusTop, 135 | radiusBottom, 136 | height, 137 | slices, 138 | color.buffer, 139 | ); 140 | } 141 | 142 | /** Draw a cylinder with base at startPos and top at endPos */ 143 | static drawCylinderEx( 144 | startPos: Vector3, 145 | endPos: Vector3, 146 | startRadius: number, 147 | endRadius: number, 148 | sides: number, 149 | color: Color, 150 | ) { 151 | lib.symbols.DrawCylinderEx( 152 | startPos.buffer, 153 | endPos.buffer, 154 | startRadius, 155 | endRadius, 156 | sides, 157 | color.buffer, 158 | ); 159 | } 160 | 161 | /** Draw a cylinder/cone wires */ 162 | static drawCylinderWires( 163 | position: Vector3, 164 | radiusTop: number, 165 | radiusBottom: number, 166 | height: number, 167 | slices: number, 168 | color: Color, 169 | ) { 170 | lib.symbols.DrawCylinderWires( 171 | position.buffer, 172 | radiusTop, 173 | radiusBottom, 174 | height, 175 | slices, 176 | color.buffer, 177 | ); 178 | } 179 | 180 | /** Draw a cylinder wires with base at startPos and top at endPos */ 181 | static drawCylinderWiresEx( 182 | startPos: Vector3, 183 | endPos: Vector3, 184 | startRadius: number, 185 | endRadius: number, 186 | sides: number, 187 | color: Color, 188 | ) { 189 | lib.symbols.DrawCylinderWiresEx( 190 | startPos.buffer, 191 | endPos.buffer, 192 | startRadius, 193 | endRadius, 194 | sides, 195 | color.buffer, 196 | ); 197 | } 198 | 199 | /** Draw a capsule with the center of its sphere caps at startPos and endPos */ 200 | static drawCapsule( 201 | startPos: Vector3, 202 | endPos: Vector3, 203 | radius: number, 204 | slices: number, 205 | rings: number, 206 | color: Color, 207 | ) { 208 | lib.symbols.DrawCapsule( 209 | startPos.buffer, 210 | endPos.buffer, 211 | radius, 212 | slices, 213 | rings, 214 | color.buffer, 215 | ); 216 | } 217 | 218 | /** Draw capsule wireframe with the center of its sphere caps at startPos and endPos */ 219 | static drawCapsuleWires( 220 | startPos: Vector3, 221 | endPos: Vector3, 222 | radius: number, 223 | slices: number, 224 | rings: number, 225 | color: Color, 226 | ) { 227 | lib.symbols.DrawCapsuleWires( 228 | startPos.buffer, 229 | endPos.buffer, 230 | radius, 231 | slices, 232 | rings, 233 | color.buffer, 234 | ); 235 | } 236 | 237 | /** Draw a plane XZ */ 238 | static drawPlane(centerPos: Vector3, size: Vector2, color: Color) { 239 | lib.symbols.DrawPlane(centerPos.buffer, size.buffer, color.buffer); 240 | } 241 | 242 | /** Draw a ray line */ 243 | static drawRay(ray: Ray, color: Color) { 244 | lib.symbols.DrawRay(ray.buffer, color.buffer); 245 | } 246 | 247 | /** Draw a grid (centered at (0, 0, 0)) */ 248 | static drawGrid(slices: number, spacing: number) { 249 | lib.symbols.DrawGrid(slices, spacing); 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /src/sound.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Functions for dealing with sound and waves 3 | * @module 4 | */ 5 | import { lib } from "../bindings/bindings.ts"; 6 | 7 | /** Wave functions */ 8 | export class Wave { 9 | #buffer: Uint8Array; 10 | /** Avoid using if at all possible */ 11 | constructor(buffer: Uint8Array) { 12 | this.#buffer = buffer; 13 | } 14 | 15 | get buffer(): Uint8Array { 16 | return this.#buffer; 17 | } 18 | 19 | /** Total number of frames (considering channels) */ 20 | get frameCount(): number { 21 | const view = new DataView(this.#buffer.buffer); 22 | return view.getUint32(0, true); 23 | } 24 | 25 | /** Frequency (samples per second) */ 26 | get sampleRate(): number { 27 | const view = new DataView(this.#buffer.buffer); 28 | return view.getUint32(4, true); 29 | } 30 | 31 | /** Bit depth (bits per sample): 8, 16, 32 (24 not supported) */ 32 | get sampleSize(): number { 33 | const view = new DataView(this.#buffer.buffer); 34 | return view.getUint32(8, true); 35 | } 36 | 37 | /** Number of channels (1-mono, 2-stereo, ...) */ 38 | get channels(): number { 39 | const view = new DataView(this.#buffer.buffer); 40 | return view.getUint32(12, true); 41 | } 42 | 43 | /** Load wave data from file */ 44 | static load(filename: string): Wave { 45 | const encoded = new TextEncoder().encode(filename + "\0"); 46 | return new Wave(lib.symbols.LoadWave(encoded)); 47 | } 48 | 49 | /** Load wave from memory buffer, fileType refers to extension: i.e. '.wav' */ 50 | static loadFromMemory(fileType: string, fileData: Uint8Array): Wave { 51 | const encoded = new TextEncoder().encode(fileType + "\0"); 52 | return new Wave( 53 | lib.symbols.LoadWaveFromMemory( 54 | encoded, 55 | Deno.UnsafePointer.of(fileData), 56 | fileData.length, 57 | ), 58 | ); 59 | } 60 | 61 | /** Checks if wave data is ready */ 62 | isReady(): boolean { 63 | return !!lib.symbols.IsWaveReady(this.#buffer); 64 | } 65 | 66 | /** Unload wave data */ 67 | unload() { 68 | lib.symbols.UnloadWave(this.#buffer); 69 | } 70 | 71 | /** Export wave data to file, returns true on success */ 72 | export(filename: string): boolean { 73 | const encoded = new TextEncoder().encode(filename + "\0"); 74 | return !!lib.symbols.ExportWave(this.#buffer, encoded); 75 | } 76 | 77 | /** Export wave sample data to code (.h), returns true on success */ 78 | exportAsCode(filename: string): boolean { 79 | const encoded = new TextEncoder().encode(filename + "\0"); 80 | return !!lib.symbols.ExportWaveAsCode(this.#buffer, encoded); 81 | } 82 | 83 | /** Copy a wave to a new wave */ 84 | copy(): Wave { 85 | return new Wave(lib.symbols.WaveCopy(this.#buffer)); 86 | } 87 | 88 | /** Crop this wave to defined samples range */ 89 | crop(initSample: number, finalSample: number) { 90 | lib.symbols.WaveCrop( 91 | Deno.UnsafePointer.of(this.#buffer), 92 | initSample, 93 | finalSample, 94 | ); 95 | } 96 | 97 | /** Convert wave data to desired format */ 98 | format(sampleRate: number, sampleSize: number, channels: number) { 99 | lib.symbols.WaveFormat( 100 | Deno.UnsafePointer.of(this.#buffer), 101 | sampleRate, 102 | sampleSize, 103 | channels, 104 | ); 105 | } 106 | 107 | /** Load samples data from wave as a 32bit float data array */ 108 | getSamples(): Float32Array { 109 | const pointer = lib.symbols.LoadWaveSamples(this.#buffer)!; 110 | const view = new Deno.UnsafePointerView(pointer); 111 | const samples = new Float32Array(this.frameCount * this.channels); 112 | 113 | for (let i = 0; i < samples.length; i++) { 114 | samples[i] = view.getFloat32(i * 4); 115 | } 116 | 117 | // unload pointer 118 | lib.symbols.UnloadWaveSamples(pointer); 119 | 120 | return samples; 121 | } 122 | } 123 | 124 | /** Sound functions */ 125 | export class Sound { 126 | #buffer: Uint8Array; 127 | /** Avoid using if at all possible */ 128 | constructor(buffer: Uint8Array) { 129 | this.#buffer = buffer; 130 | } 131 | 132 | get buffer(): Uint8Array { 133 | return this.#buffer; 134 | } 135 | 136 | /** Load sound from file */ 137 | static load(filename: string): Sound { 138 | const encoded = new TextEncoder().encode(filename + "\0"); 139 | return new Sound(lib.symbols.LoadSound(encoded)); 140 | } 141 | 142 | /** Load sound from wave data */ 143 | static loadFromWave(wave: Wave): Sound { 144 | return new Sound(lib.symbols.LoadSoundFromWave(wave.buffer)); 145 | } 146 | 147 | /** Create a new sound that shares the same sample data as the source sound, does not own the sound data */ 148 | static loadAlias(source: Sound): Sound { 149 | return new Sound(lib.symbols.LoadSoundAlias(source.buffer)); 150 | } 151 | 152 | /** Checks if a sound is ready */ 153 | isReady(): boolean { 154 | return !!lib.symbols.IsSoundReady(this.#buffer); 155 | } 156 | 157 | /** Update sound buffer with new data */ 158 | update(data: Float32Array) { 159 | lib.symbols.UpdateSound( 160 | this.#buffer, 161 | Deno.UnsafePointer.of(data), 162 | data.length, 163 | ); 164 | } 165 | 166 | /** Unload sound */ 167 | unload() { 168 | lib.symbols.UnloadSound(this.#buffer); 169 | } 170 | 171 | /** Unload a sound alias (does not deallocate sample data) */ 172 | unloadAlias() { 173 | lib.symbols.UnloadSoundAlias(this.#buffer); 174 | } 175 | 176 | /** Play a sound */ 177 | play() { 178 | lib.symbols.PlaySound(this.#buffer); 179 | } 180 | 181 | /** Stop playing a sound */ 182 | stop() { 183 | lib.symbols.StopSound(this.#buffer); 184 | } 185 | 186 | /** Pause a sound */ 187 | pause() { 188 | lib.symbols.PauseSound(this.#buffer); 189 | } 190 | 191 | /** Resume a paused sound */ 192 | resume() { 193 | lib.symbols.ResumeSound(this.#buffer); 194 | } 195 | 196 | /** Check if a sound is currently playing */ 197 | isPlaying(): boolean { 198 | return !!lib.symbols.IsSoundPlaying(this.#buffer); 199 | } 200 | 201 | /** Set volume for a sound (1.0 is max level) */ 202 | setVolume(volume: number) { 203 | lib.symbols.SetSoundVolume(this.#buffer, volume); 204 | } 205 | 206 | /** Set pitch for a sound (1.0 is base level) */ 207 | setPitch(pitch: number) { 208 | lib.symbols.SetSoundPitch(this.#buffer, pitch); 209 | } 210 | 211 | /** Set pan for a sound (0.5 is center) */ 212 | setPan(pan: number) { 213 | lib.symbols.SetSoundPan(this.#buffer, pan); 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /src/splines.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Spline drawing functions 3 | * @module 4 | */ 5 | import { lib } from "../bindings/bindings.ts"; 6 | import type { Color } from "./color.ts"; 7 | import { Vector2 } from "./_util.ts"; 8 | import { concatVector2s } from "./_helper.ts"; 9 | 10 | /** Spline functions */ 11 | export class Spline { 12 | /** Draw spline: Linear, minimum 2 points */ 13 | static drawLinear(points: Vector2[], thick: number, color: Color): void { 14 | const pointBuffer = concatVector2s(points); 15 | lib.symbols.DrawSplineLinear( 16 | Deno.UnsafePointer.of(pointBuffer), 17 | points.length, 18 | thick, 19 | color.buffer, 20 | ); 21 | } 22 | 23 | /** Draw spline: B-Spline, minimum 4 points */ 24 | static drawBasis(points: Vector2[], thick: number, color: Color): void { 25 | const pointBuffer = concatVector2s(points); 26 | lib.symbols.DrawSplineBasis( 27 | Deno.UnsafePointer.of(pointBuffer), 28 | points.length, 29 | thick, 30 | color.buffer, 31 | ); 32 | } 33 | 34 | /** Draw spline: Catmull-Rom, minimum 4 points */ 35 | static drawCatmullRom(points: Vector2[], thick: number, color: Color): void { 36 | const pointBuffer = concatVector2s(points); 37 | lib.symbols.DrawSplineCatmullRom( 38 | Deno.UnsafePointer.of(pointBuffer), 39 | points.length, 40 | thick, 41 | color.buffer, 42 | ); 43 | } 44 | 45 | /** Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...] */ 46 | static drawBezierQuadratic( 47 | points: Vector2[], 48 | thick: number, 49 | color: Color, 50 | ): void { 51 | const pointBuffer = concatVector2s(points); 52 | lib.symbols.DrawSplineBezierQuadratic( 53 | Deno.UnsafePointer.of(pointBuffer), 54 | points.length, 55 | thick, 56 | color.buffer, 57 | ); 58 | } 59 | 60 | /** Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...] */ 61 | static drawBezierCubic(points: Vector2[], thick: number, color: Color): void { 62 | const pointBuffer = concatVector2s(points); 63 | lib.symbols.DrawSplineBezierCubic( 64 | Deno.UnsafePointer.of(pointBuffer), 65 | points.length, 66 | thick, 67 | color.buffer, 68 | ); 69 | } 70 | 71 | /** Draw spline segment: Linear, 2 points */ 72 | drawSegmentLinear( 73 | p1: Vector2, 74 | p2: Vector2, 75 | thick: number, 76 | color: Color, 77 | ): void { 78 | lib.symbols.DrawSplineSegmentLinear( 79 | p1.buffer, 80 | p2.buffer, 81 | thick, 82 | color.buffer, 83 | ); 84 | } 85 | 86 | /** Draw spline segment: B-Spline, 4 points */ 87 | drawSegmentBasis( 88 | p1: Vector2, 89 | p2: Vector2, 90 | p3: Vector2, 91 | p4: Vector2, 92 | thick: number, 93 | color: Color, 94 | ): void { 95 | lib.symbols.DrawSplineSegmentBasis( 96 | p1.buffer, 97 | p2.buffer, 98 | p3.buffer, 99 | p4.buffer, 100 | thick, 101 | color.buffer, 102 | ); 103 | } 104 | 105 | /** Draw spline segment: Catmull-Rom, 4 points */ 106 | drawSegmentCatmullRom( 107 | p1: Vector2, 108 | p2: Vector2, 109 | p3: Vector2, 110 | p4: Vector2, 111 | thick: number, 112 | color: Color, 113 | ): void { 114 | lib.symbols.DrawSplineSegmentCatmullRom( 115 | p1.buffer, 116 | p2.buffer, 117 | p3.buffer, 118 | p4.buffer, 119 | thick, 120 | color.buffer, 121 | ); 122 | } 123 | 124 | /** Draw spline segment: Catmull-Rom, 4 points */ 125 | drawSegmentBezierQuadratic( 126 | p1: Vector2, 127 | c2: Vector2, 128 | p3: Vector2, 129 | thick: number, 130 | color: Color, 131 | ): void { 132 | lib.symbols.DrawSplineSegmentBezierQuadratic( 133 | p1.buffer, 134 | c2.buffer, 135 | p3.buffer, 136 | thick, 137 | color.buffer, 138 | ); 139 | } 140 | 141 | /** Draw spline segment: Cubic Bezier, 2 points, 2 control points */ 142 | drawSegmentBezierCubic( 143 | p1: Vector2, 144 | c2: Vector2, 145 | c3: Vector2, 146 | p4: Vector2, 147 | thick: number, 148 | color: Color, 149 | ): void { 150 | lib.symbols.DrawSplineSegmentBezierCubic( 151 | p1.buffer, 152 | c2.buffer, 153 | c3.buffer, 154 | p4.buffer, 155 | thick, 156 | color.buffer, 157 | ); 158 | } 159 | 160 | /** Get (evaluate) spline point: Linear */ 161 | getPointLinear(startPos: Vector2, endPos: Vector2, t: number): Vector2 { 162 | return Vector2.fromBuffer( 163 | lib.symbols.GetSplinePointLinear(startPos.buffer, endPos.buffer, t) 164 | .buffer, 165 | ); 166 | } 167 | 168 | /** Get (evaluate) spline point: B-Spline */ 169 | getPointBasis( 170 | p1: Vector2, 171 | p2: Vector2, 172 | p3: Vector2, 173 | p4: Vector2, 174 | t: number, 175 | ): Vector2 { 176 | return Vector2.fromBuffer( 177 | lib.symbols.GetSplinePointBasis( 178 | p1.buffer, 179 | p2.buffer, 180 | p3.buffer, 181 | p4.buffer, 182 | t, 183 | ).buffer, 184 | ); 185 | } 186 | 187 | /** Get (evaluate) spline point: Catmull-Rom */ 188 | getPointCatmullRom( 189 | p1: Vector2, 190 | p2: Vector2, 191 | p3: Vector2, 192 | p4: Vector2, 193 | t: number, 194 | ): Vector2 { 195 | return Vector2.fromBuffer( 196 | lib.symbols.GetSplinePointCatmullRom( 197 | p1.buffer, 198 | p2.buffer, 199 | p3.buffer, 200 | p4.buffer, 201 | t, 202 | ).buffer, 203 | ); 204 | } 205 | 206 | /** Get (evaluate) spline point: Quadratic Bezier */ 207 | getPointBezierQuad( 208 | p1: Vector2, 209 | c2: Vector2, 210 | p3: Vector2, 211 | t: number, 212 | ): Vector2 { 213 | return Vector2.fromBuffer( 214 | lib.symbols.GetSplinePointBezierQuad(p1.buffer, c2.buffer, p3.buffer, t) 215 | .buffer, 216 | ); 217 | } 218 | 219 | /** Get (evaluate) spline point: Cubic Bezier */ 220 | getPointBezierCubic( 221 | p1: Vector2, 222 | c2: Vector2, 223 | c3: Vector2, 224 | p4: Vector2, 225 | t: number, 226 | ): Vector2 { 227 | return Vector2.fromBuffer( 228 | lib.symbols.GetSplinePointBezierCubic( 229 | p1.buffer, 230 | c2.buffer, 231 | c3.buffer, 232 | p4.buffer, 233 | t, 234 | ).buffer, 235 | ); 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /src/text.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Text utility functions 3 | * @module 4 | */ 5 | import { lib } from "../bindings/bindings.ts"; 6 | import type { Color } from "./color.ts"; 7 | import type { Font } from "./font.ts"; 8 | import { Vector2 } from "./_util.ts"; 9 | 10 | /** Text-related functions */ 11 | export class Text { 12 | /** Draw current FPS */ 13 | static drawFPS(x: number, y: number) { 14 | lib.symbols.DrawFPS(x, y); 15 | } 16 | 17 | /** Draw text (using default font) */ 18 | static drawText( 19 | text: string, 20 | x: number, 21 | y: number, 22 | fontSize: number, 23 | color: Color, 24 | ) { 25 | lib.symbols.DrawText( 26 | new TextEncoder().encode(text + "\0"), 27 | x, 28 | y, 29 | fontSize, 30 | color.buffer, 31 | ); 32 | } 33 | 34 | /** Draw text using font and additional parameters */ 35 | static drawTextEx( 36 | font: Font, 37 | text: string, 38 | position: Vector2, 39 | fontSize: number, 40 | spacing: number, 41 | tint: Color, 42 | ) { 43 | lib.symbols.DrawTextEx( 44 | font.buffer, 45 | new TextEncoder().encode(text + "\0"), 46 | position.buffer, 47 | fontSize, 48 | spacing, 49 | tint.buffer, 50 | ); 51 | } 52 | 53 | /** Draw text using Font and pro parameters (rotation) */ 54 | static drawTextPro( 55 | font: Font, 56 | text: string, 57 | position: Vector2, 58 | origin: Vector2, 59 | rotation: number, 60 | fontSize: number, 61 | spacing: number, 62 | tint: Color, 63 | ) { 64 | lib.symbols.DrawTextPro( 65 | font.buffer, 66 | new TextEncoder().encode(text + "\0"), 67 | position.buffer, 68 | origin.buffer, 69 | rotation, 70 | fontSize, 71 | spacing, 72 | tint.buffer, 73 | ); 74 | } 75 | 76 | /** Set vertical line spacing when drawing with line-breaks */ 77 | static setTextLineSpacing(spacing: number) { 78 | lib.symbols.SetTextLineSpacing(spacing); 79 | } 80 | 81 | /** Measure string width for default font */ 82 | static measureText(text: string, fontSize: number): number { 83 | return lib.symbols.MeasureText( 84 | new TextEncoder().encode(text + "\0"), 85 | fontSize, 86 | ); 87 | } 88 | 89 | /** Measure string size for Font */ 90 | static measureTextEx( 91 | font: Font, 92 | text: string, 93 | fontSize: number, 94 | spacing: number, 95 | ): Vector2 { 96 | return Vector2.fromBuffer( 97 | lib.symbols.MeasureTextEx( 98 | font.buffer, 99 | new TextEncoder().encode(text + "\0"), 100 | fontSize, 101 | spacing, 102 | ).buffer, 103 | ); 104 | } 105 | } 106 | 107 | // TODO 108 | // RLAPI void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSize, Color tint); // Draw one character (codepoint) 109 | // RLAPI void DrawTextCodepoints(Font font, const int *codepoints, int codepointCount, Vector2 position, float fontSize, float spacing, Color tint); // Draw multiple character (codepoint) 110 | // RLAPI int GetGlyphIndex(Font font, int codepoint); // Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found 111 | // RLAPI GlyphInfo GetGlyphInfo(Font font, int codepoint); // Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found 112 | // RLAPI Rectangle GetGlyphAtlasRec(Font font, int codepoint); // Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found 113 | -------------------------------------------------------------------------------- /src/texture.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Texture utility functions 3 | * @module 4 | */ 5 | import { lib } from "../bindings/bindings.ts"; 6 | import { littleEndian } from "./_helper.ts"; 7 | import type { Rectangle, Vector2 } from "./_util.ts"; 8 | import type { Color } from "./color.ts"; 9 | import type { Image } from "./image.ts"; 10 | 11 | const nPatchLayout = { 12 | ninePatch: 0, 13 | threePatchVertical: 1, 14 | threePatchHorizontal: 2, 15 | }; 16 | 17 | /** The method to use when scaling textures */ 18 | export type NPatchLayout = keyof typeof nPatchLayout; 19 | 20 | /** A small class for use with scaling textures nicely */ 21 | export class NPatchInfo { 22 | constructor( 23 | /** Texture source rectangle */ 24 | public source: Rectangle, 25 | /** Left border offset */ 26 | public left: number, 27 | /** Top border offset */ 28 | public top: number, 29 | /** Right border offset */ 30 | public right: number, 31 | /** Bottom border offset */ 32 | public bottom: number, 33 | /** Layout of the n-patch: 3x3, 1x3 or 3x1 */ 34 | public layout: NPatchLayout, 35 | ) {} 36 | 37 | get buffer(): ArrayBuffer { 38 | const view = new DataView(new ArrayBuffer(36)); 39 | view.setFloat32(0, this.source.x, littleEndian); 40 | view.setFloat32(4, this.source.y, littleEndian); 41 | view.setFloat32(8, this.source.width, littleEndian); 42 | view.setFloat32(12, this.source.height, littleEndian); 43 | view.setInt32(16, this.left, littleEndian); 44 | view.setInt32(20, this.top, littleEndian); 45 | view.setInt32(24, this.right, littleEndian); 46 | view.setInt32(28, this.bottom, littleEndian); 47 | view.setInt32(32, nPatchLayout[this.layout], littleEndian); 48 | return view.buffer; 49 | } 50 | } 51 | 52 | const textureFilter = { 53 | point: 0, 54 | bilinear: 1, 55 | trilinear: 2, 56 | anisotropic4x: 3, 57 | anisotropic8x: 4, 58 | anisotropic16x: 5, 59 | }; 60 | 61 | export type TextureFilter = keyof typeof textureFilter; 62 | 63 | const textureWrap = { 64 | repeat: 0, 65 | clamp: 1, 66 | mirrorRepeat: 2, 67 | mirrorClamp: 3, 68 | }; 69 | 70 | export type TextureWrap = keyof typeof textureWrap; 71 | 72 | /** The class to create and mess with Texture2D instances */ 73 | export class Texture2D { 74 | #buffer: Uint8Array; 75 | /** Avoid using if at all possible */ 76 | constructor(buffer: Uint8Array) { 77 | this.#buffer = buffer; 78 | } 79 | 80 | get buffer(): Uint8Array { 81 | return this.#buffer; 82 | } 83 | 84 | /** Load texture from file into GPU memory (VRAM) */ 85 | static load(fileName: string): Texture2D { 86 | return new Texture2D( 87 | lib.symbols.LoadTexture(new TextEncoder().encode(fileName + "\0")), 88 | ); 89 | } 90 | 91 | /** Load texture from image data */ 92 | static loadFromImage(image: Image): Texture2D { 93 | return new Texture2D(lib.symbols.LoadTextureFromImage(image.buffer)); 94 | } 95 | 96 | /** Check if a texture is ready */ 97 | isReady(): boolean { 98 | return !!lib.symbols.IsTextureReady(this.#buffer); 99 | } 100 | 101 | /** Unload texture from GPU memory (VRAM) */ 102 | unload(): void { 103 | lib.symbols.UnloadTexture(this.#buffer); 104 | } 105 | 106 | /** Update GPU texture with new data */ 107 | update(pixels: ArrayBuffer): void { 108 | lib.symbols.UpdateTexture(this.#buffer, Deno.UnsafePointer.of(pixels)); 109 | } 110 | 111 | /** Update GPU texture rectangle with new data */ 112 | updateRectangle(rect: Rectangle, pixels: ArrayBuffer): void { 113 | lib.symbols.UpdateTextureRec( 114 | this.#buffer, 115 | rect.buffer, 116 | Deno.UnsafePointer.of(pixels), 117 | ); 118 | } 119 | 120 | /** Generate GPU mipmaps for a texture */ 121 | genMipmaps(): void { 122 | lib.symbols.GenTextureMipmaps(Deno.UnsafePointer.of(this.#buffer)); 123 | } 124 | 125 | /** Set texture scaling filter mode */ 126 | setFilter(filter: TextureFilter): void { 127 | lib.symbols.SetTextureFilter(this.#buffer, textureFilter[filter]); 128 | } 129 | 130 | /** Set texture wrapping mode */ 131 | setWrap(wrap: TextureWrap): void { 132 | lib.symbols.SetTextureWrap(this.#buffer, textureWrap[wrap]); 133 | } 134 | 135 | /** Draw a Texture2D */ 136 | draw(posX: number, posY: number, tint: Color): void { 137 | lib.symbols.DrawTexture(this.#buffer, posX, posY, tint.buffer); 138 | } 139 | 140 | /** Draw a Texture2D with position defined as Vector2 */ 141 | drawV(position: Vector2, tint: Color): void { 142 | lib.symbols.DrawTextureV(this.#buffer, position.buffer, tint.buffer); 143 | } 144 | 145 | /** Draw a Texture2D with extended parameters */ 146 | drawEx( 147 | position: Vector2, 148 | rotation: number, 149 | scale: number, 150 | tint: Color, 151 | ): void { 152 | lib.symbols.DrawTextureEx( 153 | this.#buffer, 154 | position.buffer, 155 | rotation, 156 | scale, 157 | tint.buffer, 158 | ); 159 | } 160 | 161 | /** Draw a part of a texture defined by a rectangle */ 162 | drawRect(source: Rectangle, position: Vector2, tint: Color): void { 163 | lib.symbols.DrawTextureRec( 164 | this.#buffer, 165 | source.buffer, 166 | position.buffer, 167 | tint.buffer, 168 | ); 169 | } 170 | 171 | /** Draw a part of a texture defined by a rectangle with 'pro' parameters */ 172 | drawPro( 173 | source: Rectangle, 174 | dest: Rectangle, 175 | origin: Vector2, 176 | rotation: number, 177 | tint: Color, 178 | ): void { 179 | lib.symbols.DrawTexturePro( 180 | this.#buffer, 181 | source.buffer, 182 | dest.buffer, 183 | origin.buffer, 184 | rotation, 185 | tint.buffer, 186 | ); 187 | } 188 | 189 | /** Draws a texture (or part of it) that stretches or shrinks nicely */ 190 | drawNPatch( 191 | nPatchInfo: NPatchInfo, 192 | dest: Rectangle, 193 | origin: Vector2, 194 | rotation: number, 195 | tint: Color, 196 | ): void { 197 | lib.symbols.DrawTextureNPatch( 198 | this.#buffer, 199 | nPatchInfo.buffer, 200 | dest.buffer, 201 | origin.buffer, 202 | rotation, 203 | tint.buffer, 204 | ); 205 | } 206 | } 207 | 208 | const textureCubemapLayout = { 209 | auto: 0, // Automatically detect layout type 210 | lineVertical: 1, // Layout is defined by a vertical line with faces 211 | lineHorizontal: 2, // Layout is defined by a horizontal line with faces 212 | crossThreeByFour: 3, // Layout is defined by a 3x4 cross with cubemap faces 213 | crossFourByThree: 4, // Layout is defined by a 4x3 cross with cubemap faces 214 | panorama: 5, // Layout is defined by a panorama image (equirrectangular map) 215 | }; 216 | 217 | export type TextureCubemapLayout = keyof typeof textureCubemapLayout; 218 | 219 | /** Class to create TextureCubemap instances */ 220 | export class TextureCubemap { 221 | #buffer: Uint8Array; 222 | /** Avoid using if at all possible */ 223 | constructor(buffer: Uint8Array) { 224 | this.#buffer = buffer; 225 | } 226 | 227 | get buffer(): Uint8Array { 228 | return this.#buffer; 229 | } 230 | 231 | /** Load cubemap from image, multiple image cubemap layouts supported */ 232 | static load(image: Image, layout: TextureCubemapLayout): TextureCubemap { 233 | return new TextureCubemap( 234 | lib.symbols.LoadTextureCubemap( 235 | image.buffer, 236 | textureCubemapLayout[layout], 237 | ), 238 | ); 239 | } 240 | } 241 | 242 | /** Class to create RenderTexture2D instances */ 243 | export class RenderTexture2D { 244 | #buffer: Uint8Array; 245 | /** Avoid using if at all possible */ 246 | constructor(buffer: Uint8Array) { 247 | this.#buffer = buffer; 248 | } 249 | 250 | get buffer(): Uint8Array { 251 | return this.#buffer; 252 | } 253 | 254 | /** Load texture for rendering (framebuffer) */ 255 | static load(width: number, height: number): RenderTexture2D { 256 | return new RenderTexture2D(lib.symbols.LoadRenderTexture(width, height)); 257 | } 258 | 259 | /** Check if a render texture is ready */ 260 | isReady(): boolean { 261 | return !!lib.symbols.IsRenderTextureReady(this.#buffer); 262 | } 263 | 264 | /** Unload render texture from GPU memory (VRAM) */ 265 | unload(): void { 266 | lib.symbols.UnloadRenderTexture(this.#buffer); 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /src/timing.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * A module for interacting with the timing system 3 | * @module 4 | */ 5 | import { lib } from "../bindings/bindings.ts"; 6 | 7 | /** A simple class for interacting with timings */ 8 | export class Timing { 9 | /** Set target FPS (maximum) */ 10 | static setTargetFPS(fps: number): void { 11 | lib.symbols.SetTargetFPS(fps); 12 | } 13 | 14 | /** Get time in seconds for last frame drawn (delta time) */ 15 | static getFrameTime(): number { 16 | return lib.symbols.GetFrameTime(); 17 | } 18 | 19 | /** Get elapsed time in seconds since InitWindow() */ 20 | static getTime(): number { 21 | return lib.symbols.GetTime(); 22 | } 23 | 24 | /** Returns current FPS */ 25 | static getFPS(): number { 26 | return lib.symbols.GetFPS(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/touch.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Touch utility functions 3 | * @module 4 | */ 5 | import { lib } from "../bindings/bindings.ts"; 6 | import { Vector2 } from "./_util.ts"; 7 | 8 | /** Touch functions */ 9 | export class Touch { 10 | /** Get touch position X for touch point 0 (relative to screen size) */ 11 | static getX(): number { 12 | return lib.symbols.GetTouchX(); 13 | } 14 | 15 | /** Get touch position Y for touch point 0 (relative to screen size) */ 16 | static getY(): number { 17 | return lib.symbols.GetTouchY(); 18 | } 19 | 20 | /** Get touch position XY for a touch point index (relative to screen size) */ 21 | static getPosition(index: number): Vector2 { 22 | return Vector2.fromBuffer(lib.symbols.GetTouchPosition(index).buffer); 23 | } 24 | 25 | /** Get touch point identifier for given index */ 26 | static getId(index: number): number { 27 | return lib.symbols.GetTouchPointId(index); 28 | } 29 | 30 | /** Get number of touch points */ 31 | static getCount(): number { 32 | return lib.symbols.GetTouchPointCount(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/vr.ts: -------------------------------------------------------------------------------- 1 | // TODO(lino-levan): Add VR support 2 | // RLAPI VrStereoConfig LoadVrStereoConfig(VrDeviceInfo device); // Load VR stereo config for VR simulator device parameters 3 | // RLAPI void UnloadVrStereoConfig(VrStereoConfig config); // Unload VR stereo config 4 | -------------------------------------------------------------------------------- /src/window.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Window-related functions 3 | * @module 4 | */ 5 | 6 | import { lib } from "../bindings/bindings.ts"; 7 | import { Vector2 } from "./_util.ts"; 8 | import type { Image } from "./image.ts"; 9 | 10 | /** System/Window config flags. By default all flags are set to false. */ 11 | export interface WindowState { 12 | /** Set to try enabling V-Sync on GPU */ 13 | vsync: boolean; 14 | /** Set to run program in fullscreen */ 15 | fullscreen: boolean; 16 | /** Set to allow resizable window */ 17 | resizable: boolean; 18 | /** Set to disable window decoration (frame and buttons) */ 19 | undecorated: boolean; 20 | /** Set to hide window */ 21 | hidden: boolean; 22 | /** Set to minimize window (iconify) */ 23 | minimized: boolean; 24 | /** Set to maximize window (expanded to monitor) */ 25 | maximized: boolean; 26 | /** Set to window non focused */ 27 | unfocused: boolean; 28 | /** Set to window always on top */ 29 | topmost: boolean; 30 | /** Set to allow windows running while minimized */ 31 | alwaysRun: boolean; 32 | /** Set to allow transparent framebuffer */ 33 | transparent: boolean; 34 | /** Set to support HighDPI */ 35 | highDPI: boolean; 36 | /** Set to support mouse passthrough, only supported when the undecorated flag is set as well */ 37 | mousePassthrough: boolean; 38 | /** Set to run program in borderless windowed mode */ 39 | borderless: boolean; 40 | /** Set to try enabling MSAA 4X */ 41 | msaa4x: boolean; 42 | /** Set to try enabling interlaced video format (for V3D) */ 43 | interlaced: boolean; 44 | } 45 | 46 | const FLAG_BITMASK = { 47 | vsync: 0x00000040, 48 | fullscreen: 0x00000002, 49 | resizable: 0x00000004, 50 | undecorated: 0x00000008, 51 | hidden: 0x00000080, 52 | minimized: 0x00000200, 53 | maximized: 0x00000400, 54 | unfocused: 0x00000800, 55 | topmost: 0x00001000, 56 | alwaysRun: 0x00000100, 57 | transparent: 0x00000010, 58 | highDPI: 0x00002000, 59 | mousePassthrough: 0x00004000, 60 | borderless: 0x00008000, 61 | msaa4x: 0x00000020, 62 | interlaced: 0x00010000, 63 | }; 64 | 65 | /** A class representing a window */ 66 | export class Window { 67 | /** Initialize window and OpenGL context */ 68 | static init( 69 | width: number, 70 | height: number, 71 | title: string, 72 | flags?: Partial, 73 | ) { 74 | // Initialize window configuration flags 75 | if (flags) { 76 | const flag = Object.keys(flags).reduce((acc, key) => { 77 | return acc | FLAG_BITMASK[key as keyof WindowState]; 78 | }, 0); 79 | lib.symbols.SetConfigFlags(flag); 80 | } 81 | 82 | // Initialize window 83 | lib.symbols.InitWindow( 84 | width, 85 | height, 86 | new TextEncoder().encode(title + "\0"), 87 | ); 88 | } 89 | 90 | /** Close window and unload OpenGL context */ 91 | static close(): void { 92 | lib.symbols.CloseWindow(); 93 | } 94 | 95 | /** Check if application should close (KEY_ESCAPE pressed or windows close icon clicked) */ 96 | static shouldClose(): boolean { 97 | return !!lib.symbols.WindowShouldClose(); 98 | } 99 | 100 | /** Check if window has been initialized successfully */ 101 | static isReady(): boolean { 102 | return !!lib.symbols.IsWindowReady(); 103 | } 104 | 105 | /** Check if window is currently fullscreen */ 106 | static isFullscreen(): boolean { 107 | return !!lib.symbols.IsWindowFullscreen(); 108 | } 109 | 110 | /** Check if window is currently hidden */ 111 | static isHidden(): boolean { 112 | return !!lib.symbols.IsWindowHidden(); 113 | } 114 | 115 | /** Check if window is currently minimized */ 116 | static isMinimized(): boolean { 117 | return !!lib.symbols.IsWindowMinimized(); 118 | } 119 | 120 | /** Check if window is currently maximized */ 121 | static isMaximized(): boolean { 122 | return !!lib.symbols.IsWindowMaximized(); 123 | } 124 | 125 | /** Check if window is currently focused */ 126 | static isFocused(): boolean { 127 | return !!lib.symbols.IsWindowFocused(); 128 | } 129 | 130 | /** Check if window has been resized last frame */ 131 | static isResized(): boolean { 132 | return !!lib.symbols.IsWindowResized(); 133 | } 134 | 135 | /** Check if one specific window flag is enabled */ 136 | static isState(flags: Partial): boolean { 137 | const flag = Object.keys(flags).reduce((acc, key) => { 138 | return acc | FLAG_BITMASK[key as keyof WindowState]; 139 | }, 0); 140 | return !!lib.symbols.IsWindowState(flag); 141 | } 142 | 143 | /** Set window configuration state using flags */ 144 | static setState(flags: Partial): void { 145 | const flag = Object.keys(flags).reduce((acc, key) => { 146 | return acc | FLAG_BITMASK[key as keyof WindowState]; 147 | }, 0); 148 | lib.symbols.SetWindowState(flag); 149 | } 150 | 151 | /** Clear window configuration state flags */ 152 | static clearState(flags: Partial): void { 153 | const flag = Object.keys(flags).reduce((acc, key) => { 154 | return acc | FLAG_BITMASK[key as keyof WindowState]; 155 | }, 0); 156 | lib.symbols.ClearWindowState(flag); 157 | } 158 | 159 | /** Toggle window state: fullscreen/windowed */ 160 | static toggleFullscreen(): void { 161 | lib.symbols.ToggleFullscreen(); 162 | } 163 | 164 | /** Toggle window state: borderless windowed */ 165 | static toggleBorderlessWindowed(): void { 166 | lib.symbols.ToggleBorderlessWindowed(); 167 | } 168 | 169 | /** Set window state: maximized, if resizable */ 170 | static maximize(): void { 171 | lib.symbols.MaximizeWindow(); 172 | } 173 | 174 | /** Set window state: minimized, if resizable */ 175 | static minimize(): void { 176 | lib.symbols.MinimizeWindow(); 177 | } 178 | 179 | /** Set window state: not minimized/maximized */ 180 | static restore(): void { 181 | lib.symbols.RestoreWindow(); 182 | } 183 | 184 | /** Set icon for window (single image, RGBA 32bit) */ 185 | static setIcon(image: Image): void { 186 | lib.symbols.SetWindowIcon(image.buffer); 187 | } 188 | 189 | /** Set icon for window (multiple images, RGBA 32bit) */ 190 | static setIcons(images: Image[]): void { 191 | const buffer = new Uint8Array(24 * images.length); 192 | for (let i = 0; i < images.length; i++) { 193 | buffer.set(new Uint8Array(images[i].buffer), 24 * i); 194 | } 195 | 196 | lib.symbols.SetWindowIcons(Deno.UnsafePointer.of(buffer), images.length); 197 | } 198 | 199 | /** Set title for window */ 200 | static setTitle(title: string): void { 201 | lib.symbols.SetWindowTitle(new TextEncoder().encode(title + "\0")); 202 | } 203 | 204 | /** Set window position on screen */ 205 | static setPosition(x: number, y: number): void { 206 | lib.symbols.SetWindowPosition(x, y); 207 | } 208 | 209 | // TODO: Rethink this API 210 | /** Set monitor for the current window */ 211 | static setMonitor(monitor: number): void { 212 | lib.symbols.SetWindowMonitor(monitor); 213 | } 214 | 215 | /** Set window minimum dimensions (for resizable windows) */ 216 | static setMinSize(width: number, height: number): void { 217 | lib.symbols.SetWindowMinSize(width, height); 218 | } 219 | 220 | /** Set window maximum dimensions (for resizable windows) */ 221 | static setMaxSize(width: number, height: number): void { 222 | lib.symbols.SetWindowMaxSize(width, height); 223 | } 224 | 225 | /** Set window dimensions */ 226 | static setSize(width: number, height: number): void { 227 | lib.symbols.SetWindowSize(width, height); 228 | } 229 | 230 | /** Set window opacity [0.0f..1.0f] */ 231 | static setOpacity(opacity: number): void { 232 | lib.symbols.SetWindowOpacity(opacity); 233 | } 234 | 235 | /** Set window focused */ 236 | static setFocused(): void { 237 | lib.symbols.SetWindowFocused(); 238 | } 239 | 240 | /** Get native window handle (DANGEROUS) */ 241 | static getHandle(): Deno.PointerValue { 242 | return lib.symbols.GetWindowHandle(); 243 | } 244 | 245 | /** Get window position XY on monitor */ 246 | static getPosition(): Vector2 { 247 | return Vector2.fromBuffer(lib.symbols.GetWindowPosition().buffer); 248 | } 249 | 250 | /** Get window scale DPI factor */ 251 | static getScaleDPI(): Vector2 { 252 | return Vector2.fromBuffer( 253 | lib.symbols.GetWindowScaleDPI().buffer as ArrayBuffer, 254 | ); 255 | } 256 | 257 | /** Enable waiting for events on EndDrawing(), no automatic event polling */ 258 | static enableEventWaiting(): void { 259 | lib.symbols.EnableEventWaiting(); 260 | } 261 | 262 | /** Disable waiting for events on EndDrawing(), resume automatic event polling */ 263 | static disableEventWaiting(): void { 264 | lib.symbols.DisableEventWaiting(); 265 | } 266 | } 267 | 268 | /** A class to interact with the screen */ 269 | export class Screen { 270 | /** Get current screen width */ 271 | static getWidth(): number { 272 | return lib.symbols.GetScreenWidth(); 273 | } 274 | 275 | /** Get current screen height */ 276 | static getHeight(): number { 277 | return lib.symbols.GetScreenHeight(); 278 | } 279 | 280 | /** Get current render width (it considers HiDPI) */ 281 | static getRenderWidth(): number { 282 | return lib.symbols.GetRenderWidth(); 283 | } 284 | 285 | /** Get current render height (it considers HiDPI) */ 286 | static getRenderHeight(): number { 287 | return lib.symbols.GetRenderHeight(); 288 | } 289 | } 290 | 291 | /** A class to interact with a monitor object */ 292 | export class Monitor { 293 | #id: number; 294 | /** Do not construct manually if at all possible. */ 295 | constructor(id: number) { 296 | this.#id = id; 297 | } 298 | 299 | /** Get number of connected monitors */ 300 | static getCount(): number { 301 | return lib.symbols.GetMonitorCount(); 302 | } 303 | 304 | /** Get current connected monitor */ 305 | static getCurrent(): Monitor { 306 | return new Monitor(lib.symbols.GetCurrentMonitor()); 307 | } 308 | 309 | /** Get monitor position */ 310 | getPosition(): { x: number; y: number } { 311 | const pos = new DataView(lib.symbols.GetMonitorPosition(this.#id).buffer); 312 | return { x: pos.getFloat32(0), y: pos.getFloat32(4) }; 313 | } 314 | 315 | /** Get specified monitor width (current video mode used by monitor) */ 316 | getWidth(): number { 317 | return lib.symbols.GetMonitorWidth(this.#id); 318 | } 319 | 320 | /** Get specified monitor height (current video mode used by monitor) */ 321 | getHeight(): number { 322 | return lib.symbols.GetMonitorHeight(this.#id); 323 | } 324 | 325 | /** Get specified monitor physical width in millimetres */ 326 | getPhysicalWidth(): number { 327 | return lib.symbols.GetMonitorPhysicalWidth(this.#id); 328 | } 329 | 330 | /** Get specified monitor physical height in millimetres */ 331 | getPhysicalHeight(): number { 332 | return lib.symbols.GetMonitorPhysicalHeight(this.#id); 333 | } 334 | 335 | /** Get specified monitor refresh rate */ 336 | getRefreshRate(): number { 337 | return lib.symbols.GetMonitorRefreshRate(this.#id); 338 | } 339 | 340 | /** Get the human-readable, UTF-8 encoded name of the primary monitor */ 341 | getName(): string { 342 | return new Deno.UnsafePointerView(lib.symbols.GetMonitorName(this.#id)!) 343 | .getCString(); 344 | } 345 | } 346 | 347 | // TODO(lino-levan): Investigate why this doesn't seem to work 348 | /** A class to interact with a clipboard object */ 349 | export class Clipboard { 350 | /** Get clipboard text content. */ 351 | static getText(): string { 352 | return new Deno.UnsafePointerView(lib.symbols.GetClipboardText()!) 353 | .getCString(); 354 | } 355 | 356 | /** Set clipboard text content. */ 357 | static setText(text: string): void { 358 | lib.symbols.SetClipboardText(new TextEncoder().encode(text + "\0")); 359 | } 360 | } 361 | --------------------------------------------------------------------------------