From 200e391be290558e81c48513f50a1e1a79ece613 Mon Sep 17 00:00:00 2001 From: yilisharcs Date: Sun, 31 May 2026 03:40:26 -0300 Subject: [PATCH 1/3] chore: add nix flake and lua workspace configurations --- .editorconfig | 19 +++++++++++++++++++ .envrc | 1 + .gitignore | 2 ++ .luarc.jsonc | 32 ++++++++++++++++++++++++++++++++ .stylua.toml | 13 +++++++++++++ flake.lock | 27 +++++++++++++++++++++++++++ flake.nix | 36 ++++++++++++++++++++++++++++++++++++ 7 files changed, 130 insertions(+) create mode 100644 .editorconfig create mode 100644 .envrc create mode 100644 .luarc.jsonc create mode 100644 .stylua.toml create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..642b88b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 8 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{c,h}] +indent_size = 4 + +[*.lua] +indent_size = 4 +max_line_length = 120 + +[*.nix] +indent_size = 2 diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gitignore b/.gitignore index 122ecdd..f55bbc8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +/.direnv/ + # Compiled Lua sources luac.out diff --git a/.luarc.jsonc b/.luarc.jsonc new file mode 100644 index 0000000..3a696cb --- /dev/null +++ b/.luarc.jsonc @@ -0,0 +1,32 @@ +{ + "$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json", + "runtime": { + "version": "Lua 5.5", + }, + "workspace": { + "checkThirdParty": false + }, + "diagnostics": { + "unusedLocalExclude": [ + "_*" + ], + "groupFileStatus": { + "ambiguity": "Any", + "duplicate": "Any", + "global": "Any", + "luadoc": "None", + "redefined": "Any", + "strict": "Any", + "strong": "None", + "type-check": "Any", + "unbalanced": "Any", + "unused": "Any" + } + }, + "hint": { + "enable": true, + "setType": true, + "paramType": true, + "paramName": "All" + } +} diff --git a/.stylua.toml b/.stylua.toml new file mode 100644 index 0000000..a69d6bf --- /dev/null +++ b/.stylua.toml @@ -0,0 +1,13 @@ +block_newline_gaps = "Never" +call_parentheses = "Always" +collapse_simple_statement = "Never" +column_width = 120 +indent_type = "Spaces" +indent_width = 4 +line_endings = "Unix" +quote_style = "AutoPreferDouble" +space_after_function_names = "Never" +syntax = "Lua54" # TODO: update to Lua55 once https://github.com/Kampfkarren/full-moon/pull/356 is merged + +[sort_requires] +enabled = true diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..f52cab9 --- /dev/null +++ b/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1779560665, + "narHash": "sha256-tpyBcxPpcQb8ukyNF7DoCwfSY3VPsxHoYwj00Cayv5o=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "64c08a7ca051951c8eae34e3e3cb1e202fe36786", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..81b3010 --- /dev/null +++ b/flake.nix @@ -0,0 +1,36 @@ +{ + description = "raylib-lua"; + + inputs.nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + + outputs = { + self, + nixpkgs, + }: let + system = "x86_64-linux"; + pkgs = nixpkgs.legacyPackages.${system}; + in { + devShells.${system}.default = pkgs.mkShell { + buildInputs = [ + pkgs.lua5_5 + # opengl + pkgs.libGL + # x11 + pkgs.libX11 + pkgs.libXcursor + pkgs.libXi + pkgs.libXinerama + pkgs.libXrandr + # wayland + pkgs.wayland + pkgs.wayland-scanner + pkgs.libxkbcommon + ## web support + # pkgs.emscripten + ]; + + ## audio + # LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [pkgs.alsa-lib]; + }; + }; +} From 20c03f1adb41a49c2805c878510829793e21e17e Mon Sep 17 00:00:00 2001 From: yilisharcs Date: Sun, 31 May 2026 03:40:26 -0300 Subject: [PATCH 2/3] feat: new lua parser for raylib 6.0 no examples included as of yet. the bindings may need some tweaking. generates src/raylib-lua.h and src/_meta.lua for type annotations. i'm thinking of pulling raylib.h into the tools directory... feat: update the launcher to work with the new api this one lost the drag-and-drop capabilities of the previous. TBD later. chore: update README chore: update LICENSE with new contributor me! test: update core_basic_window example the rest will be ported one by one at a later date. --- LICENSE | 1 + README.md | 8 +- examples/core/core_basic_window.lua | 31 +- src/_meta.lua | 5032 +++++++++++ src/raylib-lua.h | 11442 +++++++++++++++++--------- tools/rLuaLauncher/rlualauncher.c | 131 +- tools/rLuaParser/rluaparser.c | 287 - tools/rLuaParser/rluaparser.lua | 1812 ++++ 8 files changed, 14282 insertions(+), 4462 deletions(-) create mode 100644 src/_meta.lua create mode 100755 tools/rLuaParser/rluaparser.lua diff --git a/LICENSE b/LICENSE index 5aab379..91ed83f 100644 --- a/LICENSE +++ b/LICENSE @@ -2,6 +2,7 @@ raylib-lua is licensed under an unmodified zlib/libpng license, which is an OSI- BSD-like license that allows static linking with closed source software: Copyright (c) 2016-2017 Ghassan Al-Mashareqa and Ramon Santamaria (@raysan5) +Copyright (c) 2026 yilisharcs This software is provided "as-is", without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. diff --git a/README.md b/README.md index 3d85649..a1ad0dc 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ -Lua bindings for raylib, a simple and easy-to-use library to enjoy videogames programming (www.raylib.com) +Lua 5.5 bindings for raylib v6.0, a simple and easy-to-use library to enjoy videogames programming (www.raylib.com) raylib-lua binding is self-contained in a header-only file: [raylib-lua.h](src/raylib-lua.h). Just include that file in your project to allow loading and execution of raylib code written in Lua. Check [code examples](examples) for reference. +As a bonus, include [\_meta.lua](src/_meta.lua) to have LSP support. raylib-lua could be useful for prototyping, tools development, graphic applications, embedded systems and education. @@ -22,7 +23,9 @@ For more details, just check comments on sources. ### rLuaParser -In an effort to automatize raylib-lua binding generation I created [rLuaParser](https://github.com/raysan5/raylib-lua/tree/master/tools/rLuaParser), unfortunately there are several side cases that are not solved yet on the parsing, specially when dealing with opaque data types. Any help or contribution is welcome! +The bindings are automatically generated using [rLuaParser](tools/rLuaParser/rluaparser.lua), which replaces the old C parser. It +parses `raylib.h` to generate the C header-only binding and Lua metadata. The current implementation +may be incomplete; any help or contribution is welcome! # License @@ -30,3 +33,4 @@ raylib-lua is licensed under an unmodified zlib/libpng license, which is an OSI- BSD-like license that allows static linking with closed source software. Check [LICENSE](LICENSE) for further details. *Copyright (c) 2016-2019 Ghassan Al-Mashareqa and Ramon Santamaria ([@raysan5](https://twitter.com/raysan5))* +*Copyright (c) 2026 yilisharcs ([@yilisharcs](https://twitter.com/yilisharcs))* diff --git a/examples/core/core_basic_window.lua b/examples/core/core_basic_window.lua index ea3337a..981d37f 100644 --- a/examples/core/core_basic_window.lua +++ b/examples/core/core_basic_window.lua @@ -1,26 +1,27 @@ -------------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------------- -- -- raylib [core] example - Basic window -- --- This example has been created using raylib 1.6 (www.raylib.com) +-- This example has been created using raylib 6.0 (www.raylib.com) -- raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) -- -- Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) +-- Copyright (c) 2026 yilisharcs -- -------------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------------- -- Initialization -------------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------------- local screenWidth = 800 local screenHeight = 450 -InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window") +rl.InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window") -SetTargetFPS(60) -- Set target frames-per-second -------------------------------------------------------------------------------------------- +rl.SetTargetFPS(60); -- Set our game to run at 60 frames-per-second +-------------------------------------------------------------------------------------- -- Main game loop -while not WindowShouldClose() do -- Detect window close button or ESC key +while not rl.WindowShouldClose() do -- Detect window close button or ESC key -- Update --------------------------------------------------------------------------------------- -- TODO: Update your variables here @@ -28,17 +29,17 @@ while not WindowShouldClose() do -- Detect window close button or ESC -- Draw --------------------------------------------------------------------------------------- - BeginDrawing() + rl.BeginDrawing() - ClearBackground(RAYWHITE) + rl.ClearBackground(rl.RAYWHITE) - DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY) + rl.DrawText("Congrats! You created your first window!", 190, 200, 20, rl.LIGHTGRAY) - EndDrawing() + rl.EndDrawing() --------------------------------------------------------------------------------------- end -- De-Initialization -------------------------------------------------------------------------------------------- -CloseWindow() -- Close window and OpenGL context -------------------------------------------------------------------------------------------- \ No newline at end of file +-------------------------------------------------------------------------------------- +rl.CloseWindow() -- Close window and OpenGL context +-------------------------------------------------------------------------------------- diff --git a/src/_meta.lua b/src/_meta.lua new file mode 100644 index 0000000..29ad42f --- /dev/null +++ b/src/_meta.lua @@ -0,0 +1,5032 @@ +---@meta _ +--[[ ********************************************************************************************** + + raylib-lua v6.0 - raylib Lua type definitions for LuaLS + + AUTO-GENERATED by tools/rLuaParser/rluaparser.lua + + LICENSE: zlib/libpng + + Copyright (c) 2026 yilisharcs + +************************************************************************************************ ]] + +error("Cannot require a meta file") + +--- AudioStream, custom audio stream +---@class rl.AudioStream +--- Pointer to internal data used by the audio system +---@field buffer userdata +--- Pointer to internal data processor, useful for audio effects +---@field processor userdata +--- Frequency (samples per second) +---@field sampleRate integer +--- Bit depth (bits per sample): 8, 16, 32 (24 not supported) +---@field sampleSize integer +--- Number of channels (1-mono, 2-stereo, ...) +---@field channels integer + +--- Automation event +---@class rl.AutomationEvent +--- Event frame +---@field frame integer +--- Event type (AutomationEventType) +---@field type integer +--- Event parameters (if required) +---@field params { [1]: integer, [2]: integer, [3]: integer, [4]: integer } + +--- Automation event list +---@class rl.AutomationEventList +--- Events max entries (MAX_AUTOMATION_EVENTS) +---@field capacity integer +--- Events entries count +---@field count integer +--- Events entries +---@field events userdata + +--- Bone, skeletal animation bone +---@class rl.BoneInfo +--- Bone name +---@field name string +--- Bone parent +---@field parent integer + +--- BoundingBox +---@class rl.BoundingBox +--- Minimum vertex box-corner +---@field min rl.Vector3 +--- Maximum vertex box-corner +---@field max rl.Vector3 + +--- Camera2D, defines position/orientation in 2d space +---@class rl.Camera2D +--- Camera offset (screen space offset from window origin) +---@field offset rl.Vector2 +--- Camera target (world space target point that is mapped to screen space offset) +---@field target rl.Vector2 +--- Camera rotation in degrees (pivots around target) +---@field rotation number +--- Camera zoom (scaling around target), must not be set to 0, set to 1.0f for no scale +---@field zoom number + +--- Camera, defines position/orientation in 3d space +---@class rl.Camera3D +--- Camera position +---@field position rl.Vector3 +--- Camera target it looks-at +---@field target rl.Vector3 +--- Camera up vector (rotation over its axis) +---@field up rl.Vector3 +--- Camera field-of-view aperture in Y (degrees) in perspective, used as near plane height in world units in orthographic +---@field fovy number +--- Camera projection: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC +---@field projection integer + +--- Color, 4 components, R8G8B8A8 (32bit) +---@class rl.Color +--- Color red value +---@field r integer +--- Color green value +---@field g integer +--- Color blue value +---@field b integer +--- Color alpha value +---@field a integer + +--- File path list +---@class rl.FilePathList +--- Filepaths entries count +---@field count integer +--- Filepaths entries +---@field paths userdata + +--- Font, font texture and GlyphInfo array data +---@class rl.Font +--- Base size (default chars height) +---@field baseSize integer +--- Number of glyph characters +---@field glyphCount integer +--- Padding around the glyph characters +---@field glyphPadding integer +--- Texture atlas containing the glyphs +---@field texture rl.Texture +--- Rectangles in texture for the glyphs +---@field recs userdata +--- Glyphs info data +---@field glyphs userdata + +--- GlyphInfo, font characters glyphs info +---@class rl.GlyphInfo +--- Character value (Unicode) +---@field value integer +--- Character offset X when drawing +---@field offsetX integer +--- Character offset Y when drawing +---@field offsetY integer +--- Character advance position X +---@field advanceX integer +--- Character image data +---@field image rl.Image + +--- Image, pixel data stored in CPU memory (RAM) +---@class rl.Image +--- Image raw data +---@field data userdata +--- Image base width +---@field width integer +--- Image base height +---@field height integer +--- Mipmap levels, 1 by default +---@field mipmaps integer +--- Data format (PixelFormat type) +---@field format integer + +--- Material, includes shader and maps +---@class rl.Material +--- Material shader +---@field shader rl.Shader +--- Material maps array (MAX_MATERIAL_MAPS) +---@field maps userdata +--- Material generic parameters (if required) +---@field params { [1]: number, [2]: number, [3]: number, [4]: number } + +--- MaterialMap +---@class rl.MaterialMap +--- Material map texture +---@field texture rl.Texture +--- Material map color +---@field color rl.Color +--- Material map value +---@field value number + +--- Matrix, 4x4 components, column major, OpenGL style, right-handed +---@class rl.Matrix +--- Matrix first row (4 components) +---@field m0 number +--- Matrix second row (4 components) +---@field m1 number +--- Matrix third row (4 components) +---@field m2 number +--- Matrix fourth row (4 components) +---@field m3 number +--- Matrix first row (4 components) +---@field m4 number +--- Matrix second row (4 components) +---@field m5 number +--- Matrix third row (4 components) +---@field m6 number +--- Matrix fourth row (4 components) +---@field m7 number +--- Matrix first row (4 components) +---@field m8 number +--- Matrix second row (4 components) +---@field m9 number +--- Matrix third row (4 components) +---@field m10 number +--- Matrix fourth row (4 components) +---@field m11 number +--- Matrix first row (4 components) +---@field m12 number +--- Matrix second row (4 components) +---@field m13 number +--- Matrix third row (4 components) +---@field m14 number +--- Matrix fourth row (4 components) +---@field m15 number + +--- Mesh, vertex data and vao/vbo +---@class rl.Mesh +--- Number of vertices stored in arrays +---@field vertexCount integer +--- Number of triangles stored (indexed or not) +---@field triangleCount integer +--- Vertex position (XYZ - 3 components per vertex) (shader-location = 0) +---@field vertices userdata +--- Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) +---@field texcoords userdata +--- Vertex texture second coordinates (UV - 2 components per vertex) (shader-location = 5) +---@field texcoords2 userdata +--- Vertex normals (XYZ - 3 components per vertex) (shader-location = 2) +---@field normals userdata +--- Vertex tangents (XYZW - 4 components per vertex) (shader-location = 4) +---@field tangents userdata +--- Vertex colors (RGBA - 4 components per vertex) (shader-location = 3) +---@field colors userdata +--- Vertex indices (in case vertex data comes indexed) +---@field indices userdata +--- Number of bones (MAX: 256 bones) +---@field boneCount integer +--- Vertex bone indices, up to 4 bones influence by vertex (skinning) (shader-location = 6) +---@field boneIndices userdata +--- Vertex bone weight, up to 4 bones influence by vertex (skinning) (shader-location = 7) +---@field boneWeights userdata +--- Animated vertex positions (after bones transformations) +---@field animVertices userdata +--- Animated normals (after bones transformations) +---@field animNormals userdata +--- OpenGL Vertex Array Object id +---@field vaoId integer +--- OpenGL Vertex Buffer Objects id (default vertex data) +---@field vboId userdata + +--- Model, meshes, materials and animation data +---@class rl.Model +--- Local transform matrix +---@field transform rl.Matrix +--- Number of meshes +---@field meshCount integer +--- Number of materials +---@field materialCount integer +--- Meshes array +---@field meshes userdata +--- Materials array +---@field materials userdata +--- Mesh material number +---@field meshMaterial userdata +--- Skeleton for animation +---@field skeleton rl.ModelSkeleton +--- Current animation pose (Transform[]) +---@field currentPose userdata +--- Bones animated transformation matrices +---@field boneMatrices userdata + +--- ModelAnimation, contains a full animation sequence +---@class rl.ModelAnimation +--- Animation name +---@field name string +--- Number of bones (per pose) +---@field boneCount integer +--- Number of animation key frames +---@field keyframeCount integer +--- Animation sequence keyframe poses [keyframe][pose] +---@field keyframePoses userdata + +--- Skeleton, animation bones hierarchy +---@class rl.ModelSkeleton +--- Number of bones +---@field boneCount integer +--- Bones information (skeleton) +---@field bones userdata +--- Bones base transformation (Transform[]) +---@field bindPose userdata + +--- Music, audio stream, anything longer than ~10 seconds should be streamed +---@class rl.Music +--- Audio stream +---@field stream rl.AudioStream +--- Total number of frames (considering channels) +---@field frameCount integer +--- Music looping enable +---@field looping boolean +--- Type of music context (audio filetype) +---@field ctxType integer +--- Audio context data, depends on type +---@field ctxData userdata + +--- NPatchInfo, n-patch layout info +---@class rl.NPatchInfo +--- Texture source rectangle +---@field source rl.Rectangle +--- Left border offset +---@field left integer +--- Top border offset +---@field top integer +--- Right border offset +---@field right integer +--- Bottom border offset +---@field bottom integer +--- Layout of the n-patch: 3x3, 1x3 or 3x1 +---@field layout integer + +--- Ray, ray for raycasting +---@class rl.Ray +--- Ray position (origin) +---@field position rl.Vector3 +--- Ray direction (normalized) +---@field direction rl.Vector3 + +--- RayCollision, ray hit information +---@class rl.RayCollision +--- Did the ray hit something? +---@field hit boolean +--- Distance to the nearest hit +---@field distance number +--- Point of the nearest hit +---@field point rl.Vector3 +--- Surface normal of hit +---@field normal rl.Vector3 + +--- Rectangle, 4 components +---@class rl.Rectangle +--- Rectangle top-left corner position x +---@field x number +--- Rectangle top-left corner position y +---@field y number +--- Rectangle width +---@field width number +--- Rectangle height +---@field height number + +--- RenderTexture, fbo for texture rendering +---@class rl.RenderTexture +--- OpenGL framebuffer object id +---@field id integer +--- Color buffer attachment texture +---@field texture rl.Texture +--- Depth buffer attachment texture +---@field depth rl.Texture + +--- Shader +---@class rl.Shader +--- Shader program id +---@field id integer +--- Shader locations array (RL_MAX_SHADER_LOCATIONS) +---@field locs userdata + +--- Sound +---@class rl.Sound +--- Audio stream +---@field stream rl.AudioStream +--- Total number of frames (considering channels) +---@field frameCount integer + +--- Texture, tex data stored in GPU memory (VRAM) +---@class rl.Texture +--- OpenGL texture id +---@field id integer +--- Texture base width +---@field width integer +--- Texture base height +---@field height integer +--- Mipmap levels, 1 by default +---@field mipmaps integer +--- Data format (PixelFormat type) +---@field format integer + +--- Transform, vertex transformation data +---@class rl.Transform +--- Translation +---@field translation rl.Vector3 +--- Rotation +---@field rotation rl.Vector4 +--- Scale +---@field scale rl.Vector3 + +--- Vector2, 2 components +---@class rl.Vector2 +--- Vector x component +---@field x number +--- Vector y component +---@field y number + +--- Vector3, 3 components +---@class rl.Vector3 +--- Vector x component +---@field x number +--- Vector y component +---@field y number +--- Vector z component +---@field z number + +--- Vector4, 4 components +---@class rl.Vector4 +--- Vector x component +---@field x number +--- Vector y component +---@field y number +--- Vector z component +---@field z number +--- Vector w component +---@field w number + +--- VrDeviceInfo, Head-Mounted-Display device parameters +---@class rl.VrDeviceInfo +--- Horizontal resolution in pixels +---@field hResolution integer +--- Vertical resolution in pixels +---@field vResolution integer +--- Horizontal size in meters +---@field hScreenSize number +--- Vertical size in meters +---@field vScreenSize number +--- Distance between eye and display in meters +---@field eyeToScreenDistance number +--- Lens separation distance in meters +---@field lensSeparationDistance number +--- IPD (distance between pupils) in meters +---@field interpupillaryDistance number +--- Lens distortion constant parameters +---@field lensDistortionValues { [1]: number, [2]: number, [3]: number, [4]: number } +--- Chromatic aberration correction parameters +---@field chromaAbCorrection { [1]: number, [2]: number, [3]: number, [4]: number } + +--- VrStereoConfig, VR stereo rendering configuration for simulator +---@class rl.VrStereoConfig +--- VR projection matrices (per eye) +---@field projection { [1]: rl.Matrix, [2]: rl.Matrix } +--- VR view offset matrices (per eye) +---@field viewOffset { [1]: rl.Matrix, [2]: rl.Matrix } +--- VR left lens center +---@field leftLensCenter { [1]: number, [2]: number } +--- VR right lens center +---@field rightLensCenter { [1]: number, [2]: number } +--- VR left screen center +---@field leftScreenCenter { [1]: number, [2]: number } +--- VR right screen center +---@field rightScreenCenter { [1]: number, [2]: number } +--- VR distortion scale +---@field scale { [1]: number, [2]: number } +--- VR distortion scale in +---@field scaleIn { [1]: number, [2]: number } + +--- Wave, audio wave data +---@class rl.Wave +--- Total number of frames (considering channels) +---@field frameCount integer +--- Frequency (samples per second) +---@field sampleRate integer +--- Bit depth (bits per sample): 8, 16, 32 (24 not supported) +---@field sampleSize integer +--- Number of channels (1-mono, 2-stereo, ...) +---@field channels integer +--- Buffer data pointer +---@field data userdata + +---@class (partial) rl +rl = {} + +---@alias rl.ConfigFlags integer +---@alias rl.TraceLogLevel integer +---@alias rl.KeyboardKey integer +---@alias rl.MouseButton integer +---@alias rl.MouseCursor integer +---@alias rl.GamepadButton integer +---@alias rl.GamepadAxis integer +---@alias rl.MaterialMapIndex integer +---@alias rl.ShaderLocationIndex integer +---@alias rl.ShaderUniformDataType integer +---@alias rl.ShaderAttributeDataType integer +---@alias rl.PixelFormat integer +---@alias rl.TextureFilter integer +---@alias rl.TextureWrap integer +---@alias rl.CubemapLayout integer +---@alias rl.FontType integer +---@alias rl.BlendMode integer +---@alias rl.Gesture integer +---@alias rl.CameraMode integer +---@alias rl.CameraProjection integer +---@alias rl.NPatchLayout integer + +--- Set to try enabling V-Sync on GPU +---@type rl.ConfigFlags +rl.FLAG_VSYNC_HINT = 0x00000040 +--- Set to run program in fullscreen +---@type rl.ConfigFlags +rl.FLAG_FULLSCREEN_MODE = 0x00000002 +--- Set to allow resizable window +---@type rl.ConfigFlags +rl.FLAG_WINDOW_RESIZABLE = 0x00000004 +--- Set to disable window decoration (frame and buttons) +---@type rl.ConfigFlags +rl.FLAG_WINDOW_UNDECORATED = 0x00000008 +--- Set to hide window +---@type rl.ConfigFlags +rl.FLAG_WINDOW_HIDDEN = 0x00000080 +--- Set to minimize window (iconify) +---@type rl.ConfigFlags +rl.FLAG_WINDOW_MINIMIZED = 0x00000200 +--- Set to maximize window (expanded to monitor) +---@type rl.ConfigFlags +rl.FLAG_WINDOW_MAXIMIZED = 0x00000400 +--- Set to window non focused +---@type rl.ConfigFlags +rl.FLAG_WINDOW_UNFOCUSED = 0x00000800 +--- Set to window always on top +---@type rl.ConfigFlags +rl.FLAG_WINDOW_TOPMOST = 0x00001000 +--- Set to allow windows running while minimized +---@type rl.ConfigFlags +rl.FLAG_WINDOW_ALWAYS_RUN = 0x00000100 +--- Set to allow transparent framebuffer +---@type rl.ConfigFlags +rl.FLAG_WINDOW_TRANSPARENT = 0x00000010 +--- Set to support HighDPI +---@type rl.ConfigFlags +rl.FLAG_WINDOW_HIGHDPI = 0x00002000 +--- Set to support mouse passthrough, only supported when FLAG_WINDOW_UNDECORATED +---@type rl.ConfigFlags +rl.FLAG_WINDOW_MOUSE_PASSTHROUGH = 0x00004000 +--- Set to run program in borderless windowed mode +---@type rl.ConfigFlags +rl.FLAG_BORDERLESS_WINDOWED_MODE = 0x00008000 +--- Set to try enabling MSAA 4X +---@type rl.ConfigFlags +rl.FLAG_MSAA_4X_HINT = 0x00000020 +--- Set to try enabling interlaced video format (for V3D) +---@type rl.ConfigFlags +rl.FLAG_INTERLACED_HINT = 0x00010000 +--- Display all logs +---@type rl.TraceLogLevel +rl.LOG_ALL = 0 +--- Trace logging, intended for internal use only +---@type rl.TraceLogLevel +rl.LOG_TRACE = 1 +--- Debug logging, used for internal debugging, it should be disabled on release builds +---@type rl.TraceLogLevel +rl.LOG_DEBUG = 2 +--- Info logging, used for program execution info +---@type rl.TraceLogLevel +rl.LOG_INFO = 3 +--- Warning logging, used on recoverable failures +---@type rl.TraceLogLevel +rl.LOG_WARNING = 4 +--- Error logging, used on unrecoverable failures +---@type rl.TraceLogLevel +rl.LOG_ERROR = 5 +--- Fatal logging, used to abort program: exit(EXIT_FAILURE) +---@type rl.TraceLogLevel +rl.LOG_FATAL = 6 +--- Disable logging +---@type rl.TraceLogLevel +rl.LOG_NONE = 7 +--- Key: NULL, used for no key pressed +---@type rl.KeyboardKey +rl.KEY_NULL = 0 +--- Key: ' +---@type rl.KeyboardKey +rl.KEY_APOSTROPHE = 39 +--- Key: , +---@type rl.KeyboardKey +rl.KEY_COMMA = 44 +--- Key: - +---@type rl.KeyboardKey +rl.KEY_MINUS = 45 +--- Key: . +---@type rl.KeyboardKey +rl.KEY_PERIOD = 46 +--- Key: / +---@type rl.KeyboardKey +rl.KEY_SLASH = 47 +--- Key: 0 +---@type rl.KeyboardKey +rl.KEY_ZERO = 48 +--- Key: 1 +---@type rl.KeyboardKey +rl.KEY_ONE = 49 +--- Key: 2 +---@type rl.KeyboardKey +rl.KEY_TWO = 50 +--- Key: 3 +---@type rl.KeyboardKey +rl.KEY_THREE = 51 +--- Key: 4 +---@type rl.KeyboardKey +rl.KEY_FOUR = 52 +--- Key: 5 +---@type rl.KeyboardKey +rl.KEY_FIVE = 53 +--- Key: 6 +---@type rl.KeyboardKey +rl.KEY_SIX = 54 +--- Key: 7 +---@type rl.KeyboardKey +rl.KEY_SEVEN = 55 +--- Key: 8 +---@type rl.KeyboardKey +rl.KEY_EIGHT = 56 +--- Key: 9 +---@type rl.KeyboardKey +rl.KEY_NINE = 57 +--- Key: ; +---@type rl.KeyboardKey +rl.KEY_SEMICOLON = 59 +--- Key: = +---@type rl.KeyboardKey +rl.KEY_EQUAL = 61 +--- Key: A | a +---@type rl.KeyboardKey +rl.KEY_A = 65 +--- Key: B | b +---@type rl.KeyboardKey +rl.KEY_B = 66 +--- Key: C | c +---@type rl.KeyboardKey +rl.KEY_C = 67 +--- Key: D | d +---@type rl.KeyboardKey +rl.KEY_D = 68 +--- Key: E | e +---@type rl.KeyboardKey +rl.KEY_E = 69 +--- Key: F | f +---@type rl.KeyboardKey +rl.KEY_F = 70 +--- Key: G | g +---@type rl.KeyboardKey +rl.KEY_G = 71 +--- Key: H | h +---@type rl.KeyboardKey +rl.KEY_H = 72 +--- Key: I | i +---@type rl.KeyboardKey +rl.KEY_I = 73 +--- Key: J | j +---@type rl.KeyboardKey +rl.KEY_J = 74 +--- Key: K | k +---@type rl.KeyboardKey +rl.KEY_K = 75 +--- Key: L | l +---@type rl.KeyboardKey +rl.KEY_L = 76 +--- Key: M | m +---@type rl.KeyboardKey +rl.KEY_M = 77 +--- Key: N | n +---@type rl.KeyboardKey +rl.KEY_N = 78 +--- Key: O | o +---@type rl.KeyboardKey +rl.KEY_O = 79 +--- Key: P | p +---@type rl.KeyboardKey +rl.KEY_P = 80 +--- Key: Q | q +---@type rl.KeyboardKey +rl.KEY_Q = 81 +--- Key: R | r +---@type rl.KeyboardKey +rl.KEY_R = 82 +--- Key: S | s +---@type rl.KeyboardKey +rl.KEY_S = 83 +--- Key: T | t +---@type rl.KeyboardKey +rl.KEY_T = 84 +--- Key: U | u +---@type rl.KeyboardKey +rl.KEY_U = 85 +--- Key: V | v +---@type rl.KeyboardKey +rl.KEY_V = 86 +--- Key: W | w +---@type rl.KeyboardKey +rl.KEY_W = 87 +--- Key: X | x +---@type rl.KeyboardKey +rl.KEY_X = 88 +--- Key: Y | y +---@type rl.KeyboardKey +rl.KEY_Y = 89 +--- Key: Z | z +---@type rl.KeyboardKey +rl.KEY_Z = 90 +--- Key: [ +---@type rl.KeyboardKey +rl.KEY_LEFT_BRACKET = 91 +--- Key: '\' +---@type rl.KeyboardKey +rl.KEY_BACKSLASH = 92 +--- Key: ] +---@type rl.KeyboardKey +rl.KEY_RIGHT_BRACKET = 93 +--- Key: ` +---@type rl.KeyboardKey +rl.KEY_GRAVE = 96 +--- Key: Space +---@type rl.KeyboardKey +rl.KEY_SPACE = 32 +--- Key: Esc +---@type rl.KeyboardKey +rl.KEY_ESCAPE = 256 +--- Key: Enter +---@type rl.KeyboardKey +rl.KEY_ENTER = 257 +--- Key: Tab +---@type rl.KeyboardKey +rl.KEY_TAB = 258 +--- Key: Backspace +---@type rl.KeyboardKey +rl.KEY_BACKSPACE = 259 +--- Key: Ins +---@type rl.KeyboardKey +rl.KEY_INSERT = 260 +--- Key: Del +---@type rl.KeyboardKey +rl.KEY_DELETE = 261 +--- Key: Cursor right +---@type rl.KeyboardKey +rl.KEY_RIGHT = 262 +--- Key: Cursor left +---@type rl.KeyboardKey +rl.KEY_LEFT = 263 +--- Key: Cursor down +---@type rl.KeyboardKey +rl.KEY_DOWN = 264 +--- Key: Cursor up +---@type rl.KeyboardKey +rl.KEY_UP = 265 +--- Key: Page up +---@type rl.KeyboardKey +rl.KEY_PAGE_UP = 266 +--- Key: Page down +---@type rl.KeyboardKey +rl.KEY_PAGE_DOWN = 267 +--- Key: Home +---@type rl.KeyboardKey +rl.KEY_HOME = 268 +--- Key: End +---@type rl.KeyboardKey +rl.KEY_END = 269 +--- Key: Caps lock +---@type rl.KeyboardKey +rl.KEY_CAPS_LOCK = 280 +--- Key: Scroll down +---@type rl.KeyboardKey +rl.KEY_SCROLL_LOCK = 281 +--- Key: Num lock +---@type rl.KeyboardKey +rl.KEY_NUM_LOCK = 282 +--- Key: Print screen +---@type rl.KeyboardKey +rl.KEY_PRINT_SCREEN = 283 +--- Key: Pause +---@type rl.KeyboardKey +rl.KEY_PAUSE = 284 +--- Key: F1 +---@type rl.KeyboardKey +rl.KEY_F1 = 290 +--- Key: F2 +---@type rl.KeyboardKey +rl.KEY_F2 = 291 +--- Key: F3 +---@type rl.KeyboardKey +rl.KEY_F3 = 292 +--- Key: F4 +---@type rl.KeyboardKey +rl.KEY_F4 = 293 +--- Key: F5 +---@type rl.KeyboardKey +rl.KEY_F5 = 294 +--- Key: F6 +---@type rl.KeyboardKey +rl.KEY_F6 = 295 +--- Key: F7 +---@type rl.KeyboardKey +rl.KEY_F7 = 296 +--- Key: F8 +---@type rl.KeyboardKey +rl.KEY_F8 = 297 +--- Key: F9 +---@type rl.KeyboardKey +rl.KEY_F9 = 298 +--- Key: F10 +---@type rl.KeyboardKey +rl.KEY_F10 = 299 +--- Key: F11 +---@type rl.KeyboardKey +rl.KEY_F11 = 300 +--- Key: F12 +---@type rl.KeyboardKey +rl.KEY_F12 = 301 +--- Key: Shift left +---@type rl.KeyboardKey +rl.KEY_LEFT_SHIFT = 340 +--- Key: Control left +---@type rl.KeyboardKey +rl.KEY_LEFT_CONTROL = 341 +--- Key: Alt left +---@type rl.KeyboardKey +rl.KEY_LEFT_ALT = 342 +--- Key: Super left +---@type rl.KeyboardKey +rl.KEY_LEFT_SUPER = 343 +--- Key: Shift right +---@type rl.KeyboardKey +rl.KEY_RIGHT_SHIFT = 344 +--- Key: Control right +---@type rl.KeyboardKey +rl.KEY_RIGHT_CONTROL = 345 +--- Key: Alt right +---@type rl.KeyboardKey +rl.KEY_RIGHT_ALT = 346 +--- Key: Super right +---@type rl.KeyboardKey +rl.KEY_RIGHT_SUPER = 347 +--- Key: KB menu +---@type rl.KeyboardKey +rl.KEY_KB_MENU = 348 +--- Key: Keypad 0 +---@type rl.KeyboardKey +rl.KEY_KP_0 = 320 +--- Key: Keypad 1 +---@type rl.KeyboardKey +rl.KEY_KP_1 = 321 +--- Key: Keypad 2 +---@type rl.KeyboardKey +rl.KEY_KP_2 = 322 +--- Key: Keypad 3 +---@type rl.KeyboardKey +rl.KEY_KP_3 = 323 +--- Key: Keypad 4 +---@type rl.KeyboardKey +rl.KEY_KP_4 = 324 +--- Key: Keypad 5 +---@type rl.KeyboardKey +rl.KEY_KP_5 = 325 +--- Key: Keypad 6 +---@type rl.KeyboardKey +rl.KEY_KP_6 = 326 +--- Key: Keypad 7 +---@type rl.KeyboardKey +rl.KEY_KP_7 = 327 +--- Key: Keypad 8 +---@type rl.KeyboardKey +rl.KEY_KP_8 = 328 +--- Key: Keypad 9 +---@type rl.KeyboardKey +rl.KEY_KP_9 = 329 +--- Key: Keypad . +---@type rl.KeyboardKey +rl.KEY_KP_DECIMAL = 330 +--- Key: Keypad / +---@type rl.KeyboardKey +rl.KEY_KP_DIVIDE = 331 +--- Key: Keypad * +---@type rl.KeyboardKey +rl.KEY_KP_MULTIPLY = 332 +--- Key: Keypad - +---@type rl.KeyboardKey +rl.KEY_KP_SUBTRACT = 333 +--- Key: Keypad + +---@type rl.KeyboardKey +rl.KEY_KP_ADD = 334 +--- Key: Keypad Enter +---@type rl.KeyboardKey +rl.KEY_KP_ENTER = 335 +--- Key: Keypad = +---@type rl.KeyboardKey +rl.KEY_KP_EQUAL = 336 +--- Key: Android back button +---@type rl.KeyboardKey +rl.KEY_BACK = 4 +--- Key: Android menu button +---@type rl.KeyboardKey +rl.KEY_MENU = 5 +--- Key: Android volume up button +---@type rl.KeyboardKey +rl.KEY_VOLUME_UP = 24 +--- Key: Android volume down button +---@type rl.KeyboardKey +rl.KEY_VOLUME_DOWN = 25 +--- Mouse button left +---@type rl.MouseButton +rl.MOUSE_BUTTON_LEFT = 0 +--- Mouse button right +---@type rl.MouseButton +rl.MOUSE_BUTTON_RIGHT = 1 +--- Mouse button middle (pressed wheel) +---@type rl.MouseButton +rl.MOUSE_BUTTON_MIDDLE = 2 +--- Mouse button side (advanced mouse device) +---@type rl.MouseButton +rl.MOUSE_BUTTON_SIDE = 3 +--- Mouse button extra (advanced mouse device) +---@type rl.MouseButton +rl.MOUSE_BUTTON_EXTRA = 4 +--- Mouse button forward (advanced mouse device) +---@type rl.MouseButton +rl.MOUSE_BUTTON_FORWARD = 5 +--- Mouse button back (advanced mouse device) +---@type rl.MouseButton +rl.MOUSE_BUTTON_BACK = 6 +--- Default pointer shape +---@type rl.MouseCursor +rl.MOUSE_CURSOR_DEFAULT = 0 +--- Arrow shape +---@type rl.MouseCursor +rl.MOUSE_CURSOR_ARROW = 1 +--- Text writing cursor shape +---@type rl.MouseCursor +rl.MOUSE_CURSOR_IBEAM = 2 +--- Cross shape +---@type rl.MouseCursor +rl.MOUSE_CURSOR_CROSSHAIR = 3 +--- Pointing hand cursor +---@type rl.MouseCursor +rl.MOUSE_CURSOR_POINTING_HAND = 4 +--- Horizontal resize/move arrow shape +---@type rl.MouseCursor +rl.MOUSE_CURSOR_RESIZE_EW = 5 +--- Vertical resize/move arrow shape +---@type rl.MouseCursor +rl.MOUSE_CURSOR_RESIZE_NS = 6 +--- Top-left to bottom-right diagonal resize/move arrow shape +---@type rl.MouseCursor +rl.MOUSE_CURSOR_RESIZE_NWSE = 7 +--- The top-right to bottom-left diagonal resize/move arrow shape +---@type rl.MouseCursor +rl.MOUSE_CURSOR_RESIZE_NESW = 8 +--- The omnidirectional resize/move cursor shape +---@type rl.MouseCursor +rl.MOUSE_CURSOR_RESIZE_ALL = 9 +--- The operation-not-allowed shape +---@type rl.MouseCursor +rl.MOUSE_CURSOR_NOT_ALLOWED = 10 +--- Unknown button, for error checking +---@type rl.GamepadButton +rl.GAMEPAD_BUTTON_UNKNOWN = 0 +--- Gamepad left DPAD up button +---@type rl.GamepadButton +rl.GAMEPAD_BUTTON_LEFT_FACE_UP = 1 +--- Gamepad left DPAD right button +---@type rl.GamepadButton +rl.GAMEPAD_BUTTON_LEFT_FACE_RIGHT = 2 +--- Gamepad left DPAD down button +---@type rl.GamepadButton +rl.GAMEPAD_BUTTON_LEFT_FACE_DOWN = 3 +--- Gamepad left DPAD left button +---@type rl.GamepadButton +rl.GAMEPAD_BUTTON_LEFT_FACE_LEFT = 4 +--- Gamepad right button up (i.e. PS3: Triangle, Xbox: Y) +---@type rl.GamepadButton +rl.GAMEPAD_BUTTON_RIGHT_FACE_UP = 5 +--- Gamepad right button right (i.e. PS3: Circle, Xbox: B) +---@type rl.GamepadButton +rl.GAMEPAD_BUTTON_RIGHT_FACE_RIGHT = 6 +--- Gamepad right button down (i.e. PS3: Cross, Xbox: A) +---@type rl.GamepadButton +rl.GAMEPAD_BUTTON_RIGHT_FACE_DOWN = 7 +--- Gamepad right button left (i.e. PS3: Square, Xbox: X) +---@type rl.GamepadButton +rl.GAMEPAD_BUTTON_RIGHT_FACE_LEFT = 8 +--- Gamepad top/back trigger left (first), it could be a trailing button +---@type rl.GamepadButton +rl.GAMEPAD_BUTTON_LEFT_TRIGGER_1 = 9 +--- Gamepad top/back trigger left (second), it could be a trailing button +---@type rl.GamepadButton +rl.GAMEPAD_BUTTON_LEFT_TRIGGER_2 = 10 +--- Gamepad top/back trigger right (first), it could be a trailing button +---@type rl.GamepadButton +rl.GAMEPAD_BUTTON_RIGHT_TRIGGER_1 = 11 +--- Gamepad top/back trigger right (second), it could be a trailing button +---@type rl.GamepadButton +rl.GAMEPAD_BUTTON_RIGHT_TRIGGER_2 = 12 +--- Gamepad center buttons, left one (i.e. PS3: Select) +---@type rl.GamepadButton +rl.GAMEPAD_BUTTON_MIDDLE_LEFT = 13 +--- Gamepad center buttons, middle one (i.e. PS3: PS, Xbox: XBOX) +---@type rl.GamepadButton +rl.GAMEPAD_BUTTON_MIDDLE = 14 +--- Gamepad center buttons, right one (i.e. PS3: Start) +---@type rl.GamepadButton +rl.GAMEPAD_BUTTON_MIDDLE_RIGHT = 15 +--- Gamepad joystick pressed button left +---@type rl.GamepadButton +rl.GAMEPAD_BUTTON_LEFT_THUMB = 16 +--- Gamepad joystick pressed button right +---@type rl.GamepadButton +rl.GAMEPAD_BUTTON_RIGHT_THUMB = 17 +--- Gamepad left stick X axis +---@type rl.GamepadAxis +rl.GAMEPAD_AXIS_LEFT_X = 0 +--- Gamepad left stick Y axis +---@type rl.GamepadAxis +rl.GAMEPAD_AXIS_LEFT_Y = 1 +--- Gamepad right stick X axis +---@type rl.GamepadAxis +rl.GAMEPAD_AXIS_RIGHT_X = 2 +--- Gamepad right stick Y axis +---@type rl.GamepadAxis +rl.GAMEPAD_AXIS_RIGHT_Y = 3 +--- Gamepad back trigger left, pressure level: [1..-1] +---@type rl.GamepadAxis +rl.GAMEPAD_AXIS_LEFT_TRIGGER = 4 +--- Gamepad back trigger right, pressure level: [1..-1] +---@type rl.GamepadAxis +rl.GAMEPAD_AXIS_RIGHT_TRIGGER = 5 +--- Albedo material (same as: MATERIAL_MAP_DIFFUSE) +---@type rl.MaterialMapIndex +rl.MATERIAL_MAP_ALBEDO = 0 +--- Metalness material (same as: MATERIAL_MAP_SPECULAR) +---@type rl.MaterialMapIndex +rl.MATERIAL_MAP_METALNESS = 1 +--- Normal material +---@type rl.MaterialMapIndex +rl.MATERIAL_MAP_NORMAL = 2 +--- Roughness material +---@type rl.MaterialMapIndex +rl.MATERIAL_MAP_ROUGHNESS = 3 +--- Ambient occlusion material +---@type rl.MaterialMapIndex +rl.MATERIAL_MAP_OCCLUSION = 4 +--- Emission material +---@type rl.MaterialMapIndex +rl.MATERIAL_MAP_EMISSION = 5 +--- Heightmap material +---@type rl.MaterialMapIndex +rl.MATERIAL_MAP_HEIGHT = 6 +--- Cubemap material (NOTE: Uses GL_TEXTURE_CUBE_MAP) +---@type rl.MaterialMapIndex +rl.MATERIAL_MAP_CUBEMAP = 7 +--- Irradiance material (NOTE: Uses GL_TEXTURE_CUBE_MAP) +---@type rl.MaterialMapIndex +rl.MATERIAL_MAP_IRRADIANCE = 8 +--- Prefilter material (NOTE: Uses GL_TEXTURE_CUBE_MAP) +---@type rl.MaterialMapIndex +rl.MATERIAL_MAP_PREFILTER = 9 +--- Brdf material +---@type rl.MaterialMapIndex +rl.MATERIAL_MAP_BRDF = 10 +--- Shader location: vertex attribute: position +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_VERTEX_POSITION = 0 +--- Shader location: vertex attribute: texcoord01 +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_VERTEX_TEXCOORD01 = 1 +--- Shader location: vertex attribute: texcoord02 +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_VERTEX_TEXCOORD02 = 2 +--- Shader location: vertex attribute: normal +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_VERTEX_NORMAL = 3 +--- Shader location: vertex attribute: tangent +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_VERTEX_TANGENT = 4 +--- Shader location: vertex attribute: color +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_VERTEX_COLOR = 5 +--- Shader location: matrix uniform: model-view-projection +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_MATRIX_MVP = 6 +--- Shader location: matrix uniform: view (camera transform) +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_MATRIX_VIEW = 7 +--- Shader location: matrix uniform: projection +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_MATRIX_PROJECTION = 8 +--- Shader location: matrix uniform: model (transform) +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_MATRIX_MODEL = 9 +--- Shader location: matrix uniform: normal +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_MATRIX_NORMAL = 10 +--- Shader location: vector uniform: view +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_VECTOR_VIEW = 11 +--- Shader location: vector uniform: diffuse color +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_COLOR_DIFFUSE = 12 +--- Shader location: vector uniform: specular color +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_COLOR_SPECULAR = 13 +--- Shader location: vector uniform: ambient color +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_COLOR_AMBIENT = 14 +--- Shader location: sampler2d texture: albedo (same as: SHADER_LOC_MAP_DIFFUSE) +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_MAP_ALBEDO = 15 +--- Shader location: sampler2d texture: metalness (same as: SHADER_LOC_MAP_SPECULAR) +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_MAP_METALNESS = 16 +--- Shader location: sampler2d texture: normal +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_MAP_NORMAL = 17 +--- Shader location: sampler2d texture: roughness +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_MAP_ROUGHNESS = 18 +--- Shader location: sampler2d texture: occlusion +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_MAP_OCCLUSION = 19 +--- Shader location: sampler2d texture: emission +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_MAP_EMISSION = 20 +--- Shader location: sampler2d texture: heightmap +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_MAP_HEIGHT = 21 +--- Shader location: samplerCube texture: cubemap +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_MAP_CUBEMAP = 22 +--- Shader location: samplerCube texture: irradiance +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_MAP_IRRADIANCE = 23 +--- Shader location: samplerCube texture: prefilter +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_MAP_PREFILTER = 24 +--- Shader location: sampler2d texture: brdf +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_MAP_BRDF = 25 +--- Shader location: vertex attribute: bone indices +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_VERTEX_BONEIDS = 26 +--- Shader location: vertex attribute: bone weights +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_VERTEX_BONEWEIGHTS = 27 +--- Shader location: matrix attribute: bone transforms (animation) +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_MATRIX_BONETRANSFORMS = 28 +--- Shader location: vertex attribute: instance transforms +---@type rl.ShaderLocationIndex +rl.SHADER_LOC_VERTEX_INSTANCETRANSFORM = 29 +--- Shader uniform type: float +---@type rl.ShaderUniformDataType +rl.SHADER_UNIFORM_FLOAT = 0 +--- Shader uniform type: vec2 (2 float) +---@type rl.ShaderUniformDataType +rl.SHADER_UNIFORM_VEC2 = 1 +--- Shader uniform type: vec3 (3 float) +---@type rl.ShaderUniformDataType +rl.SHADER_UNIFORM_VEC3 = 2 +--- Shader uniform type: vec4 (4 float) +---@type rl.ShaderUniformDataType +rl.SHADER_UNIFORM_VEC4 = 3 +--- Shader uniform type: int +---@type rl.ShaderUniformDataType +rl.SHADER_UNIFORM_INT = 4 +--- Shader uniform type: ivec2 (2 int) +---@type rl.ShaderUniformDataType +rl.SHADER_UNIFORM_IVEC2 = 5 +--- Shader uniform type: ivec3 (3 int) +---@type rl.ShaderUniformDataType +rl.SHADER_UNIFORM_IVEC3 = 6 +--- Shader uniform type: ivec4 (4 int) +---@type rl.ShaderUniformDataType +rl.SHADER_UNIFORM_IVEC4 = 7 +--- Shader uniform type: unsigned int +---@type rl.ShaderUniformDataType +rl.SHADER_UNIFORM_UINT = 8 +--- Shader uniform type: uivec2 (2 unsigned int) +---@type rl.ShaderUniformDataType +rl.SHADER_UNIFORM_UIVEC2 = 9 +--- Shader uniform type: uivec3 (3 unsigned int) +---@type rl.ShaderUniformDataType +rl.SHADER_UNIFORM_UIVEC3 = 10 +--- Shader uniform type: uivec4 (4 unsigned int) +---@type rl.ShaderUniformDataType +rl.SHADER_UNIFORM_UIVEC4 = 11 +--- Shader uniform type: sampler2d +---@type rl.ShaderUniformDataType +rl.SHADER_UNIFORM_SAMPLER2D = 12 +--- Shader attribute type: float +---@type rl.ShaderAttributeDataType +rl.SHADER_ATTRIB_FLOAT = 0 +--- Shader attribute type: vec2 (2 float) +---@type rl.ShaderAttributeDataType +rl.SHADER_ATTRIB_VEC2 = 1 +--- Shader attribute type: vec3 (3 float) +---@type rl.ShaderAttributeDataType +rl.SHADER_ATTRIB_VEC3 = 2 +--- Shader attribute type: vec4 (4 float) +---@type rl.ShaderAttributeDataType +rl.SHADER_ATTRIB_VEC4 = 3 +--- 8 bit per pixel (no alpha) +---@type rl.PixelFormat +rl.PIXELFORMAT_UNCOMPRESSED_GRAYSCALE = 1 +--- 8*2 bpp (2 channels) +---@type rl.PixelFormat +rl.PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA = 2 +--- 16 bpp +---@type rl.PixelFormat +rl.PIXELFORMAT_UNCOMPRESSED_R5G6B5 = 3 +--- 24 bpp +---@type rl.PixelFormat +rl.PIXELFORMAT_UNCOMPRESSED_R8G8B8 = 4 +--- 16 bpp (1 bit alpha) +---@type rl.PixelFormat +rl.PIXELFORMAT_UNCOMPRESSED_R5G5B5A1 = 5 +--- 16 bpp (4 bit alpha) +---@type rl.PixelFormat +rl.PIXELFORMAT_UNCOMPRESSED_R4G4B4A4 = 6 +--- 32 bpp +---@type rl.PixelFormat +rl.PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 = 7 +--- 32 bpp (1 channel - float) +---@type rl.PixelFormat +rl.PIXELFORMAT_UNCOMPRESSED_R32 = 8 +--- 32*3 bpp (3 channels - float) +---@type rl.PixelFormat +rl.PIXELFORMAT_UNCOMPRESSED_R32G32B32 = 9 +--- 32*4 bpp (4 channels - float) +---@type rl.PixelFormat +rl.PIXELFORMAT_UNCOMPRESSED_R32G32B32A32 = 10 +--- 16 bpp (1 channel - half float) +---@type rl.PixelFormat +rl.PIXELFORMAT_UNCOMPRESSED_R16 = 11 +--- 16*3 bpp (3 channels - half float) +---@type rl.PixelFormat +rl.PIXELFORMAT_UNCOMPRESSED_R16G16B16 = 12 +--- 16*4 bpp (4 channels - half float) +---@type rl.PixelFormat +rl.PIXELFORMAT_UNCOMPRESSED_R16G16B16A16 = 13 +--- 4 bpp (no alpha) +---@type rl.PixelFormat +rl.PIXELFORMAT_COMPRESSED_DXT1_RGB = 14 +--- 4 bpp (1 bit alpha) +---@type rl.PixelFormat +rl.PIXELFORMAT_COMPRESSED_DXT1_RGBA = 15 +--- 8 bpp +---@type rl.PixelFormat +rl.PIXELFORMAT_COMPRESSED_DXT3_RGBA = 16 +--- 8 bpp +---@type rl.PixelFormat +rl.PIXELFORMAT_COMPRESSED_DXT5_RGBA = 17 +--- 4 bpp +---@type rl.PixelFormat +rl.PIXELFORMAT_COMPRESSED_ETC1_RGB = 18 +--- 4 bpp +---@type rl.PixelFormat +rl.PIXELFORMAT_COMPRESSED_ETC2_RGB = 19 +--- 8 bpp +---@type rl.PixelFormat +rl.PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA = 20 +--- 4 bpp +---@type rl.PixelFormat +rl.PIXELFORMAT_COMPRESSED_PVRT_RGB = 21 +--- 4 bpp +---@type rl.PixelFormat +rl.PIXELFORMAT_COMPRESSED_PVRT_RGBA = 22 +--- 8 bpp +---@type rl.PixelFormat +rl.PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA = 23 +--- 2 bpp +---@type rl.PixelFormat +rl.PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA = 24 +--- No filter, pixel approximation +---@type rl.TextureFilter +rl.TEXTURE_FILTER_POINT = 0 +--- Linear filtering +---@type rl.TextureFilter +rl.TEXTURE_FILTER_BILINEAR = 1 +--- Trilinear filtering (linear with mipmaps) +---@type rl.TextureFilter +rl.TEXTURE_FILTER_TRILINEAR = 2 +--- Anisotropic filtering 4x +---@type rl.TextureFilter +rl.TEXTURE_FILTER_ANISOTROPIC_4X = 3 +--- Anisotropic filtering 8x +---@type rl.TextureFilter +rl.TEXTURE_FILTER_ANISOTROPIC_8X = 4 +--- Anisotropic filtering 16x +---@type rl.TextureFilter +rl.TEXTURE_FILTER_ANISOTROPIC_16X = 5 +--- Repeats texture in tiled mode +---@type rl.TextureWrap +rl.TEXTURE_WRAP_REPEAT = 0 +--- Clamps texture to edge pixel in tiled mode +---@type rl.TextureWrap +rl.TEXTURE_WRAP_CLAMP = 1 +--- Mirrors and repeats the texture in tiled mode +---@type rl.TextureWrap +rl.TEXTURE_WRAP_MIRROR_REPEAT = 2 +--- Mirrors and clamps to border the texture in tiled mode +---@type rl.TextureWrap +rl.TEXTURE_WRAP_MIRROR_CLAMP = 3 +--- Automatically detect layout type +---@type rl.CubemapLayout +rl.CUBEMAP_LAYOUT_AUTO_DETECT = 0 +--- Layout is defined by a vertical line with faces +---@type rl.CubemapLayout +rl.CUBEMAP_LAYOUT_LINE_VERTICAL = 1 +--- Layout is defined by a horizontal line with faces +---@type rl.CubemapLayout +rl.CUBEMAP_LAYOUT_LINE_HORIZONTAL = 2 +--- Layout is defined by a 3x4 cross with cubemap faces +---@type rl.CubemapLayout +rl.CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR = 3 +--- Layout is defined by a 4x3 cross with cubemap faces +---@type rl.CubemapLayout +rl.CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE = 4 +--- Default font generation, anti-aliased +---@type rl.FontType +rl.FONT_DEFAULT = 0 +--- Bitmap font generation, no anti-aliasing +---@type rl.FontType +rl.FONT_BITMAP = 1 +--- SDF font generation, requires external shader +---@type rl.FontType +rl.FONT_SDF = 2 +--- Blend textures considering alpha (default) +---@type rl.BlendMode +rl.BLEND_ALPHA = 0 +--- Blend textures adding colors +---@type rl.BlendMode +rl.BLEND_ADDITIVE = 1 +--- Blend textures multiplying colors +---@type rl.BlendMode +rl.BLEND_MULTIPLIED = 2 +--- Blend textures adding colors (alternative) +---@type rl.BlendMode +rl.BLEND_ADD_COLORS = 3 +--- Blend textures subtracting colors (alternative) +---@type rl.BlendMode +rl.BLEND_SUBTRACT_COLORS = 4 +--- Blend premultiplied textures considering alpha +---@type rl.BlendMode +rl.BLEND_ALPHA_PREMULTIPLY = 5 +--- Blend textures using custom src/dst factors (use rlSetBlendFactors()) +---@type rl.BlendMode +rl.BLEND_CUSTOM = 6 +--- Blend textures using custom rgb/alpha separate src/dst factors (use rlSetBlendFactorsSeparate()) +---@type rl.BlendMode +rl.BLEND_CUSTOM_SEPARATE = 7 +--- No gesture +---@type rl.Gesture +rl.GESTURE_NONE = 0 +--- Tap gesture +---@type rl.Gesture +rl.GESTURE_TAP = 1 +--- Double tap gesture +---@type rl.Gesture +rl.GESTURE_DOUBLETAP = 2 +--- Hold gesture +---@type rl.Gesture +rl.GESTURE_HOLD = 4 +--- Drag gesture +---@type rl.Gesture +rl.GESTURE_DRAG = 8 +--- Swipe right gesture +---@type rl.Gesture +rl.GESTURE_SWIPE_RIGHT = 16 +--- Swipe left gesture +---@type rl.Gesture +rl.GESTURE_SWIPE_LEFT = 32 +--- Swipe up gesture +---@type rl.Gesture +rl.GESTURE_SWIPE_UP = 64 +--- Swipe down gesture +---@type rl.Gesture +rl.GESTURE_SWIPE_DOWN = 128 +--- Pinch in gesture +---@type rl.Gesture +rl.GESTURE_PINCH_IN = 256 +--- Pinch out gesture +---@type rl.Gesture +rl.GESTURE_PINCH_OUT = 512 +--- Camera custom, controlled by user (UpdateCamera() does nothing) +---@type rl.CameraMode +rl.CAMERA_CUSTOM = 0 +--- Camera free mode +---@type rl.CameraMode +rl.CAMERA_FREE = 1 +--- Camera orbital, around target, zoom supported +---@type rl.CameraMode +rl.CAMERA_ORBITAL = 2 +--- Camera first person +---@type rl.CameraMode +rl.CAMERA_FIRST_PERSON = 3 +--- Camera third person +---@type rl.CameraMode +rl.CAMERA_THIRD_PERSON = 4 +--- Perspective projection +---@type rl.CameraProjection +rl.CAMERA_PERSPECTIVE = 0 +--- Orthographic projection +---@type rl.CameraProjection +rl.CAMERA_ORTHOGRAPHIC = 1 +--- Npatch layout: 3x3 tiles +---@type rl.NPatchLayout +rl.NPATCH_NINE_PATCH = 0 +--- Npatch layout: 1x3 tiles +---@type rl.NPatchLayout +rl.NPATCH_THREE_PATCH_VERTICAL = 1 +--- Npatch layout: 3x1 tiles +---@type rl.NPatchLayout +rl.NPATCH_THREE_PATCH_HORIZONTAL = 2 +---@type number +rl.PI = 3.14159265358979323846 +---@type number +rl.DEG2RAD = (rl.PI/180.0) +---@type number +rl.RAD2DEG = (180.0/rl.PI) +--- Light Gray +---@type rl.Color +rl.LIGHTGRAY = nil +--- Gray +---@type rl.Color +rl.GRAY = nil +--- Dark Gray +---@type rl.Color +rl.DARKGRAY = nil +--- Yellow +---@type rl.Color +rl.YELLOW = nil +--- Gold +---@type rl.Color +rl.GOLD = nil +--- Orange +---@type rl.Color +rl.ORANGE = nil +--- Pink +---@type rl.Color +rl.PINK = nil +--- Red +---@type rl.Color +rl.RED = nil +--- Maroon +---@type rl.Color +rl.MAROON = nil +--- Green +---@type rl.Color +rl.GREEN = nil +--- Lime +---@type rl.Color +rl.LIME = nil +--- Dark Green +---@type rl.Color +rl.DARKGREEN = nil +--- Sky Blue +---@type rl.Color +rl.SKYBLUE = nil +--- Blue +---@type rl.Color +rl.BLUE = nil +--- Dark Blue +---@type rl.Color +rl.DARKBLUE = nil +--- Purple +---@type rl.Color +rl.PURPLE = nil +--- Violet +---@type rl.Color +rl.VIOLET = nil +--- Dark Purple +---@type rl.Color +rl.DARKPURPLE = nil +--- Beige +---@type rl.Color +rl.BEIGE = nil +--- Brown +---@type rl.Color +rl.BROWN = nil +--- Dark Brown +---@type rl.Color +rl.DARKBROWN = nil +--- White +---@type rl.Color +rl.WHITE = nil +--- Black +---@type rl.Color +rl.BLACK = nil +--- Blank (Transparent) +---@type rl.Color +rl.BLANK = nil +--- Magenta +---@type rl.Color +rl.MAGENTA = nil +--- My own White (raylib logo) +---@type rl.Color +rl.RAYWHITE = nil +---@type integer +rl.MOUSE_LEFT_BUTTON = nil +---@type integer +rl.MOUSE_RIGHT_BUTTON = nil +---@type integer +rl.MOUSE_MIDDLE_BUTTON = nil +---@type integer +rl.MATERIAL_MAP_DIFFUSE = nil +---@type integer +rl.MATERIAL_MAP_SPECULAR = nil +---@type integer +rl.SHADER_LOC_MAP_DIFFUSE = nil +---@type integer +rl.SHADER_LOC_MAP_SPECULAR = nil +--- Get a ray trace from screen position (i.e mouse) +---@param position rl.Vector2 +---@param camera rl.Camera3D +---@return rl.Ray +function rl.GetMouseRay(position, camera) end + + +--- Callbacks to hook some internal functions +--- WARNING: These callbacks are intended for advanced users +--- Logging: Redirect trace log messages +---@param logLevel integer +---@param text string +---@param args rl.va_list +function rl.TraceLogCallback(logLevel, text, args) end + +--- FileIO: Load binary data +---@param fileName string +---@param dataSize userdata +---@return userdata +function rl.LoadFileDataCallback(fileName, dataSize) end + +--- FileIO: Save binary data +---@param fileName string +---@param data userdata +---@param dataSize integer +---@return boolean +function rl.SaveFileDataCallback(fileName, data, dataSize) end + +--- FileIO: Load text data +---@param fileName string +---@return string +function rl.LoadFileTextCallback(fileName) end + +--- FileIO: Save text data +---@param fileName string +---@param text string +---@return boolean +function rl.SaveFileTextCallback(fileName, text) end + +--- Window-related functions +--- Initialize window and OpenGL context +---@param width integer +---@param height integer +---@param title string +function rl.InitWindow(width, height, title) end + +--- Close window and unload OpenGL context +function rl.CloseWindow() end + +--- Check if application should close (KEY_ESCAPE pressed or windows close icon clicked) +---@return boolean +function rl.WindowShouldClose() end + +--- Check if window has been initialized successfully +---@return boolean +function rl.IsWindowReady() end + +--- Check if window is currently fullscreen +---@return boolean +function rl.IsWindowFullscreen() end + +--- Check if window is currently hidden +---@return boolean +function rl.IsWindowHidden() end + +--- Check if window is currently minimized +---@return boolean +function rl.IsWindowMinimized() end + +--- Check if window is currently maximized +---@return boolean +function rl.IsWindowMaximized() end + +--- Check if window is currently focused +---@return boolean +function rl.IsWindowFocused() end + +--- Check if window has been resized last frame +---@return boolean +function rl.IsWindowResized() end + +--- Check if one specific window flag is enabled +---@param flag integer +---@return boolean +function rl.IsWindowState(flag) end + +--- Set window configuration state using flags +---@param flags integer +function rl.SetWindowState(flags) end + +--- Clear window configuration state flags +---@param flags integer +function rl.ClearWindowState(flags) end + +--- Toggle window state: fullscreen/windowed, resizes monitor to match window resolution +function rl.ToggleFullscreen() end + +--- Toggle window state: borderless windowed, resizes window to match monitor resolution +function rl.ToggleBorderlessWindowed() end + +--- Set window state: maximized, if resizable +function rl.MaximizeWindow() end + +--- Set window state: minimized, if resizable +function rl.MinimizeWindow() end + +--- Restore window from being minimized/maximized +function rl.RestoreWindow() end + +--- Set icon for window (single image, RGBA 32bit) +---@param image rl.Image +function rl.SetWindowIcon(image) end + +--- Set icon for window (multiple images, RGBA 32bit) +---@param images userdata +---@param count integer +function rl.SetWindowIcons(images, count) end + +--- Set title for window +---@param title string +function rl.SetWindowTitle(title) end + +--- Set window position on screen +---@param x integer +---@param y integer +function rl.SetWindowPosition(x, y) end + +--- Set monitor for the current window +---@param monitor integer +function rl.SetWindowMonitor(monitor) end + +--- Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE) +---@param width integer +---@param height integer +function rl.SetWindowMinSize(width, height) end + +--- Set window maximum dimensions (for FLAG_WINDOW_RESIZABLE) +---@param width integer +---@param height integer +function rl.SetWindowMaxSize(width, height) end + +--- Set window dimensions +---@param width integer +---@param height integer +function rl.SetWindowSize(width, height) end + +--- Set window opacity [0.0f..1.0f] +---@param opacity number +function rl.SetWindowOpacity(opacity) end + +--- Set window focused +function rl.SetWindowFocused() end + +--- Get native window handle +---@return userdata +function rl.GetWindowHandle() end + +--- Get current screen width +---@return integer +function rl.GetScreenWidth() end + +--- Get current screen height +---@return integer +function rl.GetScreenHeight() end + +--- Get current render width (it considers HiDPI) +---@return integer +function rl.GetRenderWidth() end + +--- Get current render height (it considers HiDPI) +---@return integer +function rl.GetRenderHeight() end + +--- Get number of connected monitors +---@return integer +function rl.GetMonitorCount() end + +--- Get current monitor where window is placed +---@return integer +function rl.GetCurrentMonitor() end + +--- Get specified monitor position +---@param monitor integer +---@return rl.Vector2 +function rl.GetMonitorPosition(monitor) end + +--- Get specified monitor width (current video mode used by monitor) +---@param monitor integer +---@return integer +function rl.GetMonitorWidth(monitor) end + +--- Get specified monitor height (current video mode used by monitor) +---@param monitor integer +---@return integer +function rl.GetMonitorHeight(monitor) end + +--- Get specified monitor physical width in millimetres +---@param monitor integer +---@return integer +function rl.GetMonitorPhysicalWidth(monitor) end + +--- Get specified monitor physical height in millimetres +---@param monitor integer +---@return integer +function rl.GetMonitorPhysicalHeight(monitor) end + +--- Get specified monitor refresh rate +---@param monitor integer +---@return integer +function rl.GetMonitorRefreshRate(monitor) end + +--- Get window position XY on monitor +---@return rl.Vector2 +function rl.GetWindowPosition() end + +--- Get window scale DPI factor +---@return rl.Vector2 +function rl.GetWindowScaleDPI() end + +--- Get the human-readable, UTF-8 encoded name of the specified monitor +---@param monitor integer +---@return string +function rl.GetMonitorName(monitor) end + +--- Set clipboard text content +---@param text string +function rl.SetClipboardText(text) end + +--- Get clipboard text content +---@return string +function rl.GetClipboardText() end + +--- Get clipboard image content +---@return rl.Image +function rl.GetClipboardImage() end + +--- Enable waiting for events on EndDrawing(), no automatic event polling +function rl.EnableEventWaiting() end + +--- Disable waiting for events on EndDrawing(), automatic events polling +function rl.DisableEventWaiting() end + +--- Cursor-related functions +--- Shows cursor +function rl.ShowCursor() end + +--- Hides cursor +function rl.HideCursor() end + +--- Check if cursor is not visible +---@return boolean +function rl.IsCursorHidden() end + +--- Enables cursor (unlock cursor) +function rl.EnableCursor() end + +--- Disables cursor (lock cursor) +function rl.DisableCursor() end + +--- Check if cursor is on the screen +---@return boolean +function rl.IsCursorOnScreen() end + +--- Drawing-related functions +--- Set background color (framebuffer clear color) +---@param color rl.Color +function rl.ClearBackground(color) end + +--- Setup canvas (framebuffer) to start drawing +function rl.BeginDrawing() end + +--- End canvas drawing and swap buffers (double buffering) +function rl.EndDrawing() end + +--- Begin 2D mode with custom camera (2D) +---@param camera rl.Camera2D +function rl.BeginMode2D(camera) end + +--- Ends 2D mode with custom camera +function rl.EndMode2D() end + +--- Begin 3D mode with custom camera (3D) +---@param camera rl.Camera3D +function rl.BeginMode3D(camera) end + +--- Ends 3D mode and returns to default 2D orthographic mode +function rl.EndMode3D() end + +--- Begin drawing to render texture +---@param target rl.RenderTexture +function rl.BeginTextureMode(target) end + +--- Ends drawing to render texture +function rl.EndTextureMode() end + +--- Begin custom shader drawing +---@param shader rl.Shader +function rl.BeginShaderMode(shader) end + +--- End custom shader drawing (use default shader) +function rl.EndShaderMode() end + +--- Begin blending mode (alpha, additive, multiplied, subtract, custom) +---@param mode integer +function rl.BeginBlendMode(mode) end + +--- End blending mode (reset to default: alpha blending) +function rl.EndBlendMode() end + +--- Begin scissor mode (define screen area for following drawing) +---@param x integer +---@param y integer +---@param width integer +---@param height integer +function rl.BeginScissorMode(x, y, width, height) end + +--- End scissor mode +function rl.EndScissorMode() end + +--- Begin stereo rendering (requires VR simulator) +---@param config rl.VrStereoConfig +function rl.BeginVrStereoMode(config) end + +--- End stereo rendering (requires VR simulator) +function rl.EndVrStereoMode() end + +--- VR stereo config functions for VR simulator +--- Load VR stereo config for VR simulator device parameters +---@param device rl.VrDeviceInfo +---@return rl.VrStereoConfig +function rl.LoadVrStereoConfig(device) end + +--- Unload VR stereo config +---@param config rl.VrStereoConfig +function rl.UnloadVrStereoConfig(config) end + +--- Shader management functions +--- NOTE: Shader functionality is not available on OpenGL 1.1 +--- Load shader from files and bind default locations +---@param vsFileName string +---@param fsFileName string +---@return rl.Shader +function rl.LoadShader(vsFileName, fsFileName) end + +--- Load shader from code strings and bind default locations +---@param vsCode string +---@param fsCode string +---@return rl.Shader +function rl.LoadShaderFromMemory(vsCode, fsCode) end + +--- Check if a shader is valid (loaded on GPU) +---@param shader rl.Shader +---@return boolean +function rl.IsShaderValid(shader) end + +--- Get shader uniform location +---@param shader rl.Shader +---@param uniformName string +---@return integer +function rl.GetShaderLocation(shader, uniformName) end + +--- Get shader attribute location +---@param shader rl.Shader +---@param attribName string +---@return integer +function rl.GetShaderLocationAttrib(shader, attribName) end + +--- Set shader uniform value +---@param shader rl.Shader +---@param locIndex integer +---@param value userdata +---@param uniformType integer +function rl.SetShaderValue(shader, locIndex, value, uniformType) end + +--- Set shader uniform value vector +---@param shader rl.Shader +---@param locIndex integer +---@param value userdata +---@param uniformType integer +---@param count integer +function rl.SetShaderValueV(shader, locIndex, value, uniformType, count) end + +--- Set shader uniform value (matrix 4x4) +---@param shader rl.Shader +---@param locIndex integer +---@param mat rl.Matrix +function rl.SetShaderValueMatrix(shader, locIndex, mat) end + +--- Set shader uniform value and bind the texture (sampler2d) +---@param shader rl.Shader +---@param locIndex integer +---@param texture rl.Texture +function rl.SetShaderValueTexture(shader, locIndex, texture) end + +--- Unload shader from GPU memory (VRAM) +---@param shader rl.Shader +function rl.UnloadShader(shader) end + +--- Get a ray trace from screen position (i.e mouse) +---@param position rl.Vector2 +---@param camera rl.Camera3D +---@return rl.Ray +function rl.GetScreenToWorldRay(position, camera) end + +--- Get a ray trace from screen position (i.e mouse) in a viewport +---@param position rl.Vector2 +---@param camera rl.Camera3D +---@param width integer +---@param height integer +---@return rl.Ray +function rl.GetScreenToWorldRayEx(position, camera, width, height) end + +--- Get the screen space position for a 3d world space position +---@param position rl.Vector3 +---@param camera rl.Camera3D +---@return rl.Vector2 +function rl.GetWorldToScreen(position, camera) end + +--- Get size position for a 3d world space position +---@param position rl.Vector3 +---@param camera rl.Camera3D +---@param width integer +---@param height integer +---@return rl.Vector2 +function rl.GetWorldToScreenEx(position, camera, width, height) end + +--- Get the screen space position for a 2d camera world space position +---@param position rl.Vector2 +---@param camera rl.Camera2D +---@return rl.Vector2 +function rl.GetWorldToScreen2D(position, camera) end + +--- Get the world space position for a 2d camera screen space position +---@param position rl.Vector2 +---@param camera rl.Camera2D +---@return rl.Vector2 +function rl.GetScreenToWorld2D(position, camera) end + +--- Get camera transform matrix (view matrix) +---@param camera rl.Camera3D +---@return rl.Matrix +function rl.GetCameraMatrix(camera) end + +--- Get camera 2d transform matrix +---@param camera rl.Camera2D +---@return rl.Matrix +function rl.GetCameraMatrix2D(camera) end + +--- Timing-related functions +--- Set target FPS (maximum) +---@param fps integer +function rl.SetTargetFPS(fps) end + +--- Get time in seconds for last frame drawn (delta time) +---@return number +function rl.GetFrameTime() end + +--- Get elapsed time in seconds since InitWindow() +---@return number +function rl.GetTime() end + +--- Get current FPS +---@return integer +function rl.GetFPS() end + +--- Custom frame control functions +--- NOTE: Those functions are intended for advanced users that want full control over the frame processing +--- By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timing + PollInputEvents() +--- To avoid that behaviour and control frame processes manually, enable in config.h: SUPPORT_CUSTOM_FRAME_CONTROL +--- Swap back buffer with front buffer (screen drawing) +function rl.SwapScreenBuffer() end + +--- Register all input events +function rl.PollInputEvents() end + +--- Wait for some time (halt program execution) +---@param seconds number +function rl.WaitTime(seconds) end + +--- Random values generation functions +--- Set the seed for the random number generator +---@param seed integer +function rl.SetRandomSeed(seed) end + +--- Get a random value between min and max (both included) +---@param min integer +---@param max integer +---@return integer +function rl.GetRandomValue(min, max) end + +--- Load random values sequence, no values repeated +---@param count integer +---@param min integer +---@param max integer +---@return userdata +function rl.LoadRandomSequence(count, min, max) end + +--- Unload random values sequence +---@param sequence userdata +function rl.UnloadRandomSequence(sequence) end + +--- Misc. functions +--- Takes a screenshot of current screen (filename extension defines format) +---@param fileName string +function rl.TakeScreenshot(fileName) end + +--- Setup init configuration flags (view FLAGS) +---@param flags integer +function rl.SetConfigFlags(flags) end + +--- Open URL with default system browser (if available) +---@param url string +function rl.OpenURL(url) end + +--- Logging system +--- Set the current threshold (minimum) log level +---@param logLevel integer +function rl.SetTraceLogLevel(logLevel) end + +--- Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...) +---@param logLevel integer +---@param text string +---@param ... any +function rl.TraceLog(logLevel, text, ...) end + +--- Set custom trace log +---@param callback rl.TraceLogCallback +function rl.SetTraceLogCallback(callback) end + +--- Memory management, using internal allocators +--- Internal memory allocator +---@param size integer +---@return userdata +function rl.MemAlloc(size) end + +--- Internal memory reallocator +---@param ptr userdata +---@param size integer +---@return userdata +function rl.MemRealloc(ptr, size) end + +--- Internal memory free +---@param ptr userdata +function rl.MemFree(ptr) end + +--- File system management functions +--- Load file data as byte array (read) +---@param fileName string +---@param dataSize userdata +---@return userdata +function rl.LoadFileData(fileName, dataSize) end + +--- Unload file data allocated by LoadFileData() +---@param data userdata +function rl.UnloadFileData(data) end + +--- Save data to file from byte array (write), returns true on success +---@param fileName string +---@param data userdata +---@param dataSize integer +---@return boolean +function rl.SaveFileData(fileName, data, dataSize) end + +--- Export data to code (.h), returns true on success +---@param data userdata +---@param dataSize integer +---@param fileName string +---@return boolean +function rl.ExportDataAsCode(data, dataSize, fileName) end + +--- Load text data from file (read), returns a '\0' terminated string +---@param fileName string +---@return string +function rl.LoadFileText(fileName) end + +--- Unload file text data allocated by LoadFileText() +---@param text string +function rl.UnloadFileText(text) end + +--- Save text data to file (write), string must be '\0' terminated, returns true on success +---@param fileName string +---@param text string +---@return boolean +function rl.SaveFileText(fileName, text) end + +--- File access custom callbacks +--- WARNING: Callbacks setup is intended for advanced users +--- Set custom file binary data loader +---@param callback rl.LoadFileDataCallback +function rl.SetLoadFileDataCallback(callback) end + +--- Set custom file binary data saver +---@param callback rl.SaveFileDataCallback +function rl.SetSaveFileDataCallback(callback) end + +--- Set custom file text data loader +---@param callback rl.LoadFileTextCallback +function rl.SetLoadFileTextCallback(callback) end + +--- Set custom file text data saver +---@param callback rl.SaveFileTextCallback +function rl.SetSaveFileTextCallback(callback) end + +--- Rename file (if exists) +---@param fileName string +---@param fileRename string +---@return integer +function rl.FileRename(fileName, fileRename) end + +--- Remove file (if exists) +---@param fileName string +---@return integer +function rl.FileRemove(fileName) end + +--- Copy file from one path to another, dstPath created if it doesn't exist +---@param srcPath string +---@param dstPath string +---@return integer +function rl.FileCopy(srcPath, dstPath) end + +--- Move file from one directory to another, dstPath created if it doesn't exist +---@param srcPath string +---@param dstPath string +---@return integer +function rl.FileMove(srcPath, dstPath) end + +--- Replace text in an existing file +---@param fileName string +---@param search string +---@param replacement string +---@return integer +function rl.FileTextReplace(fileName, search, replacement) end + +--- Find text in existing file +---@param fileName string +---@param search string +---@return integer +function rl.FileTextFindIndex(fileName, search) end + +--- Check if file exists +---@param fileName string +---@return boolean +function rl.FileExists(fileName) end + +--- Check if a directory path exists +---@param dirPath string +---@return boolean +function rl.DirectoryExists(dirPath) end + +--- Check file extension (recommended include point: .png, .wav) +---@param fileName string +---@param ext string +---@return boolean +function rl.IsFileExtension(fileName, ext) end + +--- Get file length in bytes (NOTE: GetFileSize() conflicts with windows.h) +---@param fileName string +---@return integer +function rl.GetFileLength(fileName) end + +--- Get file modification time (last write time) +---@param fileName string +---@return integer +function rl.GetFileModTime(fileName) end + +--- Get pointer to extension for a filename string (includes dot: '.png') +---@param fileName string +---@return string +function rl.GetFileExtension(fileName) end + +--- Get pointer to filename for a path string +---@param filePath string +---@return string +function rl.GetFileName(filePath) end + +--- Get filename string without extension (uses static string) +---@param filePath string +---@return string +function rl.GetFileNameWithoutExt(filePath) end + +--- Get full path for a given fileName with path (uses static string) +---@param filePath string +---@return string +function rl.GetDirectoryPath(filePath) end + +--- Get previous directory path for a given path (uses static string) +---@param dirPath string +---@return string +function rl.GetPrevDirectoryPath(dirPath) end + +--- Get current working directory (uses static string) +---@return string +function rl.GetWorkingDirectory() end + +--- Get the directory of the running application (uses static string) +---@return string +function rl.GetApplicationDirectory() end + +--- Create directories (including full path requested), returns 0 on success +---@param dirPath string +---@return integer +function rl.MakeDirectory(dirPath) end + +--- Change working directory, return true on success +---@param dirPath string +---@return boolean +function rl.ChangeDirectory(dirPath) end + +--- Check if a given path is a file or a directory +---@param path string +---@return boolean +function rl.IsPathFile(path) end + +--- Check if fileName is valid for the platform/OS +---@param fileName string +---@return boolean +function rl.IsFileNameValid(fileName) end + +--- Load directory filepaths, files and directories, no subdirs scan +---@param dirPath string +---@return rl.FilePathList +function rl.LoadDirectoryFiles(dirPath) end + +--- Load directory filepaths with extension filtering and subdir scan; some filters available: "*.*", "FILES*", "DIRS*" +---@param basePath string +---@param filter string +---@param scanSubdirs boolean +---@return rl.FilePathList +function rl.LoadDirectoryFilesEx(basePath, filter, scanSubdirs) end + +--- Unload filepaths +---@param files rl.FilePathList +function rl.UnloadDirectoryFiles(files) end + +--- Check if a file has been dropped into window +---@return boolean +function rl.IsFileDropped() end + +--- Load dropped filepaths +---@return rl.FilePathList +function rl.LoadDroppedFiles() end + +--- Unload dropped filepaths +---@param files rl.FilePathList +function rl.UnloadDroppedFiles(files) end + +--- Get the file count in a directory +---@param dirPath string +---@return integer +function rl.GetDirectoryFileCount(dirPath) end + +--- Get the file count in a directory with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result +---@param basePath string +---@param filter string +---@param scanSubdirs boolean +---@return integer +function rl.GetDirectoryFileCountEx(basePath, filter, scanSubdirs) end + +--- Compression/Encoding functionality +--- Compress data (DEFLATE algorithm), memory must be MemFree() +---@param data userdata +---@param dataSize integer +---@param compDataSize userdata +---@return userdata +function rl.CompressData(data, dataSize, compDataSize) end + +--- Decompress data (DEFLATE algorithm), memory must be MemFree() +---@param compData userdata +---@param compDataSize integer +---@param dataSize userdata +---@return userdata +function rl.DecompressData(compData, compDataSize, dataSize) end + +--- Encode data to Base64 string (includes NULL terminator), memory must be MemFree() +---@param data userdata +---@param dataSize integer +---@param outputSize userdata +---@return string +function rl.EncodeDataBase64(data, dataSize, outputSize) end + +--- Decode Base64 string (expected NULL terminated), memory must be MemFree() +---@param text string +---@param outputSize userdata +---@return userdata +function rl.DecodeDataBase64(text, outputSize) end + +--- Compute CRC32 hash code +---@param data userdata +---@param dataSize integer +---@return integer +function rl.ComputeCRC32(data, dataSize) end + +--- Compute MD5 hash code, returns static int[4] (16 bytes) +---@param data userdata +---@param dataSize integer +---@return userdata +function rl.ComputeMD5(data, dataSize) end + +--- Compute SHA1 hash code, returns static int[5] (20 bytes) +---@param data userdata +---@param dataSize integer +---@return userdata +function rl.ComputeSHA1(data, dataSize) end + +--- Compute SHA256 hash code, returns static int[8] (32 bytes) +---@param data userdata +---@param dataSize integer +---@return userdata +function rl.ComputeSHA256(data, dataSize) end + +--- Automation events functionality +--- Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS +---@param fileName string +---@return rl.AutomationEventList +function rl.LoadAutomationEventList(fileName) end + +--- Unload automation events list from file +---@param list rl.AutomationEventList +function rl.UnloadAutomationEventList(list) end + +--- Export automation events list as text file +---@param list rl.AutomationEventList +---@param fileName string +---@return boolean +function rl.ExportAutomationEventList(list, fileName) end + +--- Set automation event list to record to +---@param list userdata +function rl.SetAutomationEventList(list) end + +--- Set automation event internal base frame to start recording +---@param frame integer +function rl.SetAutomationEventBaseFrame(frame) end + +--- Start recording automation events (AutomationEventList must be set) +function rl.StartAutomationEventRecording() end + +--- Stop recording automation events +function rl.StopAutomationEventRecording() end + +--- Play a recorded automation event +---@param event rl.AutomationEvent +function rl.PlayAutomationEvent(event) end + +--- Input Handling Functions (Module: core) +--- Input-related functions: keyboard +--- Check if a key has been pressed once +---@param key integer +---@return boolean +function rl.IsKeyPressed(key) end + +--- Check if a key has been pressed again +---@param key integer +---@return boolean +function rl.IsKeyPressedRepeat(key) end + +--- Check if a key is being pressed +---@param key integer +---@return boolean +function rl.IsKeyDown(key) end + +--- Check if a key has been released once +---@param key integer +---@return boolean +function rl.IsKeyReleased(key) end + +--- Check if a key is NOT being pressed +---@param key integer +---@return boolean +function rl.IsKeyUp(key) end + +--- Get key pressed (keycode), call it multiple times for keys queued, returns 0 when the queue is empty +---@return integer +function rl.GetKeyPressed() end + +--- Get char pressed (unicode), call it multiple times for chars queued, returns 0 when the queue is empty +---@return integer +function rl.GetCharPressed() end + +--- Get name of a QWERTY key on the current keyboard layout (eg returns string 'q' for KEY_A on an AZERTY keyboard) +---@param key integer +---@return string +function rl.GetKeyName(key) end + +--- Set a custom key to exit program (default is ESC) +---@param key integer +function rl.SetExitKey(key) end + +--- Input-related functions: gamepads +--- Check if a gamepad is available +---@param gamepad integer +---@return boolean +function rl.IsGamepadAvailable(gamepad) end + +--- Get gamepad internal name id +---@param gamepad integer +---@return string +function rl.GetGamepadName(gamepad) end + +--- Check if a gamepad button has been pressed once +---@param gamepad integer +---@param button integer +---@return boolean +function rl.IsGamepadButtonPressed(gamepad, button) end + +--- Check if a gamepad button is being pressed +---@param gamepad integer +---@param button integer +---@return boolean +function rl.IsGamepadButtonDown(gamepad, button) end + +--- Check if a gamepad button has been released once +---@param gamepad integer +---@param button integer +---@return boolean +function rl.IsGamepadButtonReleased(gamepad, button) end + +--- Check if a gamepad button is NOT being pressed +---@param gamepad integer +---@param button integer +---@return boolean +function rl.IsGamepadButtonUp(gamepad, button) end + +--- Get the last gamepad button pressed +---@return integer +function rl.GetGamepadButtonPressed() end + +--- Get axis count for a gamepad +---@param gamepad integer +---@return integer +function rl.GetGamepadAxisCount(gamepad) end + +--- Get movement value for a gamepad axis +---@param gamepad integer +---@param axis integer +---@return number +function rl.GetGamepadAxisMovement(gamepad, axis) end + +--- Set internal gamepad mappings (SDL_GameControllerDB) +---@param mappings string +---@return integer +function rl.SetGamepadMappings(mappings) end + +--- Set gamepad vibration for both motors (duration in seconds) +---@param gamepad integer +---@param leftMotor number +---@param rightMotor number +---@param duration number +function rl.SetGamepadVibration(gamepad, leftMotor, rightMotor, duration) end + +--- Input-related functions: mouse +--- Check if a mouse button has been pressed once +---@param button integer +---@return boolean +function rl.IsMouseButtonPressed(button) end + +--- Check if a mouse button is being pressed +---@param button integer +---@return boolean +function rl.IsMouseButtonDown(button) end + +--- Check if a mouse button has been released once +---@param button integer +---@return boolean +function rl.IsMouseButtonReleased(button) end + +--- Check if a mouse button is NOT being pressed +---@param button integer +---@return boolean +function rl.IsMouseButtonUp(button) end + +--- Get mouse position X +---@return integer +function rl.GetMouseX() end + +--- Get mouse position Y +---@return integer +function rl.GetMouseY() end + +--- Get mouse position XY +---@return rl.Vector2 +function rl.GetMousePosition() end + +--- Get mouse delta between frames +---@return rl.Vector2 +function rl.GetMouseDelta() end + +--- Set mouse position XY +---@param x integer +---@param y integer +function rl.SetMousePosition(x, y) end + +--- Set mouse offset +---@param offsetX integer +---@param offsetY integer +function rl.SetMouseOffset(offsetX, offsetY) end + +--- Set mouse scaling +---@param scaleX number +---@param scaleY number +function rl.SetMouseScale(scaleX, scaleY) end + +--- Get mouse wheel movement for X or Y, whichever is larger +---@return number +function rl.GetMouseWheelMove() end + +--- Get mouse wheel movement for both X and Y +---@return rl.Vector2 +function rl.GetMouseWheelMoveV() end + +--- Set mouse cursor +---@param cursor integer +function rl.SetMouseCursor(cursor) end + +--- Input-related functions: touch +--- Get touch position X for touch point 0 (relative to screen size) +---@return integer +function rl.GetTouchX() end + +--- Get touch position Y for touch point 0 (relative to screen size) +---@return integer +function rl.GetTouchY() end + +--- Get touch position XY for a touch point index (relative to screen size) +---@param index integer +---@return rl.Vector2 +function rl.GetTouchPosition(index) end + +--- Get touch point identifier for given index +---@param index integer +---@return integer +function rl.GetTouchPointId(index) end + +--- Get number of touch points +---@return integer +function rl.GetTouchPointCount() end + +--- Gestures and Touch Handling Functions (Module: rgestures) +--- Enable a set of gestures using flags +---@param flags integer +function rl.SetGesturesEnabled(flags) end + +--- Check if a gesture have been detected +---@param gesture integer +---@return boolean +function rl.IsGestureDetected(gesture) end + +--- Get latest detected gesture +---@return integer +function rl.GetGestureDetected() end + +--- Get gesture hold time in seconds +---@return number +function rl.GetGestureHoldDuration() end + +--- Get gesture drag vector +---@return rl.Vector2 +function rl.GetGestureDragVector() end + +--- Get gesture drag angle +---@return number +function rl.GetGestureDragAngle() end + +--- Get gesture pinch delta +---@return rl.Vector2 +function rl.GetGesturePinchVector() end + +--- Get gesture pinch angle +---@return number +function rl.GetGesturePinchAngle() end + +--- Camera System Functions (Module: rcamera) +--- Update camera position for selected mode +---@param camera userdata +---@param mode integer +function rl.UpdateCamera(camera, mode) end + +--- Update camera movement/rotation +---@param camera userdata +---@param movement rl.Vector3 +---@param rotation rl.Vector3 +---@param zoom number +function rl.UpdateCameraPro(camera, movement, rotation, zoom) end + +--- Basic Shapes Drawing Functions (Module: shapes) +--- Set texture and rectangle to be used on shapes drawing +--- NOTE: It can be useful when using basic shapes and one single font, +--- defining a font char white rectangle would allow drawing everything in a single draw call +--- Set texture and rectangle to be used on shapes drawing +---@param texture rl.Texture +---@param source rl.Rectangle +function rl.SetShapesTexture(texture, source) end + +--- Get texture that is used for shapes drawing +---@return rl.Texture +function rl.GetShapesTexture() end + +--- Get texture source rectangle that is used for shapes drawing +---@return rl.Rectangle +function rl.GetShapesTextureRectangle() end + +--- Basic shapes drawing functions +--- Draw a pixel using geometry [Can be slow, use with care] +---@param posX integer +---@param posY integer +---@param color rl.Color +function rl.DrawPixel(posX, posY, color) end + +--- Draw a pixel using geometry (Vector version) [Can be slow, use with care] +---@param position rl.Vector2 +---@param color rl.Color +function rl.DrawPixelV(position, color) end + +--- Draw a line +---@param startPosX integer +---@param startPosY integer +---@param endPosX integer +---@param endPosY integer +---@param color rl.Color +function rl.DrawLine(startPosX, startPosY, endPosX, endPosY, color) end + +--- Draw a line (using gl lines) +---@param startPos rl.Vector2 +---@param endPos rl.Vector2 +---@param color rl.Color +function rl.DrawLineV(startPos, endPos, color) end + +--- Draw a line (using triangles/quads) +---@param startPos rl.Vector2 +---@param endPos rl.Vector2 +---@param thick number +---@param color rl.Color +function rl.DrawLineEx(startPos, endPos, thick, color) end + +--- Draw lines sequence (using gl lines) +---@param points userdata +---@param pointCount integer +---@param color rl.Color +function rl.DrawLineStrip(points, pointCount, color) end + +--- Draw line segment cubic-bezier in-out interpolation +---@param startPos rl.Vector2 +---@param endPos rl.Vector2 +---@param thick number +---@param color rl.Color +function rl.DrawLineBezier(startPos, endPos, thick, color) end + +--- Draw a dashed line +---@param startPos rl.Vector2 +---@param endPos rl.Vector2 +---@param dashSize integer +---@param spaceSize integer +---@param color rl.Color +function rl.DrawLineDashed(startPos, endPos, dashSize, spaceSize, color) end + +--- Draw a color-filled circle +---@param centerX integer +---@param centerY integer +---@param radius number +---@param color rl.Color +function rl.DrawCircle(centerX, centerY, radius, color) end + +--- Draw a color-filled circle (Vector version) +---@param center rl.Vector2 +---@param radius number +---@param color rl.Color +function rl.DrawCircleV(center, radius, color) end + +--- Draw a gradient-filled circle +---@param center rl.Vector2 +---@param radius number +---@param inner rl.Color +---@param outer rl.Color +function rl.DrawCircleGradient(center, radius, inner, outer) end + +--- Draw a piece of a circle +---@param center rl.Vector2 +---@param radius number +---@param startAngle number +---@param endAngle number +---@param segments integer +---@param color rl.Color +function rl.DrawCircleSector(center, radius, startAngle, endAngle, segments, color) end + +--- Draw circle sector outline +---@param center rl.Vector2 +---@param radius number +---@param startAngle number +---@param endAngle number +---@param segments integer +---@param color rl.Color +function rl.DrawCircleSectorLines(center, radius, startAngle, endAngle, segments, color) end + +--- Draw circle outline +---@param centerX integer +---@param centerY integer +---@param radius number +---@param color rl.Color +function rl.DrawCircleLines(centerX, centerY, radius, color) end + +--- Draw circle outline (Vector version) +---@param center rl.Vector2 +---@param radius number +---@param color rl.Color +function rl.DrawCircleLinesV(center, radius, color) end + +--- Draw ellipse +---@param centerX integer +---@param centerY integer +---@param radiusH number +---@param radiusV number +---@param color rl.Color +function rl.DrawEllipse(centerX, centerY, radiusH, radiusV, color) end + +--- Draw ellipse (Vector version) +---@param center rl.Vector2 +---@param radiusH number +---@param radiusV number +---@param color rl.Color +function rl.DrawEllipseV(center, radiusH, radiusV, color) end + +--- Draw ellipse outline +---@param centerX integer +---@param centerY integer +---@param radiusH number +---@param radiusV number +---@param color rl.Color +function rl.DrawEllipseLines(centerX, centerY, radiusH, radiusV, color) end + +--- Draw ellipse outline (Vector version) +---@param center rl.Vector2 +---@param radiusH number +---@param radiusV number +---@param color rl.Color +function rl.DrawEllipseLinesV(center, radiusH, radiusV, color) end + +--- Draw ring +---@param center rl.Vector2 +---@param innerRadius number +---@param outerRadius number +---@param startAngle number +---@param endAngle number +---@param segments integer +---@param color rl.Color +function rl.DrawRing(center, innerRadius, outerRadius, startAngle, endAngle, segments, color) end + +--- Draw ring outline +---@param center rl.Vector2 +---@param innerRadius number +---@param outerRadius number +---@param startAngle number +---@param endAngle number +---@param segments integer +---@param color rl.Color +function rl.DrawRingLines(center, innerRadius, outerRadius, startAngle, endAngle, segments, color) end + +--- Draw a color-filled rectangle +---@param posX integer +---@param posY integer +---@param width integer +---@param height integer +---@param color rl.Color +function rl.DrawRectangle(posX, posY, width, height, color) end + +--- Draw a color-filled rectangle (Vector version) +---@param position rl.Vector2 +---@param size rl.Vector2 +---@param color rl.Color +function rl.DrawRectangleV(position, size, color) end + +--- Draw a color-filled rectangle +---@param rec rl.Rectangle +---@param color rl.Color +function rl.DrawRectangleRec(rec, color) end + +--- Draw a color-filled rectangle with pro parameters +---@param rec rl.Rectangle +---@param origin rl.Vector2 +---@param rotation number +---@param color rl.Color +function rl.DrawRectanglePro(rec, origin, rotation, color) end + +--- Draw a vertical-gradient-filled rectangle +---@param posX integer +---@param posY integer +---@param width integer +---@param height integer +---@param top rl.Color +---@param bottom rl.Color +function rl.DrawRectangleGradientV(posX, posY, width, height, top, bottom) end + +--- Draw a horizontal-gradient-filled rectangle +---@param posX integer +---@param posY integer +---@param width integer +---@param height integer +---@param left rl.Color +---@param right rl.Color +function rl.DrawRectangleGradientH(posX, posY, width, height, left, right) end + +--- Draw a gradient-filled rectangle with custom vertex colors +---@param rec rl.Rectangle +---@param topLeft rl.Color +---@param bottomLeft rl.Color +---@param bottomRight rl.Color +---@param topRight rl.Color +function rl.DrawRectangleGradientEx(rec, topLeft, bottomLeft, bottomRight, topRight) end + +--- Draw rectangle outline +---@param posX integer +---@param posY integer +---@param width integer +---@param height integer +---@param color rl.Color +function rl.DrawRectangleLines(posX, posY, width, height, color) end + +--- Draw rectangle outline with extended parameters +---@param rec rl.Rectangle +---@param lineThick number +---@param color rl.Color +function rl.DrawRectangleLinesEx(rec, lineThick, color) end + +--- Draw rectangle with rounded edges +---@param rec rl.Rectangle +---@param roundness number +---@param segments integer +---@param color rl.Color +function rl.DrawRectangleRounded(rec, roundness, segments, color) end + +--- Draw rectangle lines with rounded edges +---@param rec rl.Rectangle +---@param roundness number +---@param segments integer +---@param color rl.Color +function rl.DrawRectangleRoundedLines(rec, roundness, segments, color) end + +--- Draw rectangle with rounded edges outline +---@param rec rl.Rectangle +---@param roundness number +---@param segments integer +---@param lineThick number +---@param color rl.Color +function rl.DrawRectangleRoundedLinesEx(rec, roundness, segments, lineThick, color) end + +--- Draw a color-filled triangle (vertex in counter-clockwise order!) +---@param v1 rl.Vector2 +---@param v2 rl.Vector2 +---@param v3 rl.Vector2 +---@param color rl.Color +function rl.DrawTriangle(v1, v2, v3, color) end + +--- Draw triangle outline (vertex in counter-clockwise order!) +---@param v1 rl.Vector2 +---@param v2 rl.Vector2 +---@param v3 rl.Vector2 +---@param color rl.Color +function rl.DrawTriangleLines(v1, v2, v3, color) end + +--- Draw a triangle fan defined by points (first vertex is the center) +---@param points userdata +---@param pointCount integer +---@param color rl.Color +function rl.DrawTriangleFan(points, pointCount, color) end + +--- Draw a triangle strip defined by points +---@param points userdata +---@param pointCount integer +---@param color rl.Color +function rl.DrawTriangleStrip(points, pointCount, color) end + +--- Draw a regular polygon (Vector version) +---@param center rl.Vector2 +---@param sides integer +---@param radius number +---@param rotation number +---@param color rl.Color +function rl.DrawPoly(center, sides, radius, rotation, color) end + +--- Draw a polygon outline of n sides +---@param center rl.Vector2 +---@param sides integer +---@param radius number +---@param rotation number +---@param color rl.Color +function rl.DrawPolyLines(center, sides, radius, rotation, color) end + +--- Draw a polygon outline of n sides with extended parameters +---@param center rl.Vector2 +---@param sides integer +---@param radius number +---@param rotation number +---@param lineThick number +---@param color rl.Color +function rl.DrawPolyLinesEx(center, sides, radius, rotation, lineThick, color) end + +--- Splines drawing functions +--- Draw spline: Linear, minimum 2 points +---@param points userdata +---@param pointCount integer +---@param thick number +---@param color rl.Color +function rl.DrawSplineLinear(points, pointCount, thick, color) end + +--- Draw spline: B-Spline, minimum 4 points +---@param points userdata +---@param pointCount integer +---@param thick number +---@param color rl.Color +function rl.DrawSplineBasis(points, pointCount, thick, color) end + +--- Draw spline: Catmull-Rom, minimum 4 points +---@param points userdata +---@param pointCount integer +---@param thick number +---@param color rl.Color +function rl.DrawSplineCatmullRom(points, pointCount, thick, color) end + +--- Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...] +---@param points userdata +---@param pointCount integer +---@param thick number +---@param color rl.Color +function rl.DrawSplineBezierQuadratic(points, pointCount, thick, color) end + +--- Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...] +---@param points userdata +---@param pointCount integer +---@param thick number +---@param color rl.Color +function rl.DrawSplineBezierCubic(points, pointCount, thick, color) end + +--- Draw spline segment: Linear, 2 points +---@param p1 rl.Vector2 +---@param p2 rl.Vector2 +---@param thick number +---@param color rl.Color +function rl.DrawSplineSegmentLinear(p1, p2, thick, color) end + +--- Draw spline segment: B-Spline, 4 points +---@param p1 rl.Vector2 +---@param p2 rl.Vector2 +---@param p3 rl.Vector2 +---@param p4 rl.Vector2 +---@param thick number +---@param color rl.Color +function rl.DrawSplineSegmentBasis(p1, p2, p3, p4, thick, color) end + +--- Draw spline segment: Catmull-Rom, 4 points +---@param p1 rl.Vector2 +---@param p2 rl.Vector2 +---@param p3 rl.Vector2 +---@param p4 rl.Vector2 +---@param thick number +---@param color rl.Color +function rl.DrawSplineSegmentCatmullRom(p1, p2, p3, p4, thick, color) end + +--- Draw spline segment: Quadratic Bezier, 2 points, 1 control point +---@param p1 rl.Vector2 +---@param c2 rl.Vector2 +---@param p3 rl.Vector2 +---@param thick number +---@param color rl.Color +function rl.DrawSplineSegmentBezierQuadratic(p1, c2, p3, thick, color) end + +--- Draw spline segment: Cubic Bezier, 2 points, 2 control points +---@param p1 rl.Vector2 +---@param c2 rl.Vector2 +---@param c3 rl.Vector2 +---@param p4 rl.Vector2 +---@param thick number +---@param color rl.Color +function rl.DrawSplineSegmentBezierCubic(p1, c2, c3, p4, thick, color) end + +--- Spline segment point evaluation functions, for a given t [0.0f .. 1.0f] +--- Get (evaluate) spline point: Linear +---@param startPos rl.Vector2 +---@param endPos rl.Vector2 +---@param t number +---@return rl.Vector2 +function rl.GetSplinePointLinear(startPos, endPos, t) end + +--- Get (evaluate) spline point: B-Spline +---@param p1 rl.Vector2 +---@param p2 rl.Vector2 +---@param p3 rl.Vector2 +---@param p4 rl.Vector2 +---@param t number +---@return rl.Vector2 +function rl.GetSplinePointBasis(p1, p2, p3, p4, t) end + +--- Get (evaluate) spline point: Catmull-Rom +---@param p1 rl.Vector2 +---@param p2 rl.Vector2 +---@param p3 rl.Vector2 +---@param p4 rl.Vector2 +---@param t number +---@return rl.Vector2 +function rl.GetSplinePointCatmullRom(p1, p2, p3, p4, t) end + +--- Get (evaluate) spline point: Quadratic Bezier +---@param p1 rl.Vector2 +---@param c2 rl.Vector2 +---@param p3 rl.Vector2 +---@param t number +---@return rl.Vector2 +function rl.GetSplinePointBezierQuad(p1, c2, p3, t) end + +--- Get (evaluate) spline point: Cubic Bezier +---@param p1 rl.Vector2 +---@param c2 rl.Vector2 +---@param c3 rl.Vector2 +---@param p4 rl.Vector2 +---@param t number +---@return rl.Vector2 +function rl.GetSplinePointBezierCubic(p1, c2, c3, p4, t) end + +--- Basic shapes collision detection functions +--- Check collision between two rectangles +---@param rec1 rl.Rectangle +---@param rec2 rl.Rectangle +---@return boolean +function rl.CheckCollisionRecs(rec1, rec2) end + +--- Check collision between two circles +---@param center1 rl.Vector2 +---@param radius1 number +---@param center2 rl.Vector2 +---@param radius2 number +---@return boolean +function rl.CheckCollisionCircles(center1, radius1, center2, radius2) end + +--- Check collision between circle and rectangle +---@param center rl.Vector2 +---@param radius number +---@param rec rl.Rectangle +---@return boolean +function rl.CheckCollisionCircleRec(center, radius, rec) end + +--- Check if circle collides with a line created betweeen two points [p1] and [p2] +---@param center rl.Vector2 +---@param radius number +---@param p1 rl.Vector2 +---@param p2 rl.Vector2 +---@return boolean +function rl.CheckCollisionCircleLine(center, radius, p1, p2) end + +--- Check if point is inside rectangle +---@param point rl.Vector2 +---@param rec rl.Rectangle +---@return boolean +function rl.CheckCollisionPointRec(point, rec) end + +--- Check if point is inside circle +---@param point rl.Vector2 +---@param center rl.Vector2 +---@param radius number +---@return boolean +function rl.CheckCollisionPointCircle(point, center, radius) end + +--- Check if point is inside a triangle +---@param point rl.Vector2 +---@param p1 rl.Vector2 +---@param p2 rl.Vector2 +---@param p3 rl.Vector2 +---@return boolean +function rl.CheckCollisionPointTriangle(point, p1, p2, p3) end + +--- Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold] +---@param point rl.Vector2 +---@param p1 rl.Vector2 +---@param p2 rl.Vector2 +---@param threshold integer +---@return boolean +function rl.CheckCollisionPointLine(point, p1, p2, threshold) end + +--- Check if point is within a polygon described by array of vertices +---@param point rl.Vector2 +---@param points userdata +---@param pointCount integer +---@return boolean +function rl.CheckCollisionPointPoly(point, points, pointCount) end + +--- Check the collision between two lines defined by two points each, returns collision point by reference +---@param startPos1 rl.Vector2 +---@param endPos1 rl.Vector2 +---@param startPos2 rl.Vector2 +---@param endPos2 rl.Vector2 +---@param collisionPoint userdata +---@return boolean +function rl.CheckCollisionLines(startPos1, endPos1, startPos2, endPos2, collisionPoint) end + +--- Get collision rectangle for two rectangles collision +---@param rec1 rl.Rectangle +---@param rec2 rl.Rectangle +---@return rl.Rectangle +function rl.GetCollisionRec(rec1, rec2) end + +--- Texture Loading and Drawing Functions (Module: textures) +--- Image loading functions +--- NOTE: These functions do not require GPU access +--- Load image from file into CPU memory (RAM) +---@param fileName string +---@return rl.Image +function rl.LoadImage(fileName) end + +--- Load image from RAW file data +---@param fileName string +---@param width integer +---@param height integer +---@param format integer +---@param headerSize integer +---@return rl.Image +function rl.LoadImageRaw(fileName, width, height, format, headerSize) end + +--- Load image sequence from file (frames appended to image.data) +---@param fileName string +---@param frames userdata +---@return rl.Image +function rl.LoadImageAnim(fileName, frames) end + +--- Load image sequence from memory buffer +---@param fileType string +---@param fileData userdata +---@param dataSize integer +---@param frames userdata +---@return rl.Image +function rl.LoadImageAnimFromMemory(fileType, fileData, dataSize, frames) end + +--- Load image from memory buffer, fileType refers to extension: i.e. '.png' +---@param fileType string +---@param fileData userdata +---@param dataSize integer +---@return rl.Image +function rl.LoadImageFromMemory(fileType, fileData, dataSize) end + +--- Load image from GPU texture data +---@param texture rl.Texture +---@return rl.Image +function rl.LoadImageFromTexture(texture) end + +--- Load image from screen buffer and (screenshot) +---@return rl.Image +function rl.LoadImageFromScreen() end + +--- Check if an image is valid (data and parameters) +---@param image rl.Image +---@return boolean +function rl.IsImageValid(image) end + +--- Unload image from CPU memory (RAM) +---@param image rl.Image +function rl.UnloadImage(image) end + +--- Export image data to file, returns true on success +---@param image rl.Image +---@param fileName string +---@return boolean +function rl.ExportImage(image, fileName) end + +--- Export image to memory buffer, memory must be MemFree() +---@param image rl.Image +---@param fileType string +---@param fileSize userdata +---@return userdata +function rl.ExportImageToMemory(image, fileType, fileSize) end + +--- Export image as code file defining an array of bytes, returns true on success +---@param image rl.Image +---@param fileName string +---@return boolean +function rl.ExportImageAsCode(image, fileName) end + +--- Image generation functions +--- Generate image: plain color +---@param width integer +---@param height integer +---@param color rl.Color +---@return rl.Image +function rl.GenImageColor(width, height, color) end + +--- Generate image: linear gradient, direction in degrees [0..360], 0=Vertical gradient +---@param width integer +---@param height integer +---@param direction integer +---@param start rl.Color +---@param end_ rl.Color +---@return rl.Image +function rl.GenImageGradientLinear(width, height, direction, start, end_) end + +--- Generate image: radial gradient +---@param width integer +---@param height integer +---@param density number +---@param inner rl.Color +---@param outer rl.Color +---@return rl.Image +function rl.GenImageGradientRadial(width, height, density, inner, outer) end + +--- Generate image: square gradient +---@param width integer +---@param height integer +---@param density number +---@param inner rl.Color +---@param outer rl.Color +---@return rl.Image +function rl.GenImageGradientSquare(width, height, density, inner, outer) end + +--- Generate image: checked +---@param width integer +---@param height integer +---@param checksX integer +---@param checksY integer +---@param col1 rl.Color +---@param col2 rl.Color +---@return rl.Image +function rl.GenImageChecked(width, height, checksX, checksY, col1, col2) end + +--- Generate image: white noise +---@param width integer +---@param height integer +---@param factor number +---@return rl.Image +function rl.GenImageWhiteNoise(width, height, factor) end + +--- Generate image: perlin noise +---@param width integer +---@param height integer +---@param offsetX integer +---@param offsetY integer +---@param scale number +---@return rl.Image +function rl.GenImagePerlinNoise(width, height, offsetX, offsetY, scale) end + +--- Generate image: cellular algorithm, bigger tileSize means bigger cells +---@param width integer +---@param height integer +---@param tileSize integer +---@return rl.Image +function rl.GenImageCellular(width, height, tileSize) end + +--- Generate image: grayscale image from text data +---@param width integer +---@param height integer +---@param text string +---@return rl.Image +function rl.GenImageText(width, height, text) end + +--- Image manipulation functions +--- Create an image duplicate (useful for transformations) +---@param image rl.Image +---@return rl.Image +function rl.ImageCopy(image) end + +--- Create an image from another image piece +---@param image rl.Image +---@param rec rl.Rectangle +---@return rl.Image +function rl.ImageFromImage(image, rec) end + +--- Create an image from a selected channel of another image (GRAYSCALE) +---@param image rl.Image +---@param selectedChannel integer +---@return rl.Image +function rl.ImageFromChannel(image, selectedChannel) end + +--- Create an image from text (default font) +---@param text string +---@param fontSize integer +---@param color rl.Color +---@return rl.Image +function rl.ImageText(text, fontSize, color) end + +--- Create an image from text (custom sprite font) +---@param font rl.Font +---@param text string +---@param fontSize number +---@param spacing number +---@param tint rl.Color +---@return rl.Image +function rl.ImageTextEx(font, text, fontSize, spacing, tint) end + +--- Convert image data to desired format +---@param image userdata +---@param newFormat integer +function rl.ImageFormat(image, newFormat) end + +--- Convert image to POT (power-of-two) +---@param image userdata +---@param fill rl.Color +function rl.ImageToPOT(image, fill) end + +--- Crop an image to a defined rectangle +---@param image userdata +---@param crop rl.Rectangle +function rl.ImageCrop(image, crop) end + +--- Crop image depending on alpha value +---@param image userdata +---@param threshold number +function rl.ImageAlphaCrop(image, threshold) end + +--- Clear alpha channel to desired color +---@param image userdata +---@param color rl.Color +---@param threshold number +function rl.ImageAlphaClear(image, color, threshold) end + +--- Apply alpha mask to image +---@param image userdata +---@param alphaMask rl.Image +function rl.ImageAlphaMask(image, alphaMask) end + +--- Premultiply alpha channel +---@param image userdata +function rl.ImageAlphaPremultiply(image) end + +--- Apply Gaussian blur using a box blur approximation +---@param image userdata +---@param blurSize integer +function rl.ImageBlurGaussian(image, blurSize) end + +--- Apply custom square convolution kernel to image +---@param image userdata +---@param kernel userdata +---@param kernelSize integer +function rl.ImageKernelConvolution(image, kernel, kernelSize) end + +--- Resize image (Bicubic scaling algorithm) +---@param image userdata +---@param newWidth integer +---@param newHeight integer +function rl.ImageResize(image, newWidth, newHeight) end + +--- Resize image (Nearest-Neighbor scaling algorithm) +---@param image userdata +---@param newWidth integer +---@param newHeight integer +function rl.ImageResizeNN(image, newWidth, newHeight) end + +--- Resize canvas and fill with color +---@param image userdata +---@param newWidth integer +---@param newHeight integer +---@param offsetX integer +---@param offsetY integer +---@param fill rl.Color +function rl.ImageResizeCanvas(image, newWidth, newHeight, offsetX, offsetY, fill) end + +--- Compute all mipmap levels for a provided image +---@param image userdata +function rl.ImageMipmaps(image) end + +--- Dither image data to 16bpp or lower (Floyd-Steinberg dithering) +---@param image userdata +---@param rBpp integer +---@param gBpp integer +---@param bBpp integer +---@param aBpp integer +function rl.ImageDither(image, rBpp, gBpp, bBpp, aBpp) end + +--- Flip image vertically +---@param image userdata +function rl.ImageFlipVertical(image) end + +--- Flip image horizontally +---@param image userdata +function rl.ImageFlipHorizontal(image) end + +--- Rotate image by input angle in degrees (-359 to 359) +---@param image userdata +---@param degrees integer +function rl.ImageRotate(image, degrees) end + +--- Rotate image clockwise 90deg +---@param image userdata +function rl.ImageRotateCW(image) end + +--- Rotate image counter-clockwise 90deg +---@param image userdata +function rl.ImageRotateCCW(image) end + +--- Modify image color: tint +---@param image userdata +---@param color rl.Color +function rl.ImageColorTint(image, color) end + +--- Modify image color: invert +---@param image userdata +function rl.ImageColorInvert(image) end + +--- Modify image color: grayscale +---@param image userdata +function rl.ImageColorGrayscale(image) end + +--- Modify image color: contrast (-100 to 100) +---@param image userdata +---@param contrast number +function rl.ImageColorContrast(image, contrast) end + +--- Modify image color: brightness (-255 to 255) +---@param image userdata +---@param brightness integer +function rl.ImageColorBrightness(image, brightness) end + +--- Modify image color: replace color +---@param image userdata +---@param color rl.Color +---@param replace rl.Color +function rl.ImageColorReplace(image, color, replace) end + +--- Load color data from image as a Color array (RGBA - 32bit) +---@param image rl.Image +---@return userdata +function rl.LoadImageColors(image) end + +--- Load colors palette from image as a Color array (RGBA - 32bit) +---@param image rl.Image +---@param maxPaletteSize integer +---@param colorCount userdata +---@return userdata +function rl.LoadImagePalette(image, maxPaletteSize, colorCount) end + +--- Unload color data loaded with LoadImageColors() +---@param colors userdata +function rl.UnloadImageColors(colors) end + +--- Unload colors palette loaded with LoadImagePalette() +---@param colors userdata +function rl.UnloadImagePalette(colors) end + +--- Get image alpha border rectangle +---@param image rl.Image +---@param threshold number +---@return rl.Rectangle +function rl.GetImageAlphaBorder(image, threshold) end + +--- Get image pixel color at (x, y) position +---@param image rl.Image +---@param x integer +---@param y integer +---@return rl.Color +function rl.GetImageColor(image, x, y) end + +--- Image drawing functions +--- NOTE: Image software-rendering functions (CPU) +--- Clear image background with given color +---@param dst userdata +---@param color rl.Color +function rl.ImageClearBackground(dst, color) end + +--- Draw pixel within an image +---@param dst userdata +---@param posX integer +---@param posY integer +---@param color rl.Color +function rl.ImageDrawPixel(dst, posX, posY, color) end + +--- Draw pixel within an image (Vector version) +---@param dst userdata +---@param position rl.Vector2 +---@param color rl.Color +function rl.ImageDrawPixelV(dst, position, color) end + +--- Draw line within an image +---@param dst userdata +---@param startPosX integer +---@param startPosY integer +---@param endPosX integer +---@param endPosY integer +---@param color rl.Color +function rl.ImageDrawLine(dst, startPosX, startPosY, endPosX, endPosY, color) end + +--- Draw line within an image (Vector version) +---@param dst userdata +---@param start rl.Vector2 +---@param end_ rl.Vector2 +---@param color rl.Color +function rl.ImageDrawLineV(dst, start, end_, color) end + +--- Draw a line defining thickness within an image +---@param dst userdata +---@param start rl.Vector2 +---@param end_ rl.Vector2 +---@param thick integer +---@param color rl.Color +function rl.ImageDrawLineEx(dst, start, end_, thick, color) end + +--- Draw a filled circle within an image +---@param dst userdata +---@param centerX integer +---@param centerY integer +---@param radius integer +---@param color rl.Color +function rl.ImageDrawCircle(dst, centerX, centerY, radius, color) end + +--- Draw a filled circle within an image (Vector version) +---@param dst userdata +---@param center rl.Vector2 +---@param radius integer +---@param color rl.Color +function rl.ImageDrawCircleV(dst, center, radius, color) end + +--- Draw circle outline within an image +---@param dst userdata +---@param centerX integer +---@param centerY integer +---@param radius integer +---@param color rl.Color +function rl.ImageDrawCircleLines(dst, centerX, centerY, radius, color) end + +--- Draw circle outline within an image (Vector version) +---@param dst userdata +---@param center rl.Vector2 +---@param radius integer +---@param color rl.Color +function rl.ImageDrawCircleLinesV(dst, center, radius, color) end + +--- Draw rectangle within an image +---@param dst userdata +---@param posX integer +---@param posY integer +---@param width integer +---@param height integer +---@param color rl.Color +function rl.ImageDrawRectangle(dst, posX, posY, width, height, color) end + +--- Draw rectangle within an image (Vector version) +---@param dst userdata +---@param position rl.Vector2 +---@param size rl.Vector2 +---@param color rl.Color +function rl.ImageDrawRectangleV(dst, position, size, color) end + +--- Draw rectangle within an image +---@param dst userdata +---@param rec rl.Rectangle +---@param color rl.Color +function rl.ImageDrawRectangleRec(dst, rec, color) end + +--- Draw rectangle lines within an image +---@param dst userdata +---@param rec rl.Rectangle +---@param thick integer +---@param color rl.Color +function rl.ImageDrawRectangleLines(dst, rec, thick, color) end + +--- Draw triangle within an image +---@param dst userdata +---@param v1 rl.Vector2 +---@param v2 rl.Vector2 +---@param v3 rl.Vector2 +---@param color rl.Color +function rl.ImageDrawTriangle(dst, v1, v2, v3, color) end + +--- Draw triangle with interpolated colors within an image +---@param dst userdata +---@param v1 rl.Vector2 +---@param v2 rl.Vector2 +---@param v3 rl.Vector2 +---@param c1 rl.Color +---@param c2 rl.Color +---@param c3 rl.Color +function rl.ImageDrawTriangleEx(dst, v1, v2, v3, c1, c2, c3) end + +--- Draw triangle outline within an image +---@param dst userdata +---@param v1 rl.Vector2 +---@param v2 rl.Vector2 +---@param v3 rl.Vector2 +---@param color rl.Color +function rl.ImageDrawTriangleLines(dst, v1, v2, v3, color) end + +--- Draw a triangle fan defined by points within an image (first vertex is the center) +---@param dst userdata +---@param points userdata +---@param pointCount integer +---@param color rl.Color +function rl.ImageDrawTriangleFan(dst, points, pointCount, color) end + +--- Draw a triangle strip defined by points within an image +---@param dst userdata +---@param points userdata +---@param pointCount integer +---@param color rl.Color +function rl.ImageDrawTriangleStrip(dst, points, pointCount, color) end + +--- Draw a source image within a destination image (tint applied to source) +---@param dst userdata +---@param src rl.Image +---@param srcRec rl.Rectangle +---@param dstRec rl.Rectangle +---@param tint rl.Color +function rl.ImageDraw(dst, src, srcRec, dstRec, tint) end + +--- Draw text (using default font) within an image (destination) +---@param dst userdata +---@param text string +---@param posX integer +---@param posY integer +---@param fontSize integer +---@param color rl.Color +function rl.ImageDrawText(dst, text, posX, posY, fontSize, color) end + +--- Draw text (custom sprite font) within an image (destination) +---@param dst userdata +---@param font rl.Font +---@param text string +---@param position rl.Vector2 +---@param fontSize number +---@param spacing number +---@param tint rl.Color +function rl.ImageDrawTextEx(dst, font, text, position, fontSize, spacing, tint) end + +--- Texture loading functions +--- NOTE: These functions require GPU access +--- Load texture from file into GPU memory (VRAM) +---@param fileName string +---@return rl.Texture +function rl.LoadTexture(fileName) end + +--- Load texture from image data +---@param image rl.Image +---@return rl.Texture +function rl.LoadTextureFromImage(image) end + +--- Load cubemap from image, multiple image cubemap layouts supported +---@param image rl.Image +---@param layout integer +---@return rl.Texture +function rl.LoadTextureCubemap(image, layout) end + +--- Load texture for rendering (framebuffer) +---@param width integer +---@param height integer +---@return rl.RenderTexture +function rl.LoadRenderTexture(width, height) end + +--- Check if a texture is valid (loaded in GPU) +---@param texture rl.Texture +---@return boolean +function rl.IsTextureValid(texture) end + +--- Unload texture from GPU memory (VRAM) +---@param texture rl.Texture +function rl.UnloadTexture(texture) end + +--- Check if a render texture is valid (loaded in GPU) +---@param target rl.RenderTexture +---@return boolean +function rl.IsRenderTextureValid(target) end + +--- Unload render texture from GPU memory (VRAM) +---@param target rl.RenderTexture +function rl.UnloadRenderTexture(target) end + +--- Update GPU texture with new data (pixels should be able to fill texture) +---@param texture rl.Texture +---@param pixels userdata +function rl.UpdateTexture(texture, pixels) end + +--- Update GPU texture rectangle with new data (pixels and rec should fit in texture) +---@param texture rl.Texture +---@param rec rl.Rectangle +---@param pixels userdata +function rl.UpdateTextureRec(texture, rec, pixels) end + +--- Texture configuration functions +--- Generate GPU mipmaps for a texture +---@param texture userdata +function rl.GenTextureMipmaps(texture) end + +--- Set texture scaling filter mode +---@param texture rl.Texture +---@param filter integer +function rl.SetTextureFilter(texture, filter) end + +--- Set texture wrapping mode +---@param texture rl.Texture +---@param wrap integer +function rl.SetTextureWrap(texture, wrap) end + +--- Texture drawing functions +--- Draw a Texture2D +---@param texture rl.Texture +---@param posX integer +---@param posY integer +---@param tint rl.Color +function rl.DrawTexture(texture, posX, posY, tint) end + +--- Draw a Texture2D with position defined as Vector2 +---@param texture rl.Texture +---@param position rl.Vector2 +---@param tint rl.Color +function rl.DrawTextureV(texture, position, tint) end + +--- Draw a Texture2D with extended parameters +---@param texture rl.Texture +---@param position rl.Vector2 +---@param rotation number +---@param scale number +---@param tint rl.Color +function rl.DrawTextureEx(texture, position, rotation, scale, tint) end + +--- Draw a part of a texture defined by a rectangle +---@param texture rl.Texture +---@param source rl.Rectangle +---@param position rl.Vector2 +---@param tint rl.Color +function rl.DrawTextureRec(texture, source, position, tint) end + +--- Draw a part of a texture defined by a rectangle with 'pro' parameters +---@param texture rl.Texture +---@param source rl.Rectangle +---@param dest rl.Rectangle +---@param origin rl.Vector2 +---@param rotation number +---@param tint rl.Color +function rl.DrawTexturePro(texture, source, dest, origin, rotation, tint) end + +--- Draws a texture (or part of it) that stretches or shrinks nicely +---@param texture rl.Texture +---@param nPatchInfo rl.NPatchInfo +---@param dest rl.Rectangle +---@param origin rl.Vector2 +---@param rotation number +---@param tint rl.Color +function rl.DrawTextureNPatch(texture, nPatchInfo, dest, origin, rotation, tint) end + +--- Color/pixel related functions +--- Check if two colors are equal +---@param col1 rl.Color +---@param col2 rl.Color +---@return boolean +function rl.ColorIsEqual(col1, col2) end + +--- Get color with alpha applied, alpha goes from 0.0f to 1.0f +---@param color rl.Color +---@param alpha number +---@return rl.Color +function rl.Fade(color, alpha) end + +--- Get hexadecimal value for a Color (0xRRGGBBAA) +---@param color rl.Color +---@return integer +function rl.ColorToInt(color) end + +--- Get Color normalized as float [0..1] +---@param color rl.Color +---@return rl.Vector4 +function rl.ColorNormalize(color) end + +--- Get Color from normalized values [0..1] +---@param normalized rl.Vector4 +---@return rl.Color +function rl.ColorFromNormalized(normalized) end + +--- Get HSV values for a Color, hue [0..360], saturation/value [0..1] +---@param color rl.Color +---@return rl.Vector3 +function rl.ColorToHSV(color) end + +--- Get a Color from HSV values, hue [0..360], saturation/value [0..1] +---@param hue number +---@param saturation number +---@param value number +---@return rl.Color +function rl.ColorFromHSV(hue, saturation, value) end + +--- Get color multiplied with another color +---@param color rl.Color +---@param tint rl.Color +---@return rl.Color +function rl.ColorTint(color, tint) end + +--- Get color with brightness correction, brightness factor goes from -1.0f to 1.0f +---@param color rl.Color +---@param factor number +---@return rl.Color +function rl.ColorBrightness(color, factor) end + +--- Get color with contrast correction, contrast values between -1.0f and 1.0f +---@param color rl.Color +---@param contrast number +---@return rl.Color +function rl.ColorContrast(color, contrast) end + +--- Get color with alpha applied, alpha goes from 0.0f to 1.0f +---@param color rl.Color +---@param alpha number +---@return rl.Color +function rl.ColorAlpha(color, alpha) end + +--- Get src alpha-blended into dst color with tint +---@param dst rl.Color +---@param src rl.Color +---@param tint rl.Color +---@return rl.Color +function rl.ColorAlphaBlend(dst, src, tint) end + +--- Get color lerp interpolation between two colors, factor [0.0f..1.0f] +---@param color1 rl.Color +---@param color2 rl.Color +---@param factor number +---@return rl.Color +function rl.ColorLerp(color1, color2, factor) end + +--- Get Color structure from hexadecimal value +---@param hexValue integer +---@return rl.Color +function rl.GetColor(hexValue) end + +--- Get Color from a source pixel pointer of certain format +---@param srcPtr userdata +---@param format integer +---@return rl.Color +function rl.GetPixelColor(srcPtr, format) end + +--- Set color formatted into destination pixel pointer +---@param dstPtr userdata +---@param color rl.Color +---@param format integer +function rl.SetPixelColor(dstPtr, color, format) end + +--- Get pixel data size in bytes for certain format +---@param width integer +---@param height integer +---@param format integer +---@return integer +function rl.GetPixelDataSize(width, height, format) end + +--- Font Loading and Text Drawing Functions (Module: text) +--- Font loading/unloading functions +--- Get the default Font +---@return rl.Font +function rl.GetFontDefault() end + +--- Load font from file into GPU memory (VRAM) +---@param fileName string +---@return rl.Font +function rl.LoadFont(fileName) end + +--- Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height +---@param fileName string +---@param fontSize integer +---@param codepoints userdata +---@param codepointCount integer +---@return rl.Font +function rl.LoadFontEx(fileName, fontSize, codepoints, codepointCount) end + +--- Load font from Image (XNA style) +---@param image rl.Image +---@param key rl.Color +---@param firstChar integer +---@return rl.Font +function rl.LoadFontFromImage(image, key, firstChar) end + +--- Load font from memory buffer, fileType refers to extension: i.e. '.ttf' +---@param fileType string +---@param fileData userdata +---@param dataSize integer +---@param fontSize integer +---@param codepoints userdata +---@param codepointCount integer +---@return rl.Font +function rl.LoadFontFromMemory(fileType, fileData, dataSize, fontSize, codepoints, codepointCount) end + +--- Check if a font is valid (font data loaded, WARNING: GPU texture not checked) +---@param font rl.Font +---@return boolean +function rl.IsFontValid(font) end + +--- Load font data for further use +---@param fileData userdata +---@param dataSize integer +---@param fontSize integer +---@param codepoints userdata +---@param codepointCount integer +---@param type integer +---@param glyphCount userdata +---@return userdata +function rl.LoadFontData(fileData, dataSize, fontSize, codepoints, codepointCount, type, glyphCount) end + +--- Generate image font atlas using chars info +---@param glyphs userdata +---@param glyphRecs userdata +---@param glyphCount integer +---@param fontSize integer +---@param padding integer +---@param packMethod integer +---@return rl.Image +function rl.GenImageFontAtlas(glyphs, glyphRecs, glyphCount, fontSize, padding, packMethod) end + +--- Unload font chars info data (RAM) +---@param glyphs userdata +---@param glyphCount integer +function rl.UnloadFontData(glyphs, glyphCount) end + +--- Unload font from GPU memory (VRAM) +---@param font rl.Font +function rl.UnloadFont(font) end + +--- Export font as code file, returns true on success +---@param font rl.Font +---@param fileName string +---@return boolean +function rl.ExportFontAsCode(font, fileName) end + +--- Text drawing functions +--- Draw current FPS +---@param posX integer +---@param posY integer +function rl.DrawFPS(posX, posY) end + +--- Draw text (using default font) +---@param text string +---@param posX integer +---@param posY integer +---@param fontSize integer +---@param color rl.Color +function rl.DrawText(text, posX, posY, fontSize, color) end + +--- Draw text using font and additional parameters +---@param font rl.Font +---@param text string +---@param position rl.Vector2 +---@param fontSize number +---@param spacing number +---@param tint rl.Color +function rl.DrawTextEx(font, text, position, fontSize, spacing, tint) end + +--- Draw text using Font and pro parameters (rotation) +---@param font rl.Font +---@param text string +---@param position rl.Vector2 +---@param origin rl.Vector2 +---@param rotation number +---@param fontSize number +---@param spacing number +---@param tint rl.Color +function rl.DrawTextPro(font, text, position, origin, rotation, fontSize, spacing, tint) end + +--- Draw one character (codepoint) +---@param font rl.Font +---@param codepoint integer +---@param position rl.Vector2 +---@param fontSize number +---@param tint rl.Color +function rl.DrawTextCodepoint(font, codepoint, position, fontSize, tint) end + +--- Draw multiple character (codepoint) +---@param font rl.Font +---@param codepoints userdata +---@param codepointCount integer +---@param position rl.Vector2 +---@param fontSize number +---@param spacing number +---@param tint rl.Color +function rl.DrawTextCodepoints(font, codepoints, codepointCount, position, fontSize, spacing, tint) end + +--- Text font info functions +--- Set vertical line spacing when drawing with line-breaks +---@param spacing integer +function rl.SetTextLineSpacing(spacing) end + +--- Measure string width for default font +---@param text string +---@param fontSize integer +---@return integer +function rl.MeasureText(text, fontSize) end + +--- Measure string size for Font +---@param font rl.Font +---@param text string +---@param fontSize number +---@param spacing number +---@return rl.Vector2 +function rl.MeasureTextEx(font, text, fontSize, spacing) end + +--- Measure string size for an existing array of codepoints for Font +---@param font rl.Font +---@param codepoints userdata +---@param length integer +---@param fontSize number +---@param spacing number +---@return rl.Vector2 +function rl.MeasureTextCodepoints(font, codepoints, length, fontSize, spacing) end + +--- Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found +---@param font rl.Font +---@param codepoint integer +---@return integer +function rl.GetGlyphIndex(font, codepoint) end + +--- Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found +---@param font rl.Font +---@param codepoint integer +---@return rl.GlyphInfo +function rl.GetGlyphInfo(font, codepoint) end + +--- Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found +---@param font rl.Font +---@param codepoint integer +---@return rl.Rectangle +function rl.GetGlyphAtlasRec(font, codepoint) end + +--- Text codepoints management functions (unicode characters) +--- Load UTF-8 text encoded from codepoints array +---@param codepoints userdata +---@param length integer +---@return string +function rl.LoadUTF8(codepoints, length) end + +--- Unload UTF-8 text encoded from codepoints array +---@param text string +function rl.UnloadUTF8(text) end + +--- Load all codepoints from a UTF-8 text string, codepoints count returned by parameter +---@param text string +---@param count userdata +---@return userdata +function rl.LoadCodepoints(text, count) end + +--- Unload codepoints data from memory +---@param codepoints userdata +function rl.UnloadCodepoints(codepoints) end + +--- Get total number of codepoints in a UTF-8 encoded string +---@param text string +---@return integer +function rl.GetCodepointCount(text) end + +--- Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure +---@param text string +---@param codepointSize userdata +---@return integer +function rl.GetCodepoint(text, codepointSize) end + +--- Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure +---@param text string +---@param codepointSize userdata +---@return integer +function rl.GetCodepointNext(text, codepointSize) end + +--- Get previous codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure +---@param text string +---@param codepointSize userdata +---@return integer +function rl.GetCodepointPrevious(text, codepointSize) end + +--- Encode one codepoint into UTF-8 byte array (array length returned as parameter) +---@param codepoint integer +---@param utf8Size userdata +---@return string +function rl.CodepointToUTF8(codepoint, utf8Size) end + +--- Text strings management functions (no UTF-8 strings, only byte chars) +--- WARNING 1: Most of these functions use internal static buffers[], it's recommended to store returned data on user-side for re-use +--- WARNING 2: Some functions allocate memory internally for the returned strings, those strings must be freed by user using MemFree() +--- Load text as separate lines ('\n') +---@param text string +---@param count userdata +---@return userdata +function rl.LoadTextLines(text, count) end + +--- Unload text lines +---@param text userdata +---@param lineCount integer +function rl.UnloadTextLines(text, lineCount) end + +--- Copy one string to another, returns bytes copied +---@param dst string +---@param src string +---@return integer +function rl.TextCopy(dst, src) end + +--- Check if two text string are equal +---@param text1 string +---@param text2 string +---@return boolean +function rl.TextIsEqual(text1, text2) end + +--- Get text length, checks for '\0' ending +---@param text string +---@return integer +function rl.TextLength(text) end + +--- Text formatting with variables (sprintf() style) +---@param text string +---@param ... any +---@return string +function rl.TextFormat(text, ...) end + +--- Get a piece of a text string +---@param text string +---@param position integer +---@param length integer +---@return string +function rl.TextSubtext(text, position, length) end + +--- Remove text spaces, concat words +---@param text string +---@return string +function rl.TextRemoveSpaces(text) end + +--- Get text between two strings +---@param text string +---@param begin string +---@param end_ string +---@return string +function rl.GetTextBetween(text, begin, end_) end + +--- Replace text string with new string +---@param text string +---@param search string +---@param replacement string +---@return string +function rl.TextReplace(text, search, replacement) end + +--- Replace text string with new string, memory must be MemFree() +---@param text string +---@param search string +---@param replacement string +---@return string +function rl.TextReplaceAlloc(text, search, replacement) end + +--- Replace text between two specific strings +---@param text string +---@param begin string +---@param end_ string +---@param replacement string +---@return string +function rl.TextReplaceBetween(text, begin, end_, replacement) end + +--- Replace text between two specific strings, memory must be MemFree() +---@param text string +---@param begin string +---@param end_ string +---@param replacement string +---@return string +function rl.TextReplaceBetweenAlloc(text, begin, end_, replacement) end + +--- Insert text in a defined byte position +---@param text string +---@param insert string +---@param position integer +---@return string +function rl.TextInsert(text, insert, position) end + +--- Insert text in a defined byte position, memory must be MemFree() +---@param text string +---@param insert string +---@param position integer +---@return string +function rl.TextInsertAlloc(text, insert, position) end + +--- Join text strings with delimiter +---@param textList userdata +---@param count integer +---@param delimiter string +---@return string +function rl.TextJoin(textList, count, delimiter) end + +--- Split text into multiple strings, using MAX_TEXTSPLIT_COUNT static strings +---@param text string +---@param delimiter integer +---@param count userdata +---@return userdata +function rl.TextSplit(text, delimiter, count) end + +--- Append text at specific position and move cursor +---@param text string +---@param append string +---@param position userdata +function rl.TextAppend(text, append, position) end + +--- Find first text occurrence within a string, -1 if not found +---@param text string +---@param search string +---@return integer +function rl.TextFindIndex(text, search) end + +--- Get upper case version of provided string +---@param text string +---@return string +function rl.TextToUpper(text) end + +--- Get lower case version of provided string +---@param text string +---@return string +function rl.TextToLower(text) end + +--- Get Pascal case notation version of provided string +---@param text string +---@return string +function rl.TextToPascal(text) end + +--- Get Snake case notation version of provided string +---@param text string +---@return string +function rl.TextToSnake(text) end + +--- Get Camel case notation version of provided string +---@param text string +---@return string +function rl.TextToCamel(text) end + +--- Get integer value from text +---@param text string +---@return integer +function rl.TextToInteger(text) end + +--- Get float value from text +---@param text string +---@return number +function rl.TextToFloat(text) end + +--- Basic 3d Shapes Drawing Functions (Module: models) +--- Basic geometric 3D shapes drawing functions +--- Draw a line in 3D world space +---@param startPos rl.Vector3 +---@param endPos rl.Vector3 +---@param color rl.Color +function rl.DrawLine3D(startPos, endPos, color) end + +--- Draw a point in 3D space, actually a small line +---@param position rl.Vector3 +---@param color rl.Color +function rl.DrawPoint3D(position, color) end + +--- Draw a circle in 3D world space +---@param center rl.Vector3 +---@param radius number +---@param rotationAxis rl.Vector3 +---@param rotationAngle number +---@param color rl.Color +function rl.DrawCircle3D(center, radius, rotationAxis, rotationAngle, color) end + +--- Draw a color-filled triangle (vertex in counter-clockwise order!) +---@param v1 rl.Vector3 +---@param v2 rl.Vector3 +---@param v3 rl.Vector3 +---@param color rl.Color +function rl.DrawTriangle3D(v1, v2, v3, color) end + +--- Draw a triangle strip defined by points +---@param points userdata +---@param pointCount integer +---@param color rl.Color +function rl.DrawTriangleStrip3D(points, pointCount, color) end + +--- Draw cube +---@param position rl.Vector3 +---@param width number +---@param height number +---@param length number +---@param color rl.Color +function rl.DrawCube(position, width, height, length, color) end + +--- Draw cube (Vector version) +---@param position rl.Vector3 +---@param size rl.Vector3 +---@param color rl.Color +function rl.DrawCubeV(position, size, color) end + +--- Draw cube wires +---@param position rl.Vector3 +---@param width number +---@param height number +---@param length number +---@param color rl.Color +function rl.DrawCubeWires(position, width, height, length, color) end + +--- Draw cube wires (Vector version) +---@param position rl.Vector3 +---@param size rl.Vector3 +---@param color rl.Color +function rl.DrawCubeWiresV(position, size, color) end + +--- Draw sphere +---@param centerPos rl.Vector3 +---@param radius number +---@param color rl.Color +function rl.DrawSphere(centerPos, radius, color) end + +--- Draw sphere with extended parameters +---@param centerPos rl.Vector3 +---@param radius number +---@param rings integer +---@param slices integer +---@param color rl.Color +function rl.DrawSphereEx(centerPos, radius, rings, slices, color) end + +--- Draw sphere wires +---@param centerPos rl.Vector3 +---@param radius number +---@param rings integer +---@param slices integer +---@param color rl.Color +function rl.DrawSphereWires(centerPos, radius, rings, slices, color) end + +--- Draw a cylinder/cone +---@param position rl.Vector3 +---@param radiusTop number +---@param radiusBottom number +---@param height number +---@param slices integer +---@param color rl.Color +function rl.DrawCylinder(position, radiusTop, radiusBottom, height, slices, color) end + +--- Draw a cylinder with base at startPos and top at endPos +---@param startPos rl.Vector3 +---@param endPos rl.Vector3 +---@param startRadius number +---@param endRadius number +---@param sides integer +---@param color rl.Color +function rl.DrawCylinderEx(startPos, endPos, startRadius, endRadius, sides, color) end + +--- Draw a cylinder/cone wires +---@param position rl.Vector3 +---@param radiusTop number +---@param radiusBottom number +---@param height number +---@param slices integer +---@param color rl.Color +function rl.DrawCylinderWires(position, radiusTop, radiusBottom, height, slices, color) end + +--- Draw a cylinder wires with base at startPos and top at endPos +---@param startPos rl.Vector3 +---@param endPos rl.Vector3 +---@param startRadius number +---@param endRadius number +---@param sides integer +---@param color rl.Color +function rl.DrawCylinderWiresEx(startPos, endPos, startRadius, endRadius, sides, color) end + +--- Draw a capsule with the center of its sphere caps at startPos and endPos +---@param startPos rl.Vector3 +---@param endPos rl.Vector3 +---@param radius number +---@param slices integer +---@param rings integer +---@param color rl.Color +function rl.DrawCapsule(startPos, endPos, radius, slices, rings, color) end + +--- Draw capsule wireframe with the center of its sphere caps at startPos and endPos +---@param startPos rl.Vector3 +---@param endPos rl.Vector3 +---@param radius number +---@param slices integer +---@param rings integer +---@param color rl.Color +function rl.DrawCapsuleWires(startPos, endPos, radius, slices, rings, color) end + +--- Draw a plane XZ +---@param centerPos rl.Vector3 +---@param size rl.Vector2 +---@param color rl.Color +function rl.DrawPlane(centerPos, size, color) end + +--- Draw a ray line +---@param ray rl.Ray +---@param color rl.Color +function rl.DrawRay(ray, color) end + +--- Draw a grid (centered at (0, 0, 0)) +---@param slices integer +---@param spacing number +function rl.DrawGrid(slices, spacing) end + +--- Model 3d Loading and Drawing Functions (Module: models) +--- Model management functions +--- Load model from files (meshes and materials) +---@param fileName string +---@return rl.Model +function rl.LoadModel(fileName) end + +--- Load model from generated mesh (default material) +---@param mesh rl.Mesh +---@return rl.Model +function rl.LoadModelFromMesh(mesh) end + +--- Check if a model is valid (loaded in GPU, VAO/VBOs) +---@param model rl.Model +---@return boolean +function rl.IsModelValid(model) end + +--- Unload model (including meshes) from memory (RAM and/or VRAM) +---@param model rl.Model +function rl.UnloadModel(model) end + +--- Compute model bounding box limits (considers all meshes) +---@param model rl.Model +---@return rl.BoundingBox +function rl.GetModelBoundingBox(model) end + +--- Model drawing functions +--- Draw a model (with texture if set) +---@param model rl.Model +---@param position rl.Vector3 +---@param scale number +---@param tint rl.Color +function rl.DrawModel(model, position, scale, tint) end + +--- Draw a model with extended parameters +---@param model rl.Model +---@param position rl.Vector3 +---@param rotationAxis rl.Vector3 +---@param rotationAngle number +---@param scale rl.Vector3 +---@param tint rl.Color +function rl.DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint) end + +--- Draw a model wires (with texture if set) +---@param model rl.Model +---@param position rl.Vector3 +---@param scale number +---@param tint rl.Color +function rl.DrawModelWires(model, position, scale, tint) end + +--- Draw a model wires (with texture if set) with extended parameters +---@param model rl.Model +---@param position rl.Vector3 +---@param rotationAxis rl.Vector3 +---@param rotationAngle number +---@param scale rl.Vector3 +---@param tint rl.Color +function rl.DrawModelWiresEx(model, position, rotationAxis, rotationAngle, scale, tint) end + +--- Draw bounding box (wires) +---@param box rl.BoundingBox +---@param color rl.Color +function rl.DrawBoundingBox(box, color) end + +--- Draw a billboard texture +---@param camera rl.Camera3D +---@param texture rl.Texture +---@param position rl.Vector3 +---@param scale number +---@param tint rl.Color +function rl.DrawBillboard(camera, texture, position, scale, tint) end + +--- Draw a billboard texture defined by source +---@param camera rl.Camera3D +---@param texture rl.Texture +---@param source rl.Rectangle +---@param position rl.Vector3 +---@param size rl.Vector2 +---@param tint rl.Color +function rl.DrawBillboardRec(camera, texture, source, position, size, tint) end + +--- Draw a billboard texture defined by source and rotation +---@param camera rl.Camera3D +---@param texture rl.Texture +---@param source rl.Rectangle +---@param position rl.Vector3 +---@param up rl.Vector3 +---@param size rl.Vector2 +---@param origin rl.Vector2 +---@param rotation number +---@param tint rl.Color +function rl.DrawBillboardPro(camera, texture, source, position, up, size, origin, rotation, tint) end + +--- Mesh management functions +--- Upload mesh vertex data in GPU and provide VAO/VBO ids +---@param mesh userdata +---@param dynamic boolean +function rl.UploadMesh(mesh, dynamic) end + +--- Update mesh vertex data in GPU for a specific buffer index +---@param mesh rl.Mesh +---@param index integer +---@param data userdata +---@param dataSize integer +---@param offset integer +function rl.UpdateMeshBuffer(mesh, index, data, dataSize, offset) end + +--- Unload mesh data from CPU and GPU +---@param mesh rl.Mesh +function rl.UnloadMesh(mesh) end + +--- Draw a 3d mesh with material and transform +---@param mesh rl.Mesh +---@param material rl.Material +---@param transform rl.Matrix +function rl.DrawMesh(mesh, material, transform) end + +--- Draw multiple mesh instances with material and different transforms +---@param mesh rl.Mesh +---@param material rl.Material +---@param transforms userdata +---@param instances integer +function rl.DrawMeshInstanced(mesh, material, transforms, instances) end + +--- Compute mesh bounding box limits +---@param mesh rl.Mesh +---@return rl.BoundingBox +function rl.GetMeshBoundingBox(mesh) end + +--- Compute mesh tangents +---@param mesh userdata +function rl.GenMeshTangents(mesh) end + +--- Export mesh data to file, returns true on success +---@param mesh rl.Mesh +---@param fileName string +---@return boolean +function rl.ExportMesh(mesh, fileName) end + +--- Export mesh as code file (.h) defining multiple arrays of vertex attributes +---@param mesh rl.Mesh +---@param fileName string +---@return boolean +function rl.ExportMeshAsCode(mesh, fileName) end + +--- Mesh generation functions +--- Generate polygonal mesh +---@param sides integer +---@param radius number +---@return rl.Mesh +function rl.GenMeshPoly(sides, radius) end + +--- Generate plane mesh (with subdivisions) +---@param width number +---@param length number +---@param resX integer +---@param resZ integer +---@return rl.Mesh +function rl.GenMeshPlane(width, length, resX, resZ) end + +--- Generate cuboid mesh +---@param width number +---@param height number +---@param length number +---@return rl.Mesh +function rl.GenMeshCube(width, height, length) end + +--- Generate sphere mesh (standard sphere) +---@param radius number +---@param rings integer +---@param slices integer +---@return rl.Mesh +function rl.GenMeshSphere(radius, rings, slices) end + +--- Generate half-sphere mesh (no bottom cap) +---@param radius number +---@param rings integer +---@param slices integer +---@return rl.Mesh +function rl.GenMeshHemiSphere(radius, rings, slices) end + +--- Generate cylinder mesh +---@param radius number +---@param height number +---@param slices integer +---@return rl.Mesh +function rl.GenMeshCylinder(radius, height, slices) end + +--- Generate cone/pyramid mesh +---@param radius number +---@param height number +---@param slices integer +---@return rl.Mesh +function rl.GenMeshCone(radius, height, slices) end + +--- Generate torus mesh +---@param radius number +---@param size number +---@param radSeg integer +---@param sides integer +---@return rl.Mesh +function rl.GenMeshTorus(radius, size, radSeg, sides) end + +--- Generate trefoil knot mesh +---@param radius number +---@param size number +---@param radSeg integer +---@param sides integer +---@return rl.Mesh +function rl.GenMeshKnot(radius, size, radSeg, sides) end + +--- Generate heightmap mesh from image data +---@param heightmap rl.Image +---@param size rl.Vector3 +---@return rl.Mesh +function rl.GenMeshHeightmap(heightmap, size) end + +--- Generate cubes-based map mesh from image data +---@param cubicmap rl.Image +---@param cubeSize rl.Vector3 +---@return rl.Mesh +function rl.GenMeshCubicmap(cubicmap, cubeSize) end + +--- Material loading/unloading functions +--- Load materials from model file +---@param fileName string +---@param materialCount userdata +---@return userdata +function rl.LoadMaterials(fileName, materialCount) end + +--- Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) +---@return rl.Material +function rl.LoadMaterialDefault() end + +--- Check if a material is valid (shader assigned, map textures loaded in GPU) +---@param material rl.Material +---@return boolean +function rl.IsMaterialValid(material) end + +--- Unload material from GPU memory (VRAM) +---@param material rl.Material +function rl.UnloadMaterial(material) end + +--- Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...) +---@param material userdata +---@param mapType integer +---@param texture rl.Texture +function rl.SetMaterialTexture(material, mapType, texture) end + +--- Set material for a mesh +---@param model userdata +---@param meshId integer +---@param materialId integer +function rl.SetModelMeshMaterial(model, meshId, materialId) end + +--- Model animations loading/unloading functions +--- Load model animations from file +---@param fileName string +---@param animCount userdata +---@return userdata +function rl.LoadModelAnimations(fileName, animCount) end + +--- Update model animation pose (vertex buffers and bone matrices) +---@param model rl.Model +---@param anim rl.ModelAnimation +---@param frame number +function rl.UpdateModelAnimation(model, anim, frame) end + +--- Update model animation pose, blending two animations +---@param model rl.Model +---@param animA rl.ModelAnimation +---@param frameA number +---@param animB rl.ModelAnimation +---@param frameB number +---@param blend number +function rl.UpdateModelAnimationEx(model, animA, frameA, animB, frameB, blend) end + +--- Unload animation array data +---@param animations userdata +---@param animCount integer +function rl.UnloadModelAnimations(animations, animCount) end + +--- Check model animation skeleton match +---@param model rl.Model +---@param anim rl.ModelAnimation +---@return boolean +function rl.IsModelAnimationValid(model, anim) end + +--- Collision detection functions +--- Check collision between two spheres +---@param center1 rl.Vector3 +---@param radius1 number +---@param center2 rl.Vector3 +---@param radius2 number +---@return boolean +function rl.CheckCollisionSpheres(center1, radius1, center2, radius2) end + +--- Check collision between two bounding boxes +---@param box1 rl.BoundingBox +---@param box2 rl.BoundingBox +---@return boolean +function rl.CheckCollisionBoxes(box1, box2) end + +--- Check collision between box and sphere +---@param box rl.BoundingBox +---@param center rl.Vector3 +---@param radius number +---@return boolean +function rl.CheckCollisionBoxSphere(box, center, radius) end + +--- Get collision info between ray and sphere +---@param ray rl.Ray +---@param center rl.Vector3 +---@param radius number +---@return rl.RayCollision +function rl.GetRayCollisionSphere(ray, center, radius) end + +--- Get collision info between ray and box +---@param ray rl.Ray +---@param box rl.BoundingBox +---@return rl.RayCollision +function rl.GetRayCollisionBox(ray, box) end + +--- Get collision info between ray and mesh +---@param ray rl.Ray +---@param mesh rl.Mesh +---@param transform rl.Matrix +---@return rl.RayCollision +function rl.GetRayCollisionMesh(ray, mesh, transform) end + +--- Get collision info between ray and triangle +---@param ray rl.Ray +---@param p1 rl.Vector3 +---@param p2 rl.Vector3 +---@param p3 rl.Vector3 +---@return rl.RayCollision +function rl.GetRayCollisionTriangle(ray, p1, p2, p3) end + +--- Get collision info between ray and quad +---@param ray rl.Ray +---@param p1 rl.Vector3 +---@param p2 rl.Vector3 +---@param p3 rl.Vector3 +---@param p4 rl.Vector3 +---@return rl.RayCollision +function rl.GetRayCollisionQuad(ray, p1, p2, p3, p4) end + +--- Audio Loading and Playing Functions (Module: audio) +---@param bufferData userdata +---@param frames integer +function rl.AudioCallback(bufferData, frames) end + +--- Audio device management functions +--- Initialize audio device and context +function rl.InitAudioDevice() end + +--- Close the audio device and context +function rl.CloseAudioDevice() end + +--- Check if audio device has been initialized successfully +---@return boolean +function rl.IsAudioDeviceReady() end + +--- Set master volume (listener) +---@param volume number +function rl.SetMasterVolume(volume) end + +--- Get master volume (listener) +---@return number +function rl.GetMasterVolume() end + +--- Wave/Sound loading/unloading functions +--- Load wave data from file +---@param fileName string +---@return rl.Wave +function rl.LoadWave(fileName) end + +--- Load wave from memory buffer, fileType refers to extension: i.e. '.wav' +---@param fileType string +---@param fileData userdata +---@param dataSize integer +---@return rl.Wave +function rl.LoadWaveFromMemory(fileType, fileData, dataSize) end + +--- Checks if wave data is valid (data loaded and parameters) +---@param wave rl.Wave +---@return boolean +function rl.IsWaveValid(wave) end + +--- Load sound from file +---@param fileName string +---@return rl.Sound +function rl.LoadSound(fileName) end + +--- Load sound from wave data +---@param wave rl.Wave +---@return rl.Sound +function rl.LoadSoundFromWave(wave) end + +--- Create a new sound that shares the same sample data as the source sound, does not own the sound data +---@param source rl.Sound +---@return rl.Sound +function rl.LoadSoundAlias(source) end + +--- Checks if a sound is valid (data loaded and buffers initialized) +---@param sound rl.Sound +---@return boolean +function rl.IsSoundValid(sound) end + +--- Update sound buffer with new data (default data format: 32 bit float, stereo) +---@param sound rl.Sound +---@param data userdata +---@param sampleCount integer +function rl.UpdateSound(sound, data, sampleCount) end + +--- Unload wave data +---@param wave rl.Wave +function rl.UnloadWave(wave) end + +--- Unload sound +---@param sound rl.Sound +function rl.UnloadSound(sound) end + +--- Unload a sound alias (does not deallocate sample data) +---@param alias rl.Sound +function rl.UnloadSoundAlias(alias) end + +--- Export wave data to file, returns true on success +---@param wave rl.Wave +---@param fileName string +---@return boolean +function rl.ExportWave(wave, fileName) end + +--- Export wave sample data to code (.h), returns true on success +---@param wave rl.Wave +---@param fileName string +---@return boolean +function rl.ExportWaveAsCode(wave, fileName) end + +--- Wave/Sound management functions +--- Play a sound +---@param sound rl.Sound +function rl.PlaySound(sound) end + +--- Stop playing a sound +---@param sound rl.Sound +function rl.StopSound(sound) end + +--- Pause a sound +---@param sound rl.Sound +function rl.PauseSound(sound) end + +--- Resume a paused sound +---@param sound rl.Sound +function rl.ResumeSound(sound) end + +--- Check if a sound is currently playing +---@param sound rl.Sound +---@return boolean +function rl.IsSoundPlaying(sound) end + +--- Set volume for a sound (1.0 is max level) +---@param sound rl.Sound +---@param volume number +function rl.SetSoundVolume(sound, volume) end + +--- Set pitch for a sound (1.0 is base level) +---@param sound rl.Sound +---@param pitch number +function rl.SetSoundPitch(sound, pitch) end + +--- Set pan for a sound (-1.0 left, 0.0 center, 1.0 right) +---@param sound rl.Sound +---@param pan number +function rl.SetSoundPan(sound, pan) end + +--- Copy a wave to a new wave +---@param wave rl.Wave +---@return rl.Wave +function rl.WaveCopy(wave) end + +--- Crop a wave to defined frames range +---@param wave userdata +---@param initFrame integer +---@param finalFrame integer +function rl.WaveCrop(wave, initFrame, finalFrame) end + +--- Convert wave data to desired format +---@param wave userdata +---@param sampleRate integer +---@param sampleSize integer +---@param channels integer +function rl.WaveFormat(wave, sampleRate, sampleSize, channels) end + +--- Load samples data from wave as a 32bit float data array +---@param wave rl.Wave +---@return userdata +function rl.LoadWaveSamples(wave) end + +--- Unload samples data loaded with LoadWaveSamples() +---@param samples userdata +function rl.UnloadWaveSamples(samples) end + +--- Music management functions +--- Load music stream from file +---@param fileName string +---@return rl.Music +function rl.LoadMusicStream(fileName) end + +--- Load music stream from data +---@param fileType string +---@param data userdata +---@param dataSize integer +---@return rl.Music +function rl.LoadMusicStreamFromMemory(fileType, data, dataSize) end + +--- Checks if a music stream is valid (context and buffers initialized) +---@param music rl.Music +---@return boolean +function rl.IsMusicValid(music) end + +--- Unload music stream +---@param music rl.Music +function rl.UnloadMusicStream(music) end + +--- Start music playing +---@param music rl.Music +function rl.PlayMusicStream(music) end + +--- Check if music is playing +---@param music rl.Music +---@return boolean +function rl.IsMusicStreamPlaying(music) end + +--- Updates buffers for music streaming +---@param music rl.Music +function rl.UpdateMusicStream(music) end + +--- Stop music playing +---@param music rl.Music +function rl.StopMusicStream(music) end + +--- Pause music playing +---@param music rl.Music +function rl.PauseMusicStream(music) end + +--- Resume playing paused music +---@param music rl.Music +function rl.ResumeMusicStream(music) end + +--- Seek music to a position (in seconds) +---@param music rl.Music +---@param position number +function rl.SeekMusicStream(music, position) end + +--- Set volume for music (1.0 is max level) +---@param music rl.Music +---@param volume number +function rl.SetMusicVolume(music, volume) end + +--- Set pitch for a music (1.0 is base level) +---@param music rl.Music +---@param pitch number +function rl.SetMusicPitch(music, pitch) end + +--- Set pan for a music (-1.0 left, 0.0 center, 1.0 right) +---@param music rl.Music +---@param pan number +function rl.SetMusicPan(music, pan) end + +--- Get music time length (in seconds) +---@param music rl.Music +---@return number +function rl.GetMusicTimeLength(music) end + +--- Get current music time played (in seconds) +---@param music rl.Music +---@return number +function rl.GetMusicTimePlayed(music) end + +--- AudioStream management functions +--- Load audio stream (to stream raw audio pcm data) +---@param sampleRate integer +---@param sampleSize integer +---@param channels integer +---@return rl.AudioStream +function rl.LoadAudioStream(sampleRate, sampleSize, channels) end + +--- Checks if an audio stream is valid (buffers initialized) +---@param stream rl.AudioStream +---@return boolean +function rl.IsAudioStreamValid(stream) end + +--- Unload audio stream and free memory +---@param stream rl.AudioStream +function rl.UnloadAudioStream(stream) end + +--- Update audio stream buffers with data +---@param stream rl.AudioStream +---@param data userdata +---@param frameCount integer +function rl.UpdateAudioStream(stream, data, frameCount) end + +--- Check if any audio stream buffers requires refill +---@param stream rl.AudioStream +---@return boolean +function rl.IsAudioStreamProcessed(stream) end + +--- Play audio stream +---@param stream rl.AudioStream +function rl.PlayAudioStream(stream) end + +--- Pause audio stream +---@param stream rl.AudioStream +function rl.PauseAudioStream(stream) end + +--- Resume audio stream +---@param stream rl.AudioStream +function rl.ResumeAudioStream(stream) end + +--- Check if audio stream is playing +---@param stream rl.AudioStream +---@return boolean +function rl.IsAudioStreamPlaying(stream) end + +--- Stop audio stream +---@param stream rl.AudioStream +function rl.StopAudioStream(stream) end + +--- Set volume for audio stream (1.0 is max level) +---@param stream rl.AudioStream +---@param volume number +function rl.SetAudioStreamVolume(stream, volume) end + +--- Set pitch for audio stream (1.0 is base level) +---@param stream rl.AudioStream +---@param pitch number +function rl.SetAudioStreamPitch(stream, pitch) end + +--- Set pan for audio stream (-1.0 to 1.0 range, 0.0 is centered) +---@param stream rl.AudioStream +---@param pan number +function rl.SetAudioStreamPan(stream, pan) end + +--- Default size for new audio streams +---@param size integer +function rl.SetAudioStreamBufferSizeDefault(size) end + +--- Audio thread callback to request new data +---@param stream rl.AudioStream +---@param callback rl.AudioCallback +function rl.SetAudioStreamCallback(stream, callback) end + +--- Attach audio stream processor to stream, receives frames x 2 samples as 'float' (stereo) +---@param stream rl.AudioStream +---@param processor rl.AudioCallback +function rl.AttachAudioStreamProcessor(stream, processor) end + +--- Detach audio stream processor from stream +---@param stream rl.AudioStream +---@param processor rl.AudioCallback +function rl.DetachAudioStreamProcessor(stream, processor) end + +--- Attach audio stream processor to the entire audio pipeline, receives frames x 2 samples as 'float' (stereo) +---@param processor rl.AudioCallback +function rl.AttachAudioMixedProcessor(processor) end + +--- Detach audio stream processor from the entire audio pipeline +---@param processor rl.AudioCallback +function rl.DetachAudioMixedProcessor(processor) end diff --git a/src/raylib-lua.h b/src/raylib-lua.h index 0bb5859..939a836 100644 --- a/src/raylib-lua.h +++ b/src/raylib-lua.h @@ -1,50 +1,37 @@ /********************************************************************************************** * -* raylib-lua v2.0 - raylib Lua bindings for raylib v2.0 +* raylib-lua v6.0 - raylib Lua bindings for raylib v6.0 * -* NOTES: +* AUTO-GENERATED by tools/rLuaParser/rluaparser.lua * -* The following types are treated as objects with named fields, same as in C. -* Color, Vector2, Vector3, Rectangle, Ray, Camera, Camera2D -* -* Lua defines utility functions to create those objects. +* Parsed: 606 functions, 35 structs, 21 enums, 41 defines, 8 aliases * -* USAGE EXAMPLE: -* local cl = Color(255,255,255,255) -* local rec = Rectangle(10, 10, 100, 100) -* local ray = Ray(Vector3(20, 20, 20), Vector3(50, 50, 50)) -* local x2 = rec.x + rec.width +* NOTES: * -* The following types are immutable, and you can only read their non-pointer arguments. -* Image, Texture2D, RenderTexture2D, Font +* The following types are treated as Lua tables with named fields, same as in C: +* Matrix, Vector2, Vector3, Vector4, Color, Rectangle, Ray, Camera, BoundingBox * -* All other object types are opaque, that is, you cannot access or change their fields directly. +* The following types are opaque userdata with field access and automatic memory management (__gc): +* Image, Texture2D, RenderTexture2D, Mesh, Model, Shader, Font, Sound, Music, Wave * * Remember that ALL raylib types have REFERENCE SEMANTICS in Lua. -* There is currently no way to create a copy of an opaque object. -* -* Some raylib functions take a pointer to an array, and the size of that array. -* The equivalent Lua functions take only an array table of the specified type UNLESS -* it's a pointer to a large char array (e.g. for images), then it takes (and potentially returns) -* a Lua string (without the size argument, as Lua strings are sized by default). -* -* Some raylib functions take pointers to objects to modify (e.g. ImageToPOT(), etc.) -* In Lua, these functions take values and return a new changed value, instead. +* Tables (value types) are passed to C by copying fields, but multiple references +* on the Lua side point to the same table object. * -* So, in C: ImageToPOT(&image, BLACK); -* In Lua becomes: image = ImageToPOT(image, BLACK) -* -* Remember that Lua functions can return multiple values. -* This is to preserve value semantics of raylib objects. +* Some raylib functions take pointers to objects to modify (e.g. UpdateCamera(), etc.) +* For table-based types like Camera, the binding automatically writes modified fields +* back to the original Lua table. For resource types like Image, changes are made +* directly to the memory block. * * CONTRIBUTORS: * Ghassan Al-Mashareqa (ghassan@ghassan.pl): Original binding creation (for raylib 1.3) * Ramon Santamaria (@raysan5): Review, update and maintenance -* +* yilisharcs: Modernization and automatic generator (for raylib 6.0) * * LICENSE: zlib/libpng * * Copyright (c) 2015-2017 Ghassan Al-Mashareqa and Ramon Santamaria (@raysan5) +* Copyright (c) 2026 yilisharcs * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -65,9 +52,10 @@ #pragma once -#include "raylib.h" +#include +#include +#include -#define RLUA_STATIC #ifdef RLUA_STATIC #define RLUADEF static // Functions just visible to module including this file #else @@ -78,5705 +66,9049 @@ #endif #endif -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -// ... +RLUADEF lua_State *rlua_open(void); +RLUADEF void rlua_close(lua_State *L); -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- -RLUADEF void rLuaInitDevice(void); // Initialize Lua system -RLUADEF void rLuaExecuteCode(const char *code); // Execute raylib Lua code -RLUADEF void rLuaExecuteFile(const char *filename); // Execute raylib Lua script -RLUADEF void rLuaCloseDevice(void); // De-initialize Lua system +#ifdef RLUA_IMPLEMENTATION +#include "raylib.h" +#include +#include +#include +#include // Required for: va_list - Only used by TraceLogCallback +#include + +// --- Global State --- +static lua_State *RLUA_State = NULL; +static int RLUA_LogRef = LUA_REFNIL; +static pthread_mutex_t RLUA_LogMutex = PTHREAD_MUTEX_INITIALIZER; + +// --- Marshalling Helpers --- + +typedef struct { + void *data; + int count; + const char *tname; + bool owned; +} RLUA_Handle; + +static void* RLUA_CHECK_Resource(lua_State *L, int index, const char *tname) { + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, index, tname); + return h->data; +} + +static void RLUA_PUSH_Resource(lua_State *L, void *data, size_t size, const char *tname) { + RLUA_Handle *h = (RLUA_Handle *)lua_newuserdata(L, sizeof(RLUA_Handle)); + h->data = RL_MALLOC(size); + memcpy(h->data, data, size); + h->count = 1; + h->tname = tname; + h->owned = true; + luaL_setmetatable(L, tname); +} + +static void RLUA_PUSH_View(lua_State *L, const void *data, int count, const char *tname, bool owned) { + RLUA_Handle *h = (RLUA_Handle *)lua_newuserdata(L, sizeof(RLUA_Handle)); + h->data = (void *)data; + h->count = count; + h->tname = tname; + h->owned = owned; + luaL_setmetatable(L, tname); +} + +// --- Callback Trampolines --- +static void RLUA_TraceLogTrampoline(int logLevel, const char *text, va_list args) { + if (!RLUA_State || RLUA_LogRef == LUA_REFNIL) return; + char buffer[1024]; + vsnprintf(buffer, sizeof(buffer), text, args); + pthread_mutex_lock(&RLUA_LogMutex); + lua_State *L = RLUA_State; + lua_rawgeti(L, LUA_REGISTRYINDEX, RLUA_LogRef); + lua_pushinteger(L, logLevel); + lua_pushstring(L, buffer); + if (lua_pcall(L, 2, 0, 0) != LUA_OK) { + TraceLog(LOG_ERROR, "LUA: TraceLogCallback: %s", lua_tostring(L, -1)); + lua_pop(L, 1); + } + pthread_mutex_unlock(&RLUA_LogMutex); +} -/*********************************************************************************** -* -* RLUA IMPLEMENTATION -* -************************************************************************************/ +// --- Type Aliases --- -#if defined(RLUA_IMPLEMENTATION) +#define RLUA_CHECK_Camera RLUA_CHECK_Camera3D +#define RLUA_PUSH_Camera RLUA_PUSH_Camera3D +#define RLUA_WRITEBACK_Camera RLUA_WRITEBACK_Camera3D +#define RLUA_CHECK_ModelAnimPose(L, idx) (ModelAnimPose)RLUA_CHECK_Resource(L, idx, "Transform") +#define RLUA_PUSH_ModelAnimPose(L, val) RLUA_PUSH_View(L, val, 1, "Transform", false) +#define RLUA_CHECK_Quaternion RLUA_CHECK_Vector4 +#define RLUA_PUSH_Quaternion RLUA_PUSH_Vector4 +#define RLUA_CHECK_RenderTexture2D(L, idx) (*(RenderTexture2D*)RLUA_CHECK_Resource(L, idx, "RenderTexture")) +#define RLUA_PUSH_RenderTexture2D(L, val) RLUA_PUSH_Resource(L, &val, sizeof(RenderTexture2D), "RenderTexture") +#define RLUA_CHECK_Texture2D(L, idx) (*(Texture2D*)RLUA_CHECK_Resource(L, idx, "Texture")) +#define RLUA_PUSH_Texture2D(L, val) RLUA_PUSH_Resource(L, &val, sizeof(Texture2D), "Texture") +#define RLUA_CHECK_TextureCubemap(L, idx) (*(TextureCubemap*)RLUA_CHECK_Resource(L, idx, "Texture")) +#define RLUA_PUSH_TextureCubemap(L, val) RLUA_PUSH_Resource(L, &val, sizeof(TextureCubemap), "Texture") -#include "raylib.h" -#include "raymath.h" -#define PHYSAC_IMPLEMENTATION -#include "physac.h" +// --- Generated Marshallers --- -#include -#include +// Vector2, 2 components +static Vector2 RLUA_CHECK_Vector2(lua_State *L, int index) +{ + Vector2 result = { 0 }; + if (lua_istable(L, index)) { + lua_getfield(L, index, "x"); + result.x = (float)luaL_checknumber(L, -1); // Vector x component + lua_pop(L, 1); + lua_getfield(L, index, "y"); + result.y = (float)luaL_checknumber(L, -1); // Vector y component + lua_pop(L, 1); + } + return result; +} +static void RLUA_PUSH_Vector2(lua_State *L, Vector2 result) +{ + lua_createtable(L, 0, 2); + lua_pushnumber(L, result.x); // Vector x component + lua_setfield(L, -2, "x"); + lua_pushnumber(L, result.y); // Vector y component + lua_setfield(L, -2, "y"); +} +static void RLUA_WRITEBACK_Vector2(lua_State *L, int index, Vector2 val) +{ + if (lua_istable(L, index)) { + lua_pushnumber(L, val.x); // Vector x component + lua_setfield(L, index, "x"); + lua_pushnumber(L, val.y); // Vector y component + lua_setfield(L, index, "y"); + } +} -#include -#include -#include -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -#define LuaPush_int(L, value) lua_pushinteger(L, value) -#define LuaPush_float(L, value) lua_pushnumber(L, value); -#define LuaPush_bool(L, value) lua_pushboolean(L, value) -#define LuaPush_string(L, value) lua_pushstring(L, value) - -#define LuaPush_Image(L, img) LuaPushOpaqueTypeWithMetatable(L, img, Image) -#define LuaPush_Texture2D(L, tex) LuaPushOpaqueTypeWithMetatable(L, tex, Texture2D) -#define LuaPush_RenderTexture2D(L, tex) LuaPushOpaqueTypeWithMetatable(L, tex, RenderTexture2D) -#define LuaPush_Font(L, sf) LuaPushOpaqueTypeWithMetatable(L, sf, Font) -#define LuaPush_Mesh(L, vd) LuaPushOpaqueType(L, vd) -#define LuaPush_Shader(L, s) LuaPushOpaqueType(L, s) -#define LuaPush_Sound(L, snd) LuaPushOpaqueType(L, snd) -#define LuaPush_Wave(L, wav) LuaPushOpaqueType(L, wav) -#define LuaPush_Music(L, mus) LuaPushOpaqueType(L, mus) -#define LuaPush_AudioStream(L, aud) LuaPushOpaqueType(L, aud) -#define LuaPush_PhysicsBody(L, body) LuaPushOpaqueType(L, body) - -#define LuaGetArgument_ptr (void *)luaL_checkinteger -#define LuaGetArgument_int (int)luaL_checkinteger -#define LuaGetArgument_unsigned (unsigned)luaL_checkinteger -#define LuaGetArgument_char (char)luaL_checkinteger -#define LuaGetArgument_float (float)luaL_checknumber -#define LuaGetArgument_double luaL_checknumber -#define LuaGetArgument_string luaL_checkstring - -#define LuaGetArgument_Image(L, img) *(Image *)LuaGetArgumentOpaqueTypeWithMetatable(L, img, "Image") -#define LuaGetArgument_Texture2D(L, tex) *(Texture2D *)LuaGetArgumentOpaqueTypeWithMetatable(L, tex, "Texture2D") -#define LuaGetArgument_RenderTexture2D(L, rtex) *(RenderTexture2D *)LuaGetArgumentOpaqueTypeWithMetatable(L, rtex, "RenderTexture2D") -#define LuaGetArgument_Font(L, sf) *(Font *)LuaGetArgumentOpaqueTypeWithMetatable(L, sf, "Font") -#define LuaGetArgument_Mesh(L, vd) *(Mesh *)LuaGetArgumentOpaqueType(L, vd) -#define LuaGetArgument_Shader(L, s) *(Shader *)LuaGetArgumentOpaqueType(L, s) -#define LuaGetArgument_Sound(L, snd) *(Sound *)LuaGetArgumentOpaqueType(L, snd) -#define LuaGetArgument_Wave(L, wav) *(Wave *)LuaGetArgumentOpaqueType(L, wav) -#define LuaGetArgument_Music(L, mus) *(Music *)LuaGetArgumentOpaqueType(L, mus) -#define LuaGetArgument_AudioStream(L, aud) *(AudioStream *)LuaGetArgumentOpaqueType(L, aud) -#define LuaGetArgument_PhysicsBody(L, body) *(PhysicsBody *)LuaGetArgumentOpaqueType(L, body) - -#define LuaPushOpaqueType(L, str) LuaPushOpaque(L, &str, sizeof(str)) -#define LuaPushOpaqueTypeWithMetatable(L, str, meta) LuaPushOpaqueWithMetatable(L, &str, sizeof(str), #meta) - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -static lua_State* mainLuaState = 0; -static lua_State* L = 0; - -//---------------------------------------------------------------------------------- -// Module specific Functions Declaration -//---------------------------------------------------------------------------------- -static void LuaPush_Color(lua_State* L, Color color); -static void LuaPush_Vector2(lua_State* L, Vector2 vec); -static void LuaPush_Vector3(lua_State* L, Vector3 vec); -static void LuaPush_Vector4(lua_State* L, Vector4 vec); -static void LuaPush_Quaternion(lua_State* L, Quaternion vec); -static void LuaPush_Matrix(lua_State* L, Matrix *matrix); -static void LuaPush_Rectangle(lua_State* L, Rectangle rect); -static void LuaPush_Camera(lua_State* L, Camera cam); -static void LuaPush_Camera2D(lua_State* L, Camera2D cam); -static void LuaPush_Model(lua_State* L, Model mdl); -static void LuaPush_Ray(lua_State* L, Ray ray); -static void LuaPush_RayHitInfo(lua_State* L, RayHitInfo hit); - -static Color LuaGetArgument_Color(lua_State* L, int index); -static Vector2 LuaGetArgument_Vector2(lua_State* L, int index); -static Vector3 LuaGetArgument_Vector3(lua_State* L, int index); -static Vector4 LuaGetArgument_Vector4(lua_State* L, int index); -static Quaternion LuaGetArgument_Quaternion(lua_State* L, int index); -static Matrix LuaGetArgument_Matrix(lua_State* L, int index); -static Rectangle LuaGetArgument_Rectangle(lua_State* L, int index); -static Camera LuaGetArgument_Camera(lua_State* L, int index); -static Camera2D LuaGetArgument_Camera2D(lua_State* L, int index); -static Model LuaGetArgument_Model(lua_State* L, int index); -static Ray LuaGetArgument_Ray(lua_State* L, int index); - -//---------------------------------------------------------------------------------- -// rlua Helper Functions -//---------------------------------------------------------------------------------- -static void LuaStartEnum(void) +// Vector3, 3 components +static Vector3 RLUA_CHECK_Vector3(lua_State *L, int index) +{ + Vector3 result = { 0 }; + if (lua_istable(L, index)) { + lua_getfield(L, index, "x"); + result.x = (float)luaL_checknumber(L, -1); // Vector x component + lua_pop(L, 1); + lua_getfield(L, index, "y"); + result.y = (float)luaL_checknumber(L, -1); // Vector y component + lua_pop(L, 1); + lua_getfield(L, index, "z"); + result.z = (float)luaL_checknumber(L, -1); // Vector z component + lua_pop(L, 1); + } + return result; +} +static void RLUA_PUSH_Vector3(lua_State *L, Vector3 result) +{ + lua_createtable(L, 0, 3); + lua_pushnumber(L, result.x); // Vector x component + lua_setfield(L, -2, "x"); + lua_pushnumber(L, result.y); // Vector y component + lua_setfield(L, -2, "y"); + lua_pushnumber(L, result.z); // Vector z component + lua_setfield(L, -2, "z"); +} + + +// Vector4, 4 components +static Vector4 RLUA_CHECK_Vector4(lua_State *L, int index) +{ + Vector4 result = { 0 }; + if (lua_istable(L, index)) { + lua_getfield(L, index, "x"); + result.x = (float)luaL_checknumber(L, -1); // Vector x component + lua_pop(L, 1); + lua_getfield(L, index, "y"); + result.y = (float)luaL_checknumber(L, -1); // Vector y component + lua_pop(L, 1); + lua_getfield(L, index, "z"); + result.z = (float)luaL_checknumber(L, -1); // Vector z component + lua_pop(L, 1); + lua_getfield(L, index, "w"); + result.w = (float)luaL_checknumber(L, -1); // Vector w component + lua_pop(L, 1); + } + return result; +} +static void RLUA_PUSH_Vector4(lua_State *L, Vector4 result) +{ + lua_createtable(L, 0, 4); + lua_pushnumber(L, result.x); // Vector x component + lua_setfield(L, -2, "x"); + lua_pushnumber(L, result.y); // Vector y component + lua_setfield(L, -2, "y"); + lua_pushnumber(L, result.z); // Vector z component + lua_setfield(L, -2, "z"); + lua_pushnumber(L, result.w); // Vector w component + lua_setfield(L, -2, "w"); +} + + +// Matrix, 4x4 components, column major, OpenGL style, right-handed +static Matrix RLUA_CHECK_Matrix(lua_State *L, int index) +{ + Matrix result = { 0 }; + if (lua_istable(L, index)) { + lua_getfield(L, index, "m0"); + result.m0 = (float)luaL_checknumber(L, -1); // Matrix first row (4 components) + lua_pop(L, 1); + lua_getfield(L, index, "m1"); + result.m1 = (float)luaL_checknumber(L, -1); // Matrix second row (4 components) + lua_pop(L, 1); + lua_getfield(L, index, "m2"); + result.m2 = (float)luaL_checknumber(L, -1); // Matrix third row (4 components) + lua_pop(L, 1); + lua_getfield(L, index, "m3"); + result.m3 = (float)luaL_checknumber(L, -1); // Matrix fourth row (4 components) + lua_pop(L, 1); + lua_getfield(L, index, "m4"); + result.m4 = (float)luaL_checknumber(L, -1); // Matrix first row (4 components) + lua_pop(L, 1); + lua_getfield(L, index, "m5"); + result.m5 = (float)luaL_checknumber(L, -1); // Matrix second row (4 components) + lua_pop(L, 1); + lua_getfield(L, index, "m6"); + result.m6 = (float)luaL_checknumber(L, -1); // Matrix third row (4 components) + lua_pop(L, 1); + lua_getfield(L, index, "m7"); + result.m7 = (float)luaL_checknumber(L, -1); // Matrix fourth row (4 components) + lua_pop(L, 1); + lua_getfield(L, index, "m8"); + result.m8 = (float)luaL_checknumber(L, -1); // Matrix first row (4 components) + lua_pop(L, 1); + lua_getfield(L, index, "m9"); + result.m9 = (float)luaL_checknumber(L, -1); // Matrix second row (4 components) + lua_pop(L, 1); + lua_getfield(L, index, "m10"); + result.m10 = (float)luaL_checknumber(L, -1); // Matrix third row (4 components) + lua_pop(L, 1); + lua_getfield(L, index, "m11"); + result.m11 = (float)luaL_checknumber(L, -1); // Matrix fourth row (4 components) + lua_pop(L, 1); + lua_getfield(L, index, "m12"); + result.m12 = (float)luaL_checknumber(L, -1); // Matrix first row (4 components) + lua_pop(L, 1); + lua_getfield(L, index, "m13"); + result.m13 = (float)luaL_checknumber(L, -1); // Matrix second row (4 components) + lua_pop(L, 1); + lua_getfield(L, index, "m14"); + result.m14 = (float)luaL_checknumber(L, -1); // Matrix third row (4 components) + lua_pop(L, 1); + lua_getfield(L, index, "m15"); + result.m15 = (float)luaL_checknumber(L, -1); // Matrix fourth row (4 components) + lua_pop(L, 1); + } + return result; +} +static void RLUA_PUSH_Matrix(lua_State *L, Matrix result) +{ + lua_createtable(L, 0, 16); + lua_pushnumber(L, result.m0); // Matrix first row (4 components) + lua_setfield(L, -2, "m0"); + lua_pushnumber(L, result.m1); // Matrix second row (4 components) + lua_setfield(L, -2, "m1"); + lua_pushnumber(L, result.m2); // Matrix third row (4 components) + lua_setfield(L, -2, "m2"); + lua_pushnumber(L, result.m3); // Matrix fourth row (4 components) + lua_setfield(L, -2, "m3"); + lua_pushnumber(L, result.m4); // Matrix first row (4 components) + lua_setfield(L, -2, "m4"); + lua_pushnumber(L, result.m5); // Matrix second row (4 components) + lua_setfield(L, -2, "m5"); + lua_pushnumber(L, result.m6); // Matrix third row (4 components) + lua_setfield(L, -2, "m6"); + lua_pushnumber(L, result.m7); // Matrix fourth row (4 components) + lua_setfield(L, -2, "m7"); + lua_pushnumber(L, result.m8); // Matrix first row (4 components) + lua_setfield(L, -2, "m8"); + lua_pushnumber(L, result.m9); // Matrix second row (4 components) + lua_setfield(L, -2, "m9"); + lua_pushnumber(L, result.m10); // Matrix third row (4 components) + lua_setfield(L, -2, "m10"); + lua_pushnumber(L, result.m11); // Matrix fourth row (4 components) + lua_setfield(L, -2, "m11"); + lua_pushnumber(L, result.m12); // Matrix first row (4 components) + lua_setfield(L, -2, "m12"); + lua_pushnumber(L, result.m13); // Matrix second row (4 components) + lua_setfield(L, -2, "m13"); + lua_pushnumber(L, result.m14); // Matrix third row (4 components) + lua_setfield(L, -2, "m14"); + lua_pushnumber(L, result.m15); // Matrix fourth row (4 components) + lua_setfield(L, -2, "m15"); +} + + +// Color, 4 components, R8G8B8A8 (32bit) +static Color RLUA_CHECK_Color(lua_State *L, int index) +{ + Color result = { 0 }; + if (lua_istable(L, index)) { + lua_getfield(L, index, "r"); + result.r = (unsigned char)luaL_checkinteger(L, -1); // Color red value + lua_pop(L, 1); + lua_getfield(L, index, "g"); + result.g = (unsigned char)luaL_checkinteger(L, -1); // Color green value + lua_pop(L, 1); + lua_getfield(L, index, "b"); + result.b = (unsigned char)luaL_checkinteger(L, -1); // Color blue value + lua_pop(L, 1); + lua_getfield(L, index, "a"); + result.a = (unsigned char)luaL_checkinteger(L, -1); // Color alpha value + lua_pop(L, 1); + } + return result; +} +static void RLUA_PUSH_Color(lua_State *L, Color result) +{ + lua_createtable(L, 0, 4); + lua_pushinteger(L, result.r); // Color red value + lua_setfield(L, -2, "r"); + lua_pushinteger(L, result.g); // Color green value + lua_setfield(L, -2, "g"); + lua_pushinteger(L, result.b); // Color blue value + lua_setfield(L, -2, "b"); + lua_pushinteger(L, result.a); // Color alpha value + lua_setfield(L, -2, "a"); +} + + +// Rectangle, 4 components +static Rectangle RLUA_CHECK_Rectangle(lua_State *L, int index) +{ + Rectangle result = { 0 }; + if (lua_istable(L, index)) { + lua_getfield(L, index, "x"); + result.x = (float)luaL_checknumber(L, -1); // Rectangle top-left corner position x + lua_pop(L, 1); + lua_getfield(L, index, "y"); + result.y = (float)luaL_checknumber(L, -1); // Rectangle top-left corner position y + lua_pop(L, 1); + lua_getfield(L, index, "width"); + result.width = (float)luaL_checknumber(L, -1); // Rectangle width + lua_pop(L, 1); + lua_getfield(L, index, "height"); + result.height = (float)luaL_checknumber(L, -1); // Rectangle height + lua_pop(L, 1); + } + return result; +} +static void RLUA_PUSH_Rectangle(lua_State *L, Rectangle result) +{ + lua_createtable(L, 0, 4); + lua_pushnumber(L, result.x); // Rectangle top-left corner position x + lua_setfield(L, -2, "x"); + lua_pushnumber(L, result.y); // Rectangle top-left corner position y + lua_setfield(L, -2, "y"); + lua_pushnumber(L, result.width); // Rectangle width + lua_setfield(L, -2, "width"); + lua_pushnumber(L, result.height); // Rectangle height + lua_setfield(L, -2, "height"); +} + + +// NPatchInfo, n-patch layout info +static NPatchInfo RLUA_CHECK_NPatchInfo(lua_State *L, int index) +{ + NPatchInfo result = { 0 }; + if (lua_istable(L, index)) { + lua_getfield(L, index, "source"); + result.source = RLUA_CHECK_Rectangle(L, -1); // Texture source rectangle + lua_pop(L, 1); + lua_getfield(L, index, "left"); + result.left = (int)luaL_checkinteger(L, -1); // Left border offset + lua_pop(L, 1); + lua_getfield(L, index, "top"); + result.top = (int)luaL_checkinteger(L, -1); // Top border offset + lua_pop(L, 1); + lua_getfield(L, index, "right"); + result.right = (int)luaL_checkinteger(L, -1); // Right border offset + lua_pop(L, 1); + lua_getfield(L, index, "bottom"); + result.bottom = (int)luaL_checkinteger(L, -1); // Bottom border offset + lua_pop(L, 1); + lua_getfield(L, index, "layout"); + result.layout = (int)luaL_checkinteger(L, -1); // Layout of the n-patch: 3x3, 1x3 or 3x1 + lua_pop(L, 1); + } + return result; +} +static void RLUA_PUSH_NPatchInfo(lua_State *L, NPatchInfo result) +{ + lua_createtable(L, 0, 6); + RLUA_PUSH_Rectangle(L, result.source); // Texture source rectangle + lua_setfield(L, -2, "source"); + lua_pushinteger(L, result.left); // Left border offset + lua_setfield(L, -2, "left"); + lua_pushinteger(L, result.top); // Top border offset + lua_setfield(L, -2, "top"); + lua_pushinteger(L, result.right); // Right border offset + lua_setfield(L, -2, "right"); + lua_pushinteger(L, result.bottom); // Bottom border offset + lua_setfield(L, -2, "bottom"); + lua_pushinteger(L, result.layout); // Layout of the n-patch: 3x3, 1x3 or 3x1 + lua_setfield(L, -2, "layout"); +} + + +// GlyphInfo, font characters glyphs info +static GlyphInfo RLUA_CHECK_GlyphInfo(lua_State *L, int index) +{ + GlyphInfo result = { 0 }; + if (lua_istable(L, index)) { + lua_getfield(L, index, "value"); + result.value = (int)luaL_checkinteger(L, -1); // Character value (Unicode) + lua_pop(L, 1); + lua_getfield(L, index, "offsetX"); + result.offsetX = (int)luaL_checkinteger(L, -1); // Character offset X when drawing + lua_pop(L, 1); + lua_getfield(L, index, "offsetY"); + result.offsetY = (int)luaL_checkinteger(L, -1); // Character offset Y when drawing + lua_pop(L, 1); + lua_getfield(L, index, "advanceX"); + result.advanceX = (int)luaL_checkinteger(L, -1); // Character advance position X + lua_pop(L, 1); + lua_getfield(L, index, "image"); + result.image = *(Image*)RLUA_CHECK_Resource(L, -1, "Image"); // Character image data + lua_pop(L, 1); + } + return result; +} +static void RLUA_PUSH_GlyphInfo(lua_State *L, GlyphInfo result) +{ + lua_createtable(L, 0, 5); + lua_pushinteger(L, result.value); // Character value (Unicode) + lua_setfield(L, -2, "value"); + lua_pushinteger(L, result.offsetX); // Character offset X when drawing + lua_setfield(L, -2, "offsetX"); + lua_pushinteger(L, result.offsetY); // Character offset Y when drawing + lua_setfield(L, -2, "offsetY"); + lua_pushinteger(L, result.advanceX); // Character advance position X + lua_setfield(L, -2, "advanceX"); + RLUA_PUSH_Resource(L, &result.image, sizeof(Image), "Image"); // Character image data + lua_setfield(L, -2, "image"); +} + + +// Camera, defines position/orientation in 3d space +static Camera3D RLUA_CHECK_Camera3D(lua_State *L, int index) +{ + Camera3D result = { 0 }; + if (lua_istable(L, index)) { + lua_getfield(L, index, "position"); + result.position = RLUA_CHECK_Vector3(L, -1); // Camera position + lua_pop(L, 1); + lua_getfield(L, index, "target"); + result.target = RLUA_CHECK_Vector3(L, -1); // Camera target it looks-at + lua_pop(L, 1); + lua_getfield(L, index, "up"); + result.up = RLUA_CHECK_Vector3(L, -1); // Camera up vector (rotation over its axis) + lua_pop(L, 1); + lua_getfield(L, index, "fovy"); + result.fovy = (float)luaL_checknumber(L, -1); // Camera field-of-view aperture in Y (degrees) in perspective, used as near plane height in world units in orthographic + lua_pop(L, 1); + lua_getfield(L, index, "projection"); + result.projection = (int)luaL_checkinteger(L, -1); // Camera projection: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC + lua_pop(L, 1); + } + return result; +} +static void RLUA_PUSH_Camera3D(lua_State *L, Camera3D result) +{ + lua_createtable(L, 0, 5); + RLUA_PUSH_Vector3(L, result.position); // Camera position + lua_setfield(L, -2, "position"); + RLUA_PUSH_Vector3(L, result.target); // Camera target it looks-at + lua_setfield(L, -2, "target"); + RLUA_PUSH_Vector3(L, result.up); // Camera up vector (rotation over its axis) + lua_setfield(L, -2, "up"); + lua_pushnumber(L, result.fovy); // Camera field-of-view aperture in Y (degrees) in perspective, used as near plane height in world units in orthographic + lua_setfield(L, -2, "fovy"); + lua_pushinteger(L, result.projection); // Camera projection: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC + lua_setfield(L, -2, "projection"); +} +static void RLUA_WRITEBACK_Camera3D(lua_State *L, int index, Camera3D val) +{ + if (lua_istable(L, index)) { + RLUA_PUSH_Vector3(L, val.position); // Camera position + lua_setfield(L, index, "position"); + RLUA_PUSH_Vector3(L, val.target); // Camera target it looks-at + lua_setfield(L, index, "target"); + RLUA_PUSH_Vector3(L, val.up); // Camera up vector (rotation over its axis) + lua_setfield(L, index, "up"); + lua_pushnumber(L, val.fovy); // Camera field-of-view aperture in Y (degrees) in perspective, used as near plane height in world units in orthographic + lua_setfield(L, index, "fovy"); + lua_pushinteger(L, val.projection); // Camera projection: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC + lua_setfield(L, index, "projection"); + } +} + + +// Camera2D, defines position/orientation in 2d space +static Camera2D RLUA_CHECK_Camera2D(lua_State *L, int index) +{ + Camera2D result = { 0 }; + if (lua_istable(L, index)) { + lua_getfield(L, index, "offset"); + result.offset = RLUA_CHECK_Vector2(L, -1); // Camera offset (screen space offset from window origin) + lua_pop(L, 1); + lua_getfield(L, index, "target"); + result.target = RLUA_CHECK_Vector2(L, -1); // Camera target (world space target point that is mapped to screen space offset) + lua_pop(L, 1); + lua_getfield(L, index, "rotation"); + result.rotation = (float)luaL_checknumber(L, -1); // Camera rotation in degrees (pivots around target) + lua_pop(L, 1); + lua_getfield(L, index, "zoom"); + result.zoom = (float)luaL_checknumber(L, -1); // Camera zoom (scaling around target), must not be set to 0, set to 1.0f for no scale + lua_pop(L, 1); + } + return result; +} +static void RLUA_PUSH_Camera2D(lua_State *L, Camera2D result) +{ + lua_createtable(L, 0, 4); + RLUA_PUSH_Vector2(L, result.offset); // Camera offset (screen space offset from window origin) + lua_setfield(L, -2, "offset"); + RLUA_PUSH_Vector2(L, result.target); // Camera target (world space target point that is mapped to screen space offset) + lua_setfield(L, -2, "target"); + lua_pushnumber(L, result.rotation); // Camera rotation in degrees (pivots around target) + lua_setfield(L, -2, "rotation"); + lua_pushnumber(L, result.zoom); // Camera zoom (scaling around target), must not be set to 0, set to 1.0f for no scale + lua_setfield(L, -2, "zoom"); +} + + +// MaterialMap +static MaterialMap RLUA_CHECK_MaterialMap(lua_State *L, int index) +{ + MaterialMap result = { 0 }; + if (lua_istable(L, index)) { + lua_getfield(L, index, "texture"); + result.texture = *(Texture2D*)RLUA_CHECK_Resource(L, -1, "Texture2D"); // Material map texture + lua_pop(L, 1); + lua_getfield(L, index, "color"); + result.color = RLUA_CHECK_Color(L, -1); // Material map color + lua_pop(L, 1); + lua_getfield(L, index, "value"); + result.value = (float)luaL_checknumber(L, -1); // Material map value + lua_pop(L, 1); + } + return result; +} +static void RLUA_PUSH_MaterialMap(lua_State *L, MaterialMap result) +{ + lua_createtable(L, 0, 3); + RLUA_PUSH_Resource(L, &result.texture, sizeof(Texture2D), "Texture2D"); // Material map texture + lua_setfield(L, -2, "texture"); + RLUA_PUSH_Color(L, result.color); // Material map color + lua_setfield(L, -2, "color"); + lua_pushnumber(L, result.value); // Material map value + lua_setfield(L, -2, "value"); +} + + +// Transform, vertex transformation data +static Transform RLUA_CHECK_Transform(lua_State *L, int index) +{ + Transform result = { 0 }; + if (lua_istable(L, index)) { + lua_getfield(L, index, "translation"); + result.translation = RLUA_CHECK_Vector3(L, -1); // Translation + lua_pop(L, 1); + lua_getfield(L, index, "rotation"); + result.rotation = RLUA_CHECK_Quaternion(L, -1); // Rotation + lua_pop(L, 1); + lua_getfield(L, index, "scale"); + result.scale = RLUA_CHECK_Vector3(L, -1); // Scale + lua_pop(L, 1); + } + return result; +} +static void RLUA_PUSH_Transform(lua_State *L, Transform result) +{ + lua_createtable(L, 0, 3); + RLUA_PUSH_Vector3(L, result.translation); // Translation + lua_setfield(L, -2, "translation"); + RLUA_PUSH_Quaternion(L, result.rotation); // Rotation + lua_setfield(L, -2, "rotation"); + RLUA_PUSH_Vector3(L, result.scale); // Scale + lua_setfield(L, -2, "scale"); +} + + +// Bone, skeletal animation bone +static BoneInfo RLUA_CHECK_BoneInfo(lua_State *L, int index) +{ + BoneInfo result = { 0 }; + if (lua_istable(L, index)) { + lua_getfield(L, index, "name"); + if (lua_isstring(L, -1)) { strncpy(result.name, lua_tostring(L, -1), 32 - 1); } // Bone name + lua_pop(L, 1); + lua_getfield(L, index, "parent"); + result.parent = (int)luaL_checkinteger(L, -1); // Bone parent + lua_pop(L, 1); + } + return result; +} +static void RLUA_PUSH_BoneInfo(lua_State *L, BoneInfo result) +{ + lua_createtable(L, 0, 2); + lua_pushstring(L, result.name); // Bone name + lua_setfield(L, -2, "name"); + lua_pushinteger(L, result.parent); // Bone parent + lua_setfield(L, -2, "parent"); +} + + +// Skeleton, animation bones hierarchy +static ModelSkeleton RLUA_CHECK_ModelSkeleton(lua_State *L, int index) +{ + ModelSkeleton result = { 0 }; + if (lua_istable(L, index)) { + lua_getfield(L, index, "boneCount"); + result.boneCount = (int)luaL_checkinteger(L, -1); // Number of bones + lua_pop(L, 1); + lua_getfield(L, index, "bones"); + result.bones = (BoneInfo *)lua_touserdata(L, -1); // Bones information (skeleton) + lua_pop(L, 1); + lua_getfield(L, index, "bindPose"); + result.bindPose = RLUA_CHECK_ModelAnimPose(L, -1); // Bones base transformation (Transform[]) + lua_pop(L, 1); + } + return result; +} +static void RLUA_PUSH_ModelSkeleton(lua_State *L, ModelSkeleton result) +{ + lua_createtable(L, 0, 3); + lua_pushinteger(L, result.boneCount); // Number of bones + lua_setfield(L, -2, "boneCount"); + lua_pushlightuserdata(L, result.bones); // Bones information (skeleton) + lua_setfield(L, -2, "bones"); + RLUA_PUSH_ModelAnimPose(L, result.bindPose); // Bones base transformation (Transform[]) + lua_setfield(L, -2, "bindPose"); +} + + +// Ray, ray for raycasting +static Ray RLUA_CHECK_Ray(lua_State *L, int index) +{ + Ray result = { 0 }; + if (lua_istable(L, index)) { + lua_getfield(L, index, "position"); + result.position = RLUA_CHECK_Vector3(L, -1); // Ray position (origin) + lua_pop(L, 1); + lua_getfield(L, index, "direction"); + result.direction = RLUA_CHECK_Vector3(L, -1); // Ray direction (normalized) + lua_pop(L, 1); + } + return result; +} +static void RLUA_PUSH_Ray(lua_State *L, Ray result) +{ + lua_createtable(L, 0, 2); + RLUA_PUSH_Vector3(L, result.position); // Ray position (origin) + lua_setfield(L, -2, "position"); + RLUA_PUSH_Vector3(L, result.direction); // Ray direction (normalized) + lua_setfield(L, -2, "direction"); +} + + +// RayCollision, ray hit information +static RayCollision RLUA_CHECK_RayCollision(lua_State *L, int index) +{ + RayCollision result = { 0 }; + if (lua_istable(L, index)) { + lua_getfield(L, index, "hit"); + result.hit = lua_toboolean(L, -1); // Did the ray hit something? + lua_pop(L, 1); + lua_getfield(L, index, "distance"); + result.distance = (float)luaL_checknumber(L, -1); // Distance to the nearest hit + lua_pop(L, 1); + lua_getfield(L, index, "point"); + result.point = RLUA_CHECK_Vector3(L, -1); // Point of the nearest hit + lua_pop(L, 1); + lua_getfield(L, index, "normal"); + result.normal = RLUA_CHECK_Vector3(L, -1); // Surface normal of hit + lua_pop(L, 1); + } + return result; +} +static void RLUA_PUSH_RayCollision(lua_State *L, RayCollision result) +{ + lua_createtable(L, 0, 4); + lua_pushboolean(L, result.hit); // Did the ray hit something? + lua_setfield(L, -2, "hit"); + lua_pushnumber(L, result.distance); // Distance to the nearest hit + lua_setfield(L, -2, "distance"); + RLUA_PUSH_Vector3(L, result.point); // Point of the nearest hit + lua_setfield(L, -2, "point"); + RLUA_PUSH_Vector3(L, result.normal); // Surface normal of hit + lua_setfield(L, -2, "normal"); +} + + +// BoundingBox +static BoundingBox RLUA_CHECK_BoundingBox(lua_State *L, int index) +{ + BoundingBox result = { 0 }; + if (lua_istable(L, index)) { + lua_getfield(L, index, "min"); + result.min = RLUA_CHECK_Vector3(L, -1); // Minimum vertex box-corner + lua_pop(L, 1); + lua_getfield(L, index, "max"); + result.max = RLUA_CHECK_Vector3(L, -1); // Maximum vertex box-corner + lua_pop(L, 1); + } + return result; +} +static void RLUA_PUSH_BoundingBox(lua_State *L, BoundingBox result) +{ + lua_createtable(L, 0, 2); + RLUA_PUSH_Vector3(L, result.min); // Minimum vertex box-corner + lua_setfield(L, -2, "min"); + RLUA_PUSH_Vector3(L, result.max); // Maximum vertex box-corner + lua_setfield(L, -2, "max"); +} + + +// VrDeviceInfo, Head-Mounted-Display device parameters +static VrDeviceInfo RLUA_CHECK_VrDeviceInfo(lua_State *L, int index) +{ + VrDeviceInfo result = { 0 }; + if (lua_istable(L, index)) { + lua_getfield(L, index, "hResolution"); + result.hResolution = (int)luaL_checkinteger(L, -1); // Horizontal resolution in pixels + lua_pop(L, 1); + lua_getfield(L, index, "vResolution"); + result.vResolution = (int)luaL_checkinteger(L, -1); // Vertical resolution in pixels + lua_pop(L, 1); + lua_getfield(L, index, "hScreenSize"); + result.hScreenSize = (float)luaL_checknumber(L, -1); // Horizontal size in meters + lua_pop(L, 1); + lua_getfield(L, index, "vScreenSize"); + result.vScreenSize = (float)luaL_checknumber(L, -1); // Vertical size in meters + lua_pop(L, 1); + lua_getfield(L, index, "eyeToScreenDistance"); + result.eyeToScreenDistance = (float)luaL_checknumber(L, -1); // Distance between eye and display in meters + lua_pop(L, 1); + lua_getfield(L, index, "lensSeparationDistance"); + result.lensSeparationDistance = (float)luaL_checknumber(L, -1); // Lens separation distance in meters + lua_pop(L, 1); + lua_getfield(L, index, "interpupillaryDistance"); + result.interpupillaryDistance = (float)luaL_checknumber(L, -1); // IPD (distance between pupils) in meters + lua_pop(L, 1); + lua_getfield(L, index, "lensDistortionValues"); + if (lua_istable(L, -1)) { + for (int i = 0; i < 4; i++) { + lua_geti(L, -1, i + 1); + result.lensDistortionValues[i] = (float)luaL_checknumber(L, -1); + lua_pop(L, 1); + } + } + lua_pop(L, 1); + lua_getfield(L, index, "chromaAbCorrection"); + if (lua_istable(L, -1)) { + for (int i = 0; i < 4; i++) { + lua_geti(L, -1, i + 1); + result.chromaAbCorrection[i] = (float)luaL_checknumber(L, -1); + lua_pop(L, 1); + } + } + lua_pop(L, 1); + } + return result; +} +static void RLUA_PUSH_VrDeviceInfo(lua_State *L, VrDeviceInfo result) +{ + lua_createtable(L, 0, 9); + lua_pushinteger(L, result.hResolution); // Horizontal resolution in pixels + lua_setfield(L, -2, "hResolution"); + lua_pushinteger(L, result.vResolution); // Vertical resolution in pixels + lua_setfield(L, -2, "vResolution"); + lua_pushnumber(L, result.hScreenSize); // Horizontal size in meters + lua_setfield(L, -2, "hScreenSize"); + lua_pushnumber(L, result.vScreenSize); // Vertical size in meters + lua_setfield(L, -2, "vScreenSize"); + lua_pushnumber(L, result.eyeToScreenDistance); // Distance between eye and display in meters + lua_setfield(L, -2, "eyeToScreenDistance"); + lua_pushnumber(L, result.lensSeparationDistance); // Lens separation distance in meters + lua_setfield(L, -2, "lensSeparationDistance"); + lua_pushnumber(L, result.interpupillaryDistance); // IPD (distance between pupils) in meters + lua_setfield(L, -2, "interpupillaryDistance"); + lua_createtable(L, 4, 0); + for (int i = 0; i < 4; i++) { + lua_pushnumber(L, result.lensDistortionValues[i]); + lua_seti(L, -2, i + 1); + } + lua_setfield(L, -2, "lensDistortionValues"); + lua_createtable(L, 4, 0); + for (int i = 0; i < 4; i++) { + lua_pushnumber(L, result.chromaAbCorrection[i]); + lua_seti(L, -2, i + 1); + } + lua_setfield(L, -2, "chromaAbCorrection"); +} + + +// VrStereoConfig, VR stereo rendering configuration for simulator +static VrStereoConfig RLUA_CHECK_VrStereoConfig(lua_State *L, int index) +{ + VrStereoConfig result = { 0 }; + if (lua_istable(L, index)) { + lua_getfield(L, index, "projection"); + if (lua_istable(L, -1)) { + for (int i = 0; i < 2; i++) { + lua_geti(L, -1, i + 1); + result.projection[i] = RLUA_CHECK_Matrix(L, -1); + lua_pop(L, 1); + } + } + lua_pop(L, 1); + lua_getfield(L, index, "viewOffset"); + if (lua_istable(L, -1)) { + for (int i = 0; i < 2; i++) { + lua_geti(L, -1, i + 1); + result.viewOffset[i] = RLUA_CHECK_Matrix(L, -1); + lua_pop(L, 1); + } + } + lua_pop(L, 1); + lua_getfield(L, index, "leftLensCenter"); + if (lua_istable(L, -1)) { + for (int i = 0; i < 2; i++) { + lua_geti(L, -1, i + 1); + result.leftLensCenter[i] = (float)luaL_checknumber(L, -1); + lua_pop(L, 1); + } + } + lua_pop(L, 1); + lua_getfield(L, index, "rightLensCenter"); + if (lua_istable(L, -1)) { + for (int i = 0; i < 2; i++) { + lua_geti(L, -1, i + 1); + result.rightLensCenter[i] = (float)luaL_checknumber(L, -1); + lua_pop(L, 1); + } + } + lua_pop(L, 1); + lua_getfield(L, index, "leftScreenCenter"); + if (lua_istable(L, -1)) { + for (int i = 0; i < 2; i++) { + lua_geti(L, -1, i + 1); + result.leftScreenCenter[i] = (float)luaL_checknumber(L, -1); + lua_pop(L, 1); + } + } + lua_pop(L, 1); + lua_getfield(L, index, "rightScreenCenter"); + if (lua_istable(L, -1)) { + for (int i = 0; i < 2; i++) { + lua_geti(L, -1, i + 1); + result.rightScreenCenter[i] = (float)luaL_checknumber(L, -1); + lua_pop(L, 1); + } + } + lua_pop(L, 1); + lua_getfield(L, index, "scale"); + if (lua_istable(L, -1)) { + for (int i = 0; i < 2; i++) { + lua_geti(L, -1, i + 1); + result.scale[i] = (float)luaL_checknumber(L, -1); + lua_pop(L, 1); + } + } + lua_pop(L, 1); + lua_getfield(L, index, "scaleIn"); + if (lua_istable(L, -1)) { + for (int i = 0; i < 2; i++) { + lua_geti(L, -1, i + 1); + result.scaleIn[i] = (float)luaL_checknumber(L, -1); + lua_pop(L, 1); + } + } + lua_pop(L, 1); + } + return result; +} +static void RLUA_PUSH_VrStereoConfig(lua_State *L, VrStereoConfig result) +{ + lua_createtable(L, 0, 8); + lua_createtable(L, 2, 0); + for (int i = 0; i < 2; i++) { + RLUA_PUSH_Matrix(L, result.projection[i]); + lua_seti(L, -2, i + 1); + } + lua_setfield(L, -2, "projection"); + lua_createtable(L, 2, 0); + for (int i = 0; i < 2; i++) { + RLUA_PUSH_Matrix(L, result.viewOffset[i]); + lua_seti(L, -2, i + 1); + } + lua_setfield(L, -2, "viewOffset"); + lua_createtable(L, 2, 0); + for (int i = 0; i < 2; i++) { + lua_pushnumber(L, result.leftLensCenter[i]); + lua_seti(L, -2, i + 1); + } + lua_setfield(L, -2, "leftLensCenter"); + lua_createtable(L, 2, 0); + for (int i = 0; i < 2; i++) { + lua_pushnumber(L, result.rightLensCenter[i]); + lua_seti(L, -2, i + 1); + } + lua_setfield(L, -2, "rightLensCenter"); + lua_createtable(L, 2, 0); + for (int i = 0; i < 2; i++) { + lua_pushnumber(L, result.leftScreenCenter[i]); + lua_seti(L, -2, i + 1); + } + lua_setfield(L, -2, "leftScreenCenter"); + lua_createtable(L, 2, 0); + for (int i = 0; i < 2; i++) { + lua_pushnumber(L, result.rightScreenCenter[i]); + lua_seti(L, -2, i + 1); + } + lua_setfield(L, -2, "rightScreenCenter"); + lua_createtable(L, 2, 0); + for (int i = 0; i < 2; i++) { + lua_pushnumber(L, result.scale[i]); + lua_seti(L, -2, i + 1); + } + lua_setfield(L, -2, "scale"); + lua_createtable(L, 2, 0); + for (int i = 0; i < 2; i++) { + lua_pushnumber(L, result.scaleIn[i]); + lua_seti(L, -2, i + 1); + } + lua_setfield(L, -2, "scaleIn"); +} + + +// File path list +static FilePathList RLUA_CHECK_FilePathList(lua_State *L, int index) +{ + FilePathList result = { 0 }; + if (lua_istable(L, index)) { + lua_getfield(L, index, "count"); + result.count = (unsigned int)luaL_checkinteger(L, -1); // Filepaths entries count + lua_pop(L, 1); + lua_getfield(L, index, "paths"); + result.paths = (char **)lua_touserdata(L, -1); // Filepaths entries + lua_pop(L, 1); + } + return result; +} +static void RLUA_PUSH_FilePathList(lua_State *L, FilePathList result) +{ + lua_createtable(L, 0, 2); + lua_pushinteger(L, result.count); // Filepaths entries count + lua_setfield(L, -2, "count"); + lua_pushlightuserdata(L, result.paths); // Filepaths entries + lua_setfield(L, -2, "paths"); +} + + +// Automation event +static AutomationEvent RLUA_CHECK_AutomationEvent(lua_State *L, int index) +{ + AutomationEvent result = { 0 }; + if (lua_istable(L, index)) { + lua_getfield(L, index, "frame"); + result.frame = (unsigned int)luaL_checkinteger(L, -1); // Event frame + lua_pop(L, 1); + lua_getfield(L, index, "type"); + result.type = (unsigned int)luaL_checkinteger(L, -1); // Event type (AutomationEventType) + lua_pop(L, 1); + lua_getfield(L, index, "params"); + if (lua_istable(L, -1)) { + for (int i = 0; i < 4; i++) { + lua_geti(L, -1, i + 1); + result.params[i] = (int)luaL_checkinteger(L, -1); + lua_pop(L, 1); + } + } + lua_pop(L, 1); + } + return result; +} +static void RLUA_PUSH_AutomationEvent(lua_State *L, AutomationEvent result) +{ + lua_createtable(L, 0, 3); + lua_pushinteger(L, result.frame); // Event frame + lua_setfield(L, -2, "frame"); + lua_pushinteger(L, result.type); // Event type (AutomationEventType) + lua_setfield(L, -2, "type"); + lua_createtable(L, 4, 0); + for (int i = 0; i < 4; i++) { + lua_pushinteger(L, result.params[i]); + lua_seti(L, -2, i + 1); + } + lua_setfield(L, -2, "params"); +} + + +// Automation event list +static AutomationEventList RLUA_CHECK_AutomationEventList(lua_State *L, int index) +{ + AutomationEventList result = { 0 }; + if (lua_istable(L, index)) { + lua_getfield(L, index, "capacity"); + result.capacity = (unsigned int)luaL_checkinteger(L, -1); // Events max entries (MAX_AUTOMATION_EVENTS) + lua_pop(L, 1); + lua_getfield(L, index, "count"); + result.count = (unsigned int)luaL_checkinteger(L, -1); // Events entries count + lua_pop(L, 1); + lua_getfield(L, index, "events"); + result.events = (AutomationEvent *)lua_touserdata(L, -1); // Events entries + lua_pop(L, 1); + } + return result; +} +static void RLUA_PUSH_AutomationEventList(lua_State *L, AutomationEventList result) +{ + lua_createtable(L, 0, 3); + lua_pushinteger(L, result.capacity); // Events max entries (MAX_AUTOMATION_EVENTS) + lua_setfield(L, -2, "capacity"); + lua_pushinteger(L, result.count); // Events entries count + lua_setfield(L, -2, "count"); + lua_pushlightuserdata(L, result.events); // Events entries + lua_setfield(L, -2, "events"); +} +static void RLUA_WRITEBACK_AutomationEventList(lua_State *L, int index, AutomationEventList val) +{ + if (lua_istable(L, index)) { + lua_pushinteger(L, val.capacity); // Events max entries (MAX_AUTOMATION_EVENTS) + lua_setfield(L, index, "capacity"); + lua_pushinteger(L, val.count); // Events entries count + lua_setfield(L, index, "count"); + } +} + + +// --- Resource Destructors (__gc) --- + +static int rl_AudioStream_gc(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "AudioStream"); + if (h->data && h->owned) { + UnloadAudioStream(*(AudioStream*)h->data); + RL_FREE(h->data); + } + return 0; +} + +static int rl_Font_gc(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "Font"); + if (h->data && h->owned) { + UnloadFont(*(Font*)h->data); + RL_FREE(h->data); + } + return 0; +} + +static int rl_Image_gc(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "Image"); + if (h->data && h->owned) { + UnloadImage(*(Image*)h->data); + RL_FREE(h->data); + } + return 0; +} + +static int rl_Material_gc(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "Material"); + if (h->data && h->owned) { + UnloadMaterial(*(Material*)h->data); + RL_FREE(h->data); + } + return 0; +} + +static int rl_Mesh_gc(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "Mesh"); + if (h->data && h->owned) { + UnloadMesh(*(Mesh*)h->data); + RL_FREE(h->data); + } + return 0; +} + +static int rl_Model_gc(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "Model"); + if (h->data && h->owned) { + UnloadModel(*(Model*)h->data); + RL_FREE(h->data); + } + return 0; +} + +static int rl_Music_gc(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "Music"); + if (h->data && h->owned) { + UnloadMusicStream(*(Music*)h->data); + RL_FREE(h->data); + } + return 0; +} + +static int rl_RenderTexture_gc(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "RenderTexture"); + if (h->data && h->owned) { + UnloadRenderTexture(*(RenderTexture*)h->data); + RL_FREE(h->data); + } + return 0; +} + +static int rl_RenderTexture2D_gc(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "RenderTexture2D"); + if (h->data && h->owned) { + UnloadRenderTexture(*(RenderTexture2D*)h->data); + RL_FREE(h->data); + } + return 0; +} + +static int rl_Shader_gc(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "Shader"); + if (h->data && h->owned) { + UnloadShader(*(Shader*)h->data); + RL_FREE(h->data); + } + return 0; +} + +static int rl_Sound_gc(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "Sound"); + if (h->data && h->owned) { + UnloadSound(*(Sound*)h->data); + RL_FREE(h->data); + } + return 0; +} + +static int rl_Texture_gc(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "Texture"); + if (h->data && h->owned) { + UnloadTexture(*(Texture*)h->data); + RL_FREE(h->data); + } + return 0; +} + +static int rl_Texture2D_gc(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "Texture2D"); + if (h->data && h->owned) { + UnloadTexture(*(Texture2D*)h->data); + RL_FREE(h->data); + } + return 0; +} + +static int rl_TextureCubemap_gc(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "TextureCubemap"); + if (h->data && h->owned) { + UnloadTexture(*(TextureCubemap*)h->data); + RL_FREE(h->data); + } + return 0; +} + +static int rl_Wave_gc(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "Wave"); + if (h->data && h->owned) { + UnloadWave(*(Wave*)h->data); + RL_FREE(h->data); + } + return 0; +} + +// --- Resource Indexers (__index) --- + +static int rl_AudioStream_index(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "AudioStream"); + if (lua_isnumber(L, 2)) { + int i = lua_tointeger(L, 2) - 1; + if (i < 0 || i >= h->count) return luaL_error(L, "index out of bounds"); + AudioStream *ptr = &((AudioStream *)h->data)[i]; + RLUA_PUSH_View(L, ptr, 1, "AudioStream", false); + return 1; + } + const char *key = luaL_checkstring(L, 2); + AudioStream *data = (AudioStream *)h->data; + if (strcmp(key, "buffer") == 0) { // Pointer to internal data used by the audio system + lua_pushlightuserdata(L, data->buffer); + return 1; + } + if (strcmp(key, "processor") == 0) { // Pointer to internal data processor, useful for audio effects + lua_pushlightuserdata(L, data->processor); + return 1; + } + if (strcmp(key, "sampleRate") == 0) { // Frequency (samples per second) + lua_pushinteger(L, data->sampleRate); + return 1; + } + if (strcmp(key, "sampleSize") == 0) { // Bit depth (bits per sample): 8, 16, 32 (24 not supported) + lua_pushinteger(L, data->sampleSize); + return 1; + } + if (strcmp(key, "channels") == 0) { // Number of channels (1-mono, 2-stereo, ...) + lua_pushinteger(L, data->channels); + return 1; + } + return 0; +} + +static int rl_Font_index(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "Font"); + if (lua_isnumber(L, 2)) { + int i = lua_tointeger(L, 2) - 1; + if (i < 0 || i >= h->count) return luaL_error(L, "index out of bounds"); + Font *ptr = &((Font *)h->data)[i]; + RLUA_PUSH_View(L, ptr, 1, "Font", false); + return 1; + } + const char *key = luaL_checkstring(L, 2); + Font *data = (Font *)h->data; + if (strcmp(key, "baseSize") == 0) { // Base size (default chars height) + lua_pushinteger(L, data->baseSize); + return 1; + } + if (strcmp(key, "glyphCount") == 0) { // Number of glyph characters + lua_pushinteger(L, data->glyphCount); + return 1; + } + if (strcmp(key, "glyphPadding") == 0) { // Padding around the glyph characters + lua_pushinteger(L, data->glyphPadding); + return 1; + } + if (strcmp(key, "texture") == 0) { // Texture atlas containing the glyphs + RLUA_PUSH_View(L, &data->texture, 1, "Texture2D", false); + return 1; + } + if (strcmp(key, "recs") == 0) { // Rectangles in texture for the glyphs + lua_pushlightuserdata(L, data->recs); + return 1; + } + if (strcmp(key, "glyphs") == 0) { // Glyphs info data + lua_pushlightuserdata(L, data->glyphs); + return 1; + } + return 0; +} + +static int rl_Image_index(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "Image"); + if (lua_isnumber(L, 2)) { + int i = lua_tointeger(L, 2) - 1; + if (i < 0 || i >= h->count) return luaL_error(L, "index out of bounds"); + Image *ptr = &((Image *)h->data)[i]; + RLUA_PUSH_View(L, ptr, 1, "Image", false); + return 1; + } + const char *key = luaL_checkstring(L, 2); + Image *data = (Image *)h->data; + if (strcmp(key, "data") == 0) { // Image raw data + lua_pushlightuserdata(L, data->data); + return 1; + } + if (strcmp(key, "width") == 0) { // Image base width + lua_pushinteger(L, data->width); + return 1; + } + if (strcmp(key, "height") == 0) { // Image base height + lua_pushinteger(L, data->height); + return 1; + } + if (strcmp(key, "mipmaps") == 0) { // Mipmap levels, 1 by default + lua_pushinteger(L, data->mipmaps); + return 1; + } + if (strcmp(key, "format") == 0) { // Data format (PixelFormat type) + lua_pushinteger(L, data->format); + return 1; + } + return 0; +} + +static int rl_Material_index(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "Material"); + if (lua_isnumber(L, 2)) { + int i = lua_tointeger(L, 2) - 1; + if (i < 0 || i >= h->count) return luaL_error(L, "index out of bounds"); + Material *ptr = &((Material *)h->data)[i]; + RLUA_PUSH_View(L, ptr, 1, "Material", false); + return 1; + } + const char *key = luaL_checkstring(L, 2); + Material *data = (Material *)h->data; + if (strcmp(key, "shader") == 0) { // Material shader + RLUA_PUSH_View(L, &data->shader, 1, "Shader", false); + return 1; + } + if (strcmp(key, "maps") == 0) { // Material maps array (MAX_MATERIAL_MAPS) + lua_pushlightuserdata(L, data->maps); + return 1; + } + return 0; +} + +static int rl_Mesh_index(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "Mesh"); + if (lua_isnumber(L, 2)) { + int i = lua_tointeger(L, 2) - 1; + if (i < 0 || i >= h->count) return luaL_error(L, "index out of bounds"); + Mesh *ptr = &((Mesh *)h->data)[i]; + RLUA_PUSH_View(L, ptr, 1, "Mesh", false); + return 1; + } + const char *key = luaL_checkstring(L, 2); + Mesh *data = (Mesh *)h->data; + if (strcmp(key, "vertexCount") == 0) { // Number of vertices stored in arrays + lua_pushinteger(L, data->vertexCount); + return 1; + } + if (strcmp(key, "triangleCount") == 0) { // Number of triangles stored (indexed or not) + lua_pushinteger(L, data->triangleCount); + return 1; + } + if (strcmp(key, "vertices") == 0) { // Vertex position (XYZ - 3 components per vertex) (shader-location = 0) + lua_pushlightuserdata(L, data->vertices); + return 1; + } + if (strcmp(key, "texcoords") == 0) { // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) + lua_pushlightuserdata(L, data->texcoords); + return 1; + } + if (strcmp(key, "texcoords2") == 0) { // Vertex texture second coordinates (UV - 2 components per vertex) (shader-location = 5) + lua_pushlightuserdata(L, data->texcoords2); + return 1; + } + if (strcmp(key, "normals") == 0) { // Vertex normals (XYZ - 3 components per vertex) (shader-location = 2) + lua_pushlightuserdata(L, data->normals); + return 1; + } + if (strcmp(key, "tangents") == 0) { // Vertex tangents (XYZW - 4 components per vertex) (shader-location = 4) + lua_pushlightuserdata(L, data->tangents); + return 1; + } + if (strcmp(key, "colors") == 0) { // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3) + lua_pushlightuserdata(L, data->colors); + return 1; + } + if (strcmp(key, "indices") == 0) { // Vertex indices (in case vertex data comes indexed) + lua_pushlightuserdata(L, data->indices); + return 1; + } + if (strcmp(key, "boneCount") == 0) { // Number of bones (MAX: 256 bones) + lua_pushinteger(L, data->boneCount); + return 1; + } + if (strcmp(key, "boneIndices") == 0) { // Vertex bone indices, up to 4 bones influence by vertex (skinning) (shader-location = 6) + lua_pushlightuserdata(L, data->boneIndices); + return 1; + } + if (strcmp(key, "boneWeights") == 0) { // Vertex bone weight, up to 4 bones influence by vertex (skinning) (shader-location = 7) + lua_pushlightuserdata(L, data->boneWeights); + return 1; + } + if (strcmp(key, "animVertices") == 0) { // Animated vertex positions (after bones transformations) + lua_pushlightuserdata(L, data->animVertices); + return 1; + } + if (strcmp(key, "animNormals") == 0) { // Animated normals (after bones transformations) + lua_pushlightuserdata(L, data->animNormals); + return 1; + } + if (strcmp(key, "vaoId") == 0) { // OpenGL Vertex Array Object id + lua_pushinteger(L, data->vaoId); + return 1; + } + if (strcmp(key, "vboId") == 0) { // OpenGL Vertex Buffer Objects id (default vertex data) + lua_pushlightuserdata(L, data->vboId); + return 1; + } + return 0; +} + +static int rl_Model_index(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "Model"); + if (lua_isnumber(L, 2)) { + int i = lua_tointeger(L, 2) - 1; + if (i < 0 || i >= h->count) return luaL_error(L, "index out of bounds"); + Model *ptr = &((Model *)h->data)[i]; + RLUA_PUSH_View(L, ptr, 1, "Model", false); + return 1; + } + const char *key = luaL_checkstring(L, 2); + Model *data = (Model *)h->data; + if (strcmp(key, "transform") == 0) { // Local transform matrix + RLUA_PUSH_Matrix(L, data->transform); + return 1; + } + if (strcmp(key, "meshCount") == 0) { // Number of meshes + lua_pushinteger(L, data->meshCount); + return 1; + } + if (strcmp(key, "materialCount") == 0) { // Number of materials + lua_pushinteger(L, data->materialCount); + return 1; + } + if (strcmp(key, "meshes") == 0) { // Meshes array + lua_pushlightuserdata(L, data->meshes); + return 1; + } + if (strcmp(key, "materials") == 0) { // Materials array + lua_pushlightuserdata(L, data->materials); + return 1; + } + if (strcmp(key, "meshMaterial") == 0) { // Mesh material number + lua_pushlightuserdata(L, data->meshMaterial); + return 1; + } + if (strcmp(key, "skeleton") == 0) { // Skeleton for animation + RLUA_PUSH_ModelSkeleton(L, data->skeleton); + return 1; + } + if (strcmp(key, "currentPose") == 0) { // Current animation pose (Transform[]) + RLUA_PUSH_ModelAnimPose(L, data->currentPose); + return 1; + } + if (strcmp(key, "boneMatrices") == 0) { // Bones animated transformation matrices + lua_pushlightuserdata(L, data->boneMatrices); + return 1; + } + return 0; +} + +static int rl_ModelAnimation_index(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "ModelAnimation"); + if (lua_isnumber(L, 2)) { + int i = lua_tointeger(L, 2) - 1; + if (i < 0 || i >= h->count) return luaL_error(L, "index out of bounds"); + ModelAnimation *ptr = &((ModelAnimation *)h->data)[i]; + RLUA_PUSH_View(L, ptr, 1, "ModelAnimation", false); + return 1; + } + const char *key = luaL_checkstring(L, 2); + ModelAnimation *data = (ModelAnimation *)h->data; + if (strcmp(key, "boneCount") == 0) { // Number of bones (per pose) + lua_pushinteger(L, data->boneCount); + return 1; + } + if (strcmp(key, "keyframeCount") == 0) { // Number of animation key frames + lua_pushinteger(L, data->keyframeCount); + return 1; + } + if (strcmp(key, "keyframePoses") == 0) { // Animation sequence keyframe poses [keyframe][pose] + lua_pushlightuserdata(L, data->keyframePoses); + return 1; + } + return 0; +} + +static int rl_Music_index(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "Music"); + if (lua_isnumber(L, 2)) { + int i = lua_tointeger(L, 2) - 1; + if (i < 0 || i >= h->count) return luaL_error(L, "index out of bounds"); + Music *ptr = &((Music *)h->data)[i]; + RLUA_PUSH_View(L, ptr, 1, "Music", false); + return 1; + } + const char *key = luaL_checkstring(L, 2); + Music *data = (Music *)h->data; + if (strcmp(key, "stream") == 0) { // Audio stream + RLUA_PUSH_View(L, &data->stream, 1, "AudioStream", false); + return 1; + } + if (strcmp(key, "frameCount") == 0) { // Total number of frames (considering channels) + lua_pushinteger(L, data->frameCount); + return 1; + } + if (strcmp(key, "looping") == 0) { // Music looping enable + lua_pushboolean(L, data->looping); + return 1; + } + if (strcmp(key, "ctxType") == 0) { // Type of music context (audio filetype) + lua_pushinteger(L, data->ctxType); + return 1; + } + if (strcmp(key, "ctxData") == 0) { // Audio context data, depends on type + lua_pushlightuserdata(L, data->ctxData); + return 1; + } + return 0; +} + +static int rl_RenderTexture_index(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "RenderTexture"); + if (lua_isnumber(L, 2)) { + int i = lua_tointeger(L, 2) - 1; + if (i < 0 || i >= h->count) return luaL_error(L, "index out of bounds"); + RenderTexture *ptr = &((RenderTexture *)h->data)[i]; + RLUA_PUSH_View(L, ptr, 1, "RenderTexture", false); + return 1; + } + const char *key = luaL_checkstring(L, 2); + RenderTexture *data = (RenderTexture *)h->data; + if (strcmp(key, "id") == 0) { // OpenGL framebuffer object id + lua_pushinteger(L, data->id); + return 1; + } + if (strcmp(key, "texture") == 0) { // Color buffer attachment texture + RLUA_PUSH_View(L, &data->texture, 1, "Texture", false); + return 1; + } + if (strcmp(key, "depth") == 0) { // Depth buffer attachment texture + RLUA_PUSH_View(L, &data->depth, 1, "Texture", false); + return 1; + } + return 0; +} + +static int rl_Shader_index(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "Shader"); + if (lua_isnumber(L, 2)) { + int i = lua_tointeger(L, 2) - 1; + if (i < 0 || i >= h->count) return luaL_error(L, "index out of bounds"); + Shader *ptr = &((Shader *)h->data)[i]; + RLUA_PUSH_View(L, ptr, 1, "Shader", false); + return 1; + } + const char *key = luaL_checkstring(L, 2); + Shader *data = (Shader *)h->data; + if (strcmp(key, "id") == 0) { // Shader program id + lua_pushinteger(L, data->id); + return 1; + } + if (strcmp(key, "locs") == 0) { // Shader locations array (RL_MAX_SHADER_LOCATIONS) + lua_pushlightuserdata(L, data->locs); + return 1; + } + return 0; +} + +static int rl_Sound_index(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "Sound"); + if (lua_isnumber(L, 2)) { + int i = lua_tointeger(L, 2) - 1; + if (i < 0 || i >= h->count) return luaL_error(L, "index out of bounds"); + Sound *ptr = &((Sound *)h->data)[i]; + RLUA_PUSH_View(L, ptr, 1, "Sound", false); + return 1; + } + const char *key = luaL_checkstring(L, 2); + Sound *data = (Sound *)h->data; + if (strcmp(key, "stream") == 0) { // Audio stream + RLUA_PUSH_View(L, &data->stream, 1, "AudioStream", false); + return 1; + } + if (strcmp(key, "frameCount") == 0) { // Total number of frames (considering channels) + lua_pushinteger(L, data->frameCount); + return 1; + } + return 0; +} + +static int rl_Texture_index(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "Texture"); + if (lua_isnumber(L, 2)) { + int i = lua_tointeger(L, 2) - 1; + if (i < 0 || i >= h->count) return luaL_error(L, "index out of bounds"); + Texture *ptr = &((Texture *)h->data)[i]; + RLUA_PUSH_View(L, ptr, 1, "Texture", false); + return 1; + } + const char *key = luaL_checkstring(L, 2); + Texture *data = (Texture *)h->data; + if (strcmp(key, "id") == 0) { // OpenGL texture id + lua_pushinteger(L, data->id); + return 1; + } + if (strcmp(key, "width") == 0) { // Texture base width + lua_pushinteger(L, data->width); + return 1; + } + if (strcmp(key, "height") == 0) { // Texture base height + lua_pushinteger(L, data->height); + return 1; + } + if (strcmp(key, "mipmaps") == 0) { // Mipmap levels, 1 by default + lua_pushinteger(L, data->mipmaps); + return 1; + } + if (strcmp(key, "format") == 0) { // Data format (PixelFormat type) + lua_pushinteger(L, data->format); + return 1; + } + return 0; +} + +static int rl_Wave_index(lua_State *L) +{ + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "Wave"); + if (lua_isnumber(L, 2)) { + int i = lua_tointeger(L, 2) - 1; + if (i < 0 || i >= h->count) return luaL_error(L, "index out of bounds"); + Wave *ptr = &((Wave *)h->data)[i]; + RLUA_PUSH_View(L, ptr, 1, "Wave", false); + return 1; + } + const char *key = luaL_checkstring(L, 2); + Wave *data = (Wave *)h->data; + if (strcmp(key, "frameCount") == 0) { // Total number of frames (considering channels) + lua_pushinteger(L, data->frameCount); + return 1; + } + if (strcmp(key, "sampleRate") == 0) { // Frequency (samples per second) + lua_pushinteger(L, data->sampleRate); + return 1; + } + if (strcmp(key, "sampleSize") == 0) { // Bit depth (bits per sample): 8, 16, 32 (24 not supported) + lua_pushinteger(L, data->sampleSize); + return 1; + } + if (strcmp(key, "channels") == 0) { // Number of channels (1-mono, 2-stereo, ...) + lua_pushinteger(L, data->channels); + return 1; + } + if (strcmp(key, "data") == 0) { // Buffer data pointer + lua_pushlightuserdata(L, data->data); + return 1; + } + return 0; +} + +// --- Wrappers --- + +// Callbacks to hook some internal functions +// WARNING: These callbacks are intended for advanced users + +// Window-related functions +// Initialize window and OpenGL context +static int rl_InitWindow(lua_State *L) +{ + int width = (int)luaL_checkinteger(L, 1); + int height = (int)luaL_checkinteger(L, 2); + const char * title = luaL_checkstring(L, 3); + InitWindow(width, height, title); + return 0; +} + +// Close window and unload OpenGL context +static int rl_CloseWindow(lua_State *L) +{ + CloseWindow(); + return 0; +} + +// Check if application should close (KEY_ESCAPE pressed or windows close icon clicked) +static int rl_WindowShouldClose(lua_State *L) +{ + bool result = WindowShouldClose(); + lua_pushboolean(L, result); + return 1; +} + +// Check if window has been initialized successfully +static int rl_IsWindowReady(lua_State *L) +{ + bool result = IsWindowReady(); + lua_pushboolean(L, result); + return 1; +} + +// Check if window is currently fullscreen +static int rl_IsWindowFullscreen(lua_State *L) +{ + bool result = IsWindowFullscreen(); + lua_pushboolean(L, result); + return 1; +} + +// Check if window is currently hidden +static int rl_IsWindowHidden(lua_State *L) +{ + bool result = IsWindowHidden(); + lua_pushboolean(L, result); + return 1; +} + +// Check if window is currently minimized +static int rl_IsWindowMinimized(lua_State *L) +{ + bool result = IsWindowMinimized(); + lua_pushboolean(L, result); + return 1; +} + +// Check if window is currently maximized +static int rl_IsWindowMaximized(lua_State *L) +{ + bool result = IsWindowMaximized(); + lua_pushboolean(L, result); + return 1; +} + +// Check if window is currently focused +static int rl_IsWindowFocused(lua_State *L) +{ + bool result = IsWindowFocused(); + lua_pushboolean(L, result); + return 1; +} + +// Check if window has been resized last frame +static int rl_IsWindowResized(lua_State *L) +{ + bool result = IsWindowResized(); + lua_pushboolean(L, result); + return 1; +} + +// Check if one specific window flag is enabled +static int rl_IsWindowState(lua_State *L) +{ + unsigned int flag = (unsigned int)luaL_checkinteger(L, 1); + bool result = IsWindowState(flag); + lua_pushboolean(L, result); + return 1; +} + +// Set window configuration state using flags +static int rl_SetWindowState(lua_State *L) +{ + unsigned int flags = (unsigned int)luaL_checkinteger(L, 1); + SetWindowState(flags); + return 0; +} + +// Clear window configuration state flags +static int rl_ClearWindowState(lua_State *L) +{ + unsigned int flags = (unsigned int)luaL_checkinteger(L, 1); + ClearWindowState(flags); + return 0; +} + +// Toggle window state: fullscreen/windowed, resizes monitor to match window resolution +static int rl_ToggleFullscreen(lua_State *L) +{ + ToggleFullscreen(); + return 0; +} + +// Toggle window state: borderless windowed, resizes window to match monitor resolution +static int rl_ToggleBorderlessWindowed(lua_State *L) +{ + ToggleBorderlessWindowed(); + return 0; +} + +// Set window state: maximized, if resizable +static int rl_MaximizeWindow(lua_State *L) +{ + MaximizeWindow(); + return 0; +} + +// Set window state: minimized, if resizable +static int rl_MinimizeWindow(lua_State *L) +{ + MinimizeWindow(); + return 0; +} + +// Restore window from being minimized/maximized +static int rl_RestoreWindow(lua_State *L) +{ + RestoreWindow(); + return 0; +} + +// Set icon for window (single image, RGBA 32bit) +static int rl_SetWindowIcon(lua_State *L) +{ + Image image = *(Image*)RLUA_CHECK_Resource(L, 1, "Image"); + SetWindowIcon(image); + return 0; +} + +// Set icon for window (multiple images, RGBA 32bit) +static int rl_SetWindowIcons(lua_State *L) +{ + Image * images = (Image *)lua_touserdata(L, 1); + int count = (int)luaL_checkinteger(L, 2); + SetWindowIcons(images, count); + return 0; +} + +// Set title for window +static int rl_SetWindowTitle(lua_State *L) +{ + const char * title = luaL_checkstring(L, 1); + SetWindowTitle(title); + return 0; +} + +// Set window position on screen +static int rl_SetWindowPosition(lua_State *L) +{ + int x = (int)luaL_checkinteger(L, 1); + int y = (int)luaL_checkinteger(L, 2); + SetWindowPosition(x, y); + return 0; +} + +// Set monitor for the current window +static int rl_SetWindowMonitor(lua_State *L) +{ + int monitor = (int)luaL_checkinteger(L, 1); + SetWindowMonitor(monitor); + return 0; +} + +// Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE) +static int rl_SetWindowMinSize(lua_State *L) +{ + int width = (int)luaL_checkinteger(L, 1); + int height = (int)luaL_checkinteger(L, 2); + SetWindowMinSize(width, height); + return 0; +} + +// Set window maximum dimensions (for FLAG_WINDOW_RESIZABLE) +static int rl_SetWindowMaxSize(lua_State *L) +{ + int width = (int)luaL_checkinteger(L, 1); + int height = (int)luaL_checkinteger(L, 2); + SetWindowMaxSize(width, height); + return 0; +} + +// Set window dimensions +static int rl_SetWindowSize(lua_State *L) +{ + int width = (int)luaL_checkinteger(L, 1); + int height = (int)luaL_checkinteger(L, 2); + SetWindowSize(width, height); + return 0; +} + +// Set window opacity [0.0f..1.0f] +static int rl_SetWindowOpacity(lua_State *L) +{ + float opacity = (float)luaL_checknumber(L, 1); + SetWindowOpacity(opacity); + return 0; +} + +// Set window focused +static int rl_SetWindowFocused(lua_State *L) +{ + SetWindowFocused(); + return 0; +} + +// Get native window handle +static int rl_GetWindowHandle(lua_State *L) +{ + void * result = GetWindowHandle(); + lua_pushlightuserdata(L, result); + return 1; +} + +// Get current screen width +static int rl_GetScreenWidth(lua_State *L) +{ + int result = GetScreenWidth(); + lua_pushinteger(L, result); + return 1; +} + +// Get current screen height +static int rl_GetScreenHeight(lua_State *L) +{ + int result = GetScreenHeight(); + lua_pushinteger(L, result); + return 1; +} + +// Get current render width (it considers HiDPI) +static int rl_GetRenderWidth(lua_State *L) +{ + int result = GetRenderWidth(); + lua_pushinteger(L, result); + return 1; +} + +// Get current render height (it considers HiDPI) +static int rl_GetRenderHeight(lua_State *L) +{ + int result = GetRenderHeight(); + lua_pushinteger(L, result); + return 1; +} + +// Get number of connected monitors +static int rl_GetMonitorCount(lua_State *L) +{ + int result = GetMonitorCount(); + lua_pushinteger(L, result); + return 1; +} + +// Get current monitor where window is placed +static int rl_GetCurrentMonitor(lua_State *L) +{ + int result = GetCurrentMonitor(); + lua_pushinteger(L, result); + return 1; +} + +// Get specified monitor position +static int rl_GetMonitorPosition(lua_State *L) +{ + int monitor = (int)luaL_checkinteger(L, 1); + Vector2 result = GetMonitorPosition(monitor); + RLUA_PUSH_Vector2(L, result); + return 1; +} + +// Get specified monitor width (current video mode used by monitor) +static int rl_GetMonitorWidth(lua_State *L) +{ + int monitor = (int)luaL_checkinteger(L, 1); + int result = GetMonitorWidth(monitor); + lua_pushinteger(L, result); + return 1; +} + +// Get specified monitor height (current video mode used by monitor) +static int rl_GetMonitorHeight(lua_State *L) +{ + int monitor = (int)luaL_checkinteger(L, 1); + int result = GetMonitorHeight(monitor); + lua_pushinteger(L, result); + return 1; +} + +// Get specified monitor physical width in millimetres +static int rl_GetMonitorPhysicalWidth(lua_State *L) +{ + int monitor = (int)luaL_checkinteger(L, 1); + int result = GetMonitorPhysicalWidth(monitor); + lua_pushinteger(L, result); + return 1; +} + +// Get specified monitor physical height in millimetres +static int rl_GetMonitorPhysicalHeight(lua_State *L) +{ + int monitor = (int)luaL_checkinteger(L, 1); + int result = GetMonitorPhysicalHeight(monitor); + lua_pushinteger(L, result); + return 1; +} + +// Get specified monitor refresh rate +static int rl_GetMonitorRefreshRate(lua_State *L) +{ + int monitor = (int)luaL_checkinteger(L, 1); + int result = GetMonitorRefreshRate(monitor); + lua_pushinteger(L, result); + return 1; +} + +// Get window position XY on monitor +static int rl_GetWindowPosition(lua_State *L) +{ + Vector2 result = GetWindowPosition(); + RLUA_PUSH_Vector2(L, result); + return 1; +} + +// Get window scale DPI factor +static int rl_GetWindowScaleDPI(lua_State *L) +{ + Vector2 result = GetWindowScaleDPI(); + RLUA_PUSH_Vector2(L, result); + return 1; +} + +// Get the human-readable, UTF-8 encoded name of the specified monitor +static int rl_GetMonitorName(lua_State *L) +{ + int monitor = (int)luaL_checkinteger(L, 1); + const char * result = GetMonitorName(monitor); + lua_pushstring(L, result); + return 1; +} + +// Set clipboard text content +static int rl_SetClipboardText(lua_State *L) +{ + const char * text = luaL_checkstring(L, 1); + SetClipboardText(text); + return 0; +} + +// Get clipboard text content +static int rl_GetClipboardText(lua_State *L) +{ + const char * result = GetClipboardText(); + lua_pushstring(L, result); + return 1; +} + +// Get clipboard image content +static int rl_GetClipboardImage(lua_State *L) +{ + Image result = GetClipboardImage(); + RLUA_PUSH_Resource(L, &result, sizeof(Image), "Image"); + return 1; +} + +// Enable waiting for events on EndDrawing(), no automatic event polling +static int rl_EnableEventWaiting(lua_State *L) +{ + EnableEventWaiting(); + return 0; +} + +// Disable waiting for events on EndDrawing(), automatic events polling +static int rl_DisableEventWaiting(lua_State *L) +{ + DisableEventWaiting(); + return 0; +} + +// Cursor-related functions +// Shows cursor +static int rl_ShowCursor(lua_State *L) +{ + ShowCursor(); + return 0; +} + +// Hides cursor +static int rl_HideCursor(lua_State *L) +{ + HideCursor(); + return 0; +} + +// Check if cursor is not visible +static int rl_IsCursorHidden(lua_State *L) +{ + bool result = IsCursorHidden(); + lua_pushboolean(L, result); + return 1; +} + +// Enables cursor (unlock cursor) +static int rl_EnableCursor(lua_State *L) +{ + EnableCursor(); + return 0; +} + +// Disables cursor (lock cursor) +static int rl_DisableCursor(lua_State *L) +{ + DisableCursor(); + return 0; +} + +// Check if cursor is on the screen +static int rl_IsCursorOnScreen(lua_State *L) +{ + bool result = IsCursorOnScreen(); + lua_pushboolean(L, result); + return 1; +} + +// Drawing-related functions +// Set background color (framebuffer clear color) +static int rl_ClearBackground(lua_State *L) +{ + Color color = RLUA_CHECK_Color(L, 1); + ClearBackground(color); + return 0; +} + +// Setup canvas (framebuffer) to start drawing +static int rl_BeginDrawing(lua_State *L) +{ + BeginDrawing(); + return 0; +} + +// End canvas drawing and swap buffers (double buffering) +static int rl_EndDrawing(lua_State *L) +{ + EndDrawing(); + return 0; +} + +// Begin 2D mode with custom camera (2D) +static int rl_BeginMode2D(lua_State *L) +{ + Camera2D camera = RLUA_CHECK_Camera2D(L, 1); + BeginMode2D(camera); + return 0; +} + +// Ends 2D mode with custom camera +static int rl_EndMode2D(lua_State *L) +{ + EndMode2D(); + return 0; +} + +// Begin 3D mode with custom camera (3D) +static int rl_BeginMode3D(lua_State *L) +{ + Camera3D camera = RLUA_CHECK_Camera3D(L, 1); + BeginMode3D(camera); + return 0; +} + +// Ends 3D mode and returns to default 2D orthographic mode +static int rl_EndMode3D(lua_State *L) +{ + EndMode3D(); + return 0; +} + +// Begin drawing to render texture +static int rl_BeginTextureMode(lua_State *L) +{ + RenderTexture2D target = *(RenderTexture2D*)RLUA_CHECK_Resource(L, 1, "RenderTexture2D"); + BeginTextureMode(target); + return 0; +} + +// Ends drawing to render texture +static int rl_EndTextureMode(lua_State *L) +{ + EndTextureMode(); + return 0; +} + +// Begin custom shader drawing +static int rl_BeginShaderMode(lua_State *L) +{ + Shader shader = *(Shader*)RLUA_CHECK_Resource(L, 1, "Shader"); + BeginShaderMode(shader); + return 0; +} + +// End custom shader drawing (use default shader) +static int rl_EndShaderMode(lua_State *L) +{ + EndShaderMode(); + return 0; +} + +// Begin blending mode (alpha, additive, multiplied, subtract, custom) +static int rl_BeginBlendMode(lua_State *L) +{ + int mode = (int)luaL_checkinteger(L, 1); + BeginBlendMode(mode); + return 0; +} + +// End blending mode (reset to default: alpha blending) +static int rl_EndBlendMode(lua_State *L) +{ + EndBlendMode(); + return 0; +} + +// Begin scissor mode (define screen area for following drawing) +static int rl_BeginScissorMode(lua_State *L) +{ + int x = (int)luaL_checkinteger(L, 1); + int y = (int)luaL_checkinteger(L, 2); + int width = (int)luaL_checkinteger(L, 3); + int height = (int)luaL_checkinteger(L, 4); + BeginScissorMode(x, y, width, height); + return 0; +} + +// End scissor mode +static int rl_EndScissorMode(lua_State *L) +{ + EndScissorMode(); + return 0; +} + +// Begin stereo rendering (requires VR simulator) +static int rl_BeginVrStereoMode(lua_State *L) +{ + VrStereoConfig config = RLUA_CHECK_VrStereoConfig(L, 1); + BeginVrStereoMode(config); + return 0; +} + +// End stereo rendering (requires VR simulator) +static int rl_EndVrStereoMode(lua_State *L) +{ + EndVrStereoMode(); + return 0; +} + +// VR stereo config functions for VR simulator +// Load VR stereo config for VR simulator device parameters +static int rl_LoadVrStereoConfig(lua_State *L) +{ + VrDeviceInfo device = RLUA_CHECK_VrDeviceInfo(L, 1); + VrStereoConfig result = LoadVrStereoConfig(device); + RLUA_PUSH_VrStereoConfig(L, result); + return 1; +} + +// Unload VR stereo config +static int rl_UnloadVrStereoConfig(lua_State *L) +{ + VrStereoConfig config = RLUA_CHECK_VrStereoConfig(L, 1); + UnloadVrStereoConfig(config); + return 0; +} + +// Shader management functions +// NOTE: Shader functionality is not available on OpenGL 1.1 +// Load shader from files and bind default locations +static int rl_LoadShader(lua_State *L) +{ + const char * vsFileName = luaL_checkstring(L, 1); + const char * fsFileName = luaL_checkstring(L, 2); + Shader result = LoadShader(vsFileName, fsFileName); + RLUA_PUSH_Resource(L, &result, sizeof(Shader), "Shader"); + return 1; +} + +// Load shader from code strings and bind default locations +static int rl_LoadShaderFromMemory(lua_State *L) +{ + const char * vsCode = luaL_checkstring(L, 1); + const char * fsCode = luaL_checkstring(L, 2); + Shader result = LoadShaderFromMemory(vsCode, fsCode); + RLUA_PUSH_Resource(L, &result, sizeof(Shader), "Shader"); + return 1; +} + +// Check if a shader is valid (loaded on GPU) +static int rl_IsShaderValid(lua_State *L) +{ + Shader shader = *(Shader*)RLUA_CHECK_Resource(L, 1, "Shader"); + bool result = IsShaderValid(shader); + lua_pushboolean(L, result); + return 1; +} + +// Get shader uniform location +static int rl_GetShaderLocation(lua_State *L) +{ + Shader shader = *(Shader*)RLUA_CHECK_Resource(L, 1, "Shader"); + const char * uniformName = luaL_checkstring(L, 2); + int result = GetShaderLocation(shader, uniformName); + lua_pushinteger(L, result); + return 1; +} + +// Get shader attribute location +static int rl_GetShaderLocationAttrib(lua_State *L) +{ + Shader shader = *(Shader*)RLUA_CHECK_Resource(L, 1, "Shader"); + const char * attribName = luaL_checkstring(L, 2); + int result = GetShaderLocationAttrib(shader, attribName); + lua_pushinteger(L, result); + return 1; +} + +// Set shader uniform value +static int rl_SetShaderValue(lua_State *L) +{ + Shader shader = *(Shader*)RLUA_CHECK_Resource(L, 1, "Shader"); + int locIndex = (int)luaL_checkinteger(L, 2); + const void * value = (const void *)lua_touserdata(L, 3); + int uniformType = (int)luaL_checkinteger(L, 4); + SetShaderValue(shader, locIndex, value, uniformType); + return 0; +} + +// Set shader uniform value vector +static int rl_SetShaderValueV(lua_State *L) +{ + Shader shader = *(Shader*)RLUA_CHECK_Resource(L, 1, "Shader"); + int locIndex = (int)luaL_checkinteger(L, 2); + const void * value = (const void *)lua_touserdata(L, 3); + int uniformType = (int)luaL_checkinteger(L, 4); + int count = (int)luaL_checkinteger(L, 5); + SetShaderValueV(shader, locIndex, value, uniformType, count); + return 0; +} + +// Set shader uniform value (matrix 4x4) +static int rl_SetShaderValueMatrix(lua_State *L) +{ + Shader shader = *(Shader*)RLUA_CHECK_Resource(L, 1, "Shader"); + int locIndex = (int)luaL_checkinteger(L, 2); + Matrix mat = RLUA_CHECK_Matrix(L, 3); + SetShaderValueMatrix(shader, locIndex, mat); + return 0; +} + +// Set shader uniform value and bind the texture (sampler2d) +static int rl_SetShaderValueTexture(lua_State *L) +{ + Shader shader = *(Shader*)RLUA_CHECK_Resource(L, 1, "Shader"); + int locIndex = (int)luaL_checkinteger(L, 2); + Texture2D texture = *(Texture2D*)RLUA_CHECK_Resource(L, 3, "Texture2D"); + SetShaderValueTexture(shader, locIndex, texture); + return 0; +} + +// Unload shader from GPU memory (VRAM) +static int rl_UnloadShader(lua_State *L) +{ + Shader shader = *(Shader*)RLUA_CHECK_Resource(L, 1, "Shader"); + UnloadShader(shader); + return 0; +} + +// Get a ray trace from screen position (i.e mouse) +static int rl_GetScreenToWorldRay(lua_State *L) +{ + Vector2 position = RLUA_CHECK_Vector2(L, 1); + Camera camera = RLUA_CHECK_Camera(L, 2); + Ray result = GetScreenToWorldRay(position, camera); + RLUA_PUSH_Ray(L, result); + return 1; +} + +// Get a ray trace from screen position (i.e mouse) in a viewport +static int rl_GetScreenToWorldRayEx(lua_State *L) +{ + Vector2 position = RLUA_CHECK_Vector2(L, 1); + Camera camera = RLUA_CHECK_Camera(L, 2); + int width = (int)luaL_checkinteger(L, 3); + int height = (int)luaL_checkinteger(L, 4); + Ray result = GetScreenToWorldRayEx(position, camera, width, height); + RLUA_PUSH_Ray(L, result); + return 1; +} + +// Get the screen space position for a 3d world space position +static int rl_GetWorldToScreen(lua_State *L) +{ + Vector3 position = RLUA_CHECK_Vector3(L, 1); + Camera camera = RLUA_CHECK_Camera(L, 2); + Vector2 result = GetWorldToScreen(position, camera); + RLUA_PUSH_Vector2(L, result); + return 1; +} + +// Get size position for a 3d world space position +static int rl_GetWorldToScreenEx(lua_State *L) +{ + Vector3 position = RLUA_CHECK_Vector3(L, 1); + Camera camera = RLUA_CHECK_Camera(L, 2); + int width = (int)luaL_checkinteger(L, 3); + int height = (int)luaL_checkinteger(L, 4); + Vector2 result = GetWorldToScreenEx(position, camera, width, height); + RLUA_PUSH_Vector2(L, result); + return 1; +} + +// Get the screen space position for a 2d camera world space position +static int rl_GetWorldToScreen2D(lua_State *L) +{ + Vector2 position = RLUA_CHECK_Vector2(L, 1); + Camera2D camera = RLUA_CHECK_Camera2D(L, 2); + Vector2 result = GetWorldToScreen2D(position, camera); + RLUA_PUSH_Vector2(L, result); + return 1; +} + +// Get the world space position for a 2d camera screen space position +static int rl_GetScreenToWorld2D(lua_State *L) +{ + Vector2 position = RLUA_CHECK_Vector2(L, 1); + Camera2D camera = RLUA_CHECK_Camera2D(L, 2); + Vector2 result = GetScreenToWorld2D(position, camera); + RLUA_PUSH_Vector2(L, result); + return 1; +} + +// Get camera transform matrix (view matrix) +static int rl_GetCameraMatrix(lua_State *L) +{ + Camera camera = RLUA_CHECK_Camera(L, 1); + Matrix result = GetCameraMatrix(camera); + RLUA_PUSH_Matrix(L, result); + return 1; +} + +// Get camera 2d transform matrix +static int rl_GetCameraMatrix2D(lua_State *L) +{ + Camera2D camera = RLUA_CHECK_Camera2D(L, 1); + Matrix result = GetCameraMatrix2D(camera); + RLUA_PUSH_Matrix(L, result); + return 1; +} + +// Timing-related functions +// Set target FPS (maximum) +static int rl_SetTargetFPS(lua_State *L) +{ + int fps = (int)luaL_checkinteger(L, 1); + SetTargetFPS(fps); + return 0; +} + +// Get time in seconds for last frame drawn (delta time) +static int rl_GetFrameTime(lua_State *L) +{ + float result = GetFrameTime(); + lua_pushnumber(L, result); + return 1; +} + +// Get elapsed time in seconds since InitWindow() +static int rl_GetTime(lua_State *L) +{ + double result = GetTime(); + lua_pushnumber(L, result); + return 1; +} + +// Get current FPS +static int rl_GetFPS(lua_State *L) +{ + int result = GetFPS(); + lua_pushinteger(L, result); + return 1; +} + +// Custom frame control functions +// NOTE: Those functions are intended for advanced users that want full control over the frame processing +// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timing + PollInputEvents() +// To avoid that behaviour and control frame processes manually, enable in config.h: SUPPORT_CUSTOM_FRAME_CONTROL +// Swap back buffer with front buffer (screen drawing) +static int rl_SwapScreenBuffer(lua_State *L) +{ + SwapScreenBuffer(); + return 0; +} + +// Register all input events +static int rl_PollInputEvents(lua_State *L) +{ + PollInputEvents(); + return 0; +} + +// Wait for some time (halt program execution) +static int rl_WaitTime(lua_State *L) +{ + double seconds = luaL_checknumber(L, 1); + WaitTime(seconds); + return 0; +} + +// Random values generation functions +// Set the seed for the random number generator +static int rl_SetRandomSeed(lua_State *L) +{ + unsigned int seed = (unsigned int)luaL_checkinteger(L, 1); + SetRandomSeed(seed); + return 0; +} + +// Get a random value between min and max (both included) +static int rl_GetRandomValue(lua_State *L) +{ + int min = (int)luaL_checkinteger(L, 1); + int max = (int)luaL_checkinteger(L, 2); + int result = GetRandomValue(min, max); + lua_pushinteger(L, result); + return 1; +} + +// Load random values sequence, no values repeated +static int rl_LoadRandomSequence(lua_State *L) +{ + unsigned int count = (unsigned int)luaL_checkinteger(L, 1); + int min = (int)luaL_checkinteger(L, 2); + int max = (int)luaL_checkinteger(L, 3); + int * result = LoadRandomSequence(count, min, max); + lua_pushlightuserdata(L, result); + return 1; +} + +// Unload random values sequence +static int rl_UnloadRandomSequence(lua_State *L) +{ + int * sequence = (int *)lua_touserdata(L, 1); + UnloadRandomSequence(sequence); + return 0; +} + +// Misc. functions +// Takes a screenshot of current screen (filename extension defines format) +static int rl_TakeScreenshot(lua_State *L) +{ + const char * fileName = luaL_checkstring(L, 1); + TakeScreenshot(fileName); + return 0; +} + +// Setup init configuration flags (view FLAGS) +static int rl_SetConfigFlags(lua_State *L) +{ + unsigned int flags = (unsigned int)luaL_checkinteger(L, 1); + SetConfigFlags(flags); + return 0; +} + +// Open URL with default system browser (if available) +static int rl_OpenURL(lua_State *L) +{ + const char * url = luaL_checkstring(L, 1); + OpenURL(url); + return 0; +} + +// Logging system +// Set the current threshold (minimum) log level +static int rl_SetTraceLogLevel(lua_State *L) { - lua_newtable(L); + int logLevel = (int)luaL_checkinteger(L, 1); + SetTraceLogLevel(logLevel); + return 0; } -static void LuaSetEnum(const char *name, int value) +// Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...) +static int rl_TraceLog(lua_State *L) { - LuaPush_int(L, value); - lua_setfield(L, -2, name); + int n = lua_gettop(L); + if (n < 2) return luaL_error(L, "TraceLog requires at least 2 arguments"); + int logLevel = (int)luaL_checkinteger(L, 1); + if (n == 2) { + TraceLog(logLevel, "%s", luaL_checkstring(L, 2)); + } else { + lua_getglobal(L, "string"); + lua_getfield(L, -1, "format"); + for (int i = 2; i <= n; i++) lua_pushvalue(L, i); + lua_call(L, n - 1, 1); + TraceLog(logLevel, "%s", lua_tostring(L, -1)); + lua_pop(L, 2); + } + return 0; } -static void LuaSetEnumColor(const char *name, Color color) +// Set custom trace log +static int rl_SetTraceLogCallback(lua_State *L) { - LuaPush_Color(L, color); - lua_setfield(L, -2, name); + if (lua_isnil(L, 1)) { + if (RLUA_LogRef != LUA_REFNIL) { + luaL_unref(L, LUA_REGISTRYINDEX, RLUA_LogRef); + RLUA_LogRef = LUA_REFNIL; + } + SetTraceLogCallback(NULL); + } else { + luaL_checktype(L, 1, LUA_TFUNCTION); + if (RLUA_LogRef != LUA_REFNIL) luaL_unref(L, LUA_REGISTRYINDEX, RLUA_LogRef); + lua_pushvalue(L, 1); + RLUA_LogRef = luaL_ref(L, LUA_REGISTRYINDEX); + SetTraceLogCallback(RLUA_TraceLogTrampoline); + } + return 0; } -static void LuaEndEnum(const char *name) + +// Memory management, using internal allocators +// Internal memory allocator +static int rl_MemAlloc(lua_State *L) { - lua_setglobal(L, name); + unsigned int size = (unsigned int)luaL_checkinteger(L, 1); + void * result = MemAlloc(size); + lua_pushlightuserdata(L, result); + return 1; } -static void LuaPushOpaque(lua_State* L, void *ptr, size_t size) +// Internal memory reallocator +static int rl_MemRealloc(lua_State *L) { - void *ud = lua_newuserdata(L, size); - memcpy(ud, ptr, size); + void * ptr = lua_touserdata(L, 1); + unsigned int size = (unsigned int)luaL_checkinteger(L, 2); + void * result = MemRealloc(ptr, size); + lua_pushlightuserdata(L, result); + return 1; } -static void LuaPushOpaqueWithMetatable(lua_State* L, void *ptr, size_t size, const char *metatable_name) +// Internal memory free +static int rl_MemFree(lua_State *L) { - void *ud = lua_newuserdata(L, size); - memcpy(ud, ptr, size); - luaL_setmetatable(L, metatable_name); + void * ptr = lua_touserdata(L, 1); + MemFree(ptr); + return 0; } -static void* LuaGetArgumentOpaqueType(lua_State* L, int index) +// File system management functions +// Load file data as byte array (read) +static int rl_LoadFileData(lua_State *L) { - return lua_touserdata(L, index); + const char * fileName = luaL_checkstring(L, 1); + int dataSize = 0; + unsigned char * result = LoadFileData(fileName, &dataSize); + RLUA_PUSH_View(L, result, dataSize, "unsigned char", true); + return 1; } -static void* LuaGetArgumentOpaqueTypeWithMetatable(lua_State* L, int index, const char *metatable_name) +// Unload file data allocated by LoadFileData() +static int rl_UnloadFileData(lua_State *L) { - return luaL_checkudata(L, index, metatable_name); + unsigned char * data = (unsigned char *)lua_touserdata(L, 1); + UnloadFileData(data); + return 0; } -//---------------------------------------------------------------------------------- -// LuaIndex* functions -//---------------------------------------------------------------------------------- -static int LuaIndexImage(lua_State* L) +// Save data to file from byte array (write), returns true on success +static int rl_SaveFileData(lua_State *L) { - Image img = LuaGetArgument_Image(L, 1); - const char *key = luaL_checkstring(L, 2); - - if (!strcmp(key, "width")) LuaPush_int(L, img.width); - else if (!strcmp(key, "height")) LuaPush_int(L, img.height); - else if (!strcmp(key, "mipmaps")) LuaPush_int(L, img.mipmaps); - else if (!strcmp(key, "format")) LuaPush_int(L, img.format); - else return 0; - + const char * fileName = luaL_checkstring(L, 1); + void * data = lua_touserdata(L, 2); + int dataSize = (int)luaL_checkinteger(L, 3); + bool result = SaveFileData(fileName, data, dataSize); + lua_pushboolean(L, result); return 1; } -static int LuaIndexTexture2D(lua_State* L) +// Export data to code (.h), returns true on success +static int rl_ExportDataAsCode(lua_State *L) { - Texture2D img = LuaGetArgument_Texture2D(L, 1); - const char *key = luaL_checkstring(L, 2); - - if (!strcmp(key, "width")) LuaPush_int(L, img.width); - else if (!strcmp(key, "height")) LuaPush_int(L, img.height); - else if (!strcmp(key, "mipmaps")) LuaPush_int(L, img.mipmaps); - else if (!strcmp(key, "format")) LuaPush_int(L, img.format); - else if (!strcmp(key, "id")) LuaPush_int(L, img.id); - else return 0; - + const unsigned char * data = (const unsigned char *)lua_touserdata(L, 1); + int dataSize = (int)luaL_checkinteger(L, 2); + const char * fileName = luaL_checkstring(L, 3); + bool result = ExportDataAsCode(data, dataSize, fileName); + lua_pushboolean(L, result); return 1; } -static int LuaIndexRenderTexture2D(lua_State* L) +// Load text data from file (read), returns a '\0' terminated string +static int rl_LoadFileText(lua_State *L) { - RenderTexture2D img = LuaGetArgument_RenderTexture2D(L, 1); - const char *key = luaL_checkstring(L, 2); - - if (!strcmp(key, "texture")) LuaPush_Texture2D(L, img.texture); - else if (!strcmp(key, "depth")) LuaPush_Texture2D(L, img.depth); - else return 0; - + const char * fileName = luaL_checkstring(L, 1); + char * result = LoadFileText(fileName); + lua_pushstring(L, result); return 1; } -static int LuaIndexFont(lua_State* L) +// Unload file text data allocated by LoadFileText() +static int rl_UnloadFileText(lua_State *L) { - Font img = LuaGetArgument_Font(L, 1); - const char *key = luaL_checkstring(L, 2); - - if (!strcmp(key, "baseSize")) LuaPush_int(L, img.baseSize); - else if (!strcmp(key, "texture")) LuaPush_Texture2D(L, img.texture); - else if (!strcmp(key, "charsCount")) LuaPush_int(L, img.charsCount); - else return 0; - + const char * text = luaL_checkstring(L, 1); + UnloadFileText((char *)text); + return 0; +} + +// Save text data to file (write), string must be '\0' terminated, returns true on success +static int rl_SaveFileText(lua_State *L) +{ + const char * fileName = luaL_checkstring(L, 1); + const char * text = luaL_checkstring(L, 2); + bool result = SaveFileText(fileName, text); + lua_pushboolean(L, result); return 1; } -static void LuaBuildOpaqueMetatables(void) +// File access custom callbacks +// WARNING: Callbacks setup is intended for advanced users +// Set custom file binary data loader +static int rl_SetLoadFileDataCallback(lua_State *L) { - luaL_newmetatable(L, "Image"); - lua_pushcfunction(L, &LuaIndexImage); - lua_setfield(L, -2, "__index"); - lua_pop(L, 1); + LoadFileDataCallback callback = (LoadFileDataCallback)lua_touserdata(L, 1); + SetLoadFileDataCallback(callback); + return 0; +} - luaL_newmetatable(L, "Texture2D"); - lua_pushcfunction(L, &LuaIndexTexture2D); - lua_setfield(L, -2, "__index"); - lua_pop(L, 1); +// Set custom file binary data saver +static int rl_SetSaveFileDataCallback(lua_State *L) +{ + SaveFileDataCallback callback = (SaveFileDataCallback)lua_touserdata(L, 1); + SetSaveFileDataCallback(callback); + return 0; +} - luaL_newmetatable(L, "RenderTexture2D"); - lua_pushcfunction(L, &LuaIndexRenderTexture2D); - lua_setfield(L, -2, "__index"); - lua_pop(L, 1); +// Set custom file text data loader +static int rl_SetLoadFileTextCallback(lua_State *L) +{ + LoadFileTextCallback callback = (LoadFileTextCallback)lua_touserdata(L, 1); + SetLoadFileTextCallback(callback); + return 0; +} - luaL_newmetatable(L, "Font"); - lua_pushcfunction(L, &LuaIndexFont); - lua_setfield(L, -2, "__index"); - lua_pop(L, 1); +// Set custom file text data saver +static int rl_SetSaveFileTextCallback(lua_State *L) +{ + SaveFileTextCallback callback = (SaveFileTextCallback)lua_touserdata(L, 1); + SetSaveFileTextCallback(callback); + return 0; } -//---------------------------------------------------------------------------------- -// LuaGetArgument functions -//---------------------------------------------------------------------------------- +// Rename file (if exists) +static int rl_FileRename(lua_State *L) +{ + const char * fileName = luaL_checkstring(L, 1); + const char * fileRename = luaL_checkstring(L, 2); + int result = FileRename(fileName, fileRename); + lua_pushinteger(L, result); + return 1; +} -// Vector2 type -static Vector2 LuaGetArgument_Vector2(lua_State *L, int index) +// Remove file (if exists) +static int rl_FileRemove(lua_State *L) { - Vector2 result = { 0 }; - index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values - luaL_argcheck(L, lua_getfield(L, index, "x") == LUA_TNUMBER, index, "Expected Vector2.x"); - result.x = LuaGetArgument_float(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "y") == LUA_TNUMBER, index, "Expected Vector2.y"); - result.y = LuaGetArgument_float(L, -1); - lua_pop(L, 2); - return result; + const char * fileName = luaL_checkstring(L, 1); + int result = FileRemove(fileName); + lua_pushinteger(L, result); + return 1; } -// Vector3 type -static Vector3 LuaGetArgument_Vector3(lua_State *L, int index) +// Copy file from one path to another, dstPath created if it doesn't exist +static int rl_FileCopy(lua_State *L) { - Vector3 result = { 0 }; - index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values - luaL_argcheck(L, lua_getfield(L, index, "x") == LUA_TNUMBER, index, "Expected Vector3.x"); - result.x = LuaGetArgument_float(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "y") == LUA_TNUMBER, index, "Expected Vector3.y"); - result.y = LuaGetArgument_float(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "z") == LUA_TNUMBER, index, "Expected Vector3.z"); - result.z = LuaGetArgument_float(L, -1); - lua_pop(L, 3); - return result; + const char * srcPath = luaL_checkstring(L, 1); + const char * dstPath = luaL_checkstring(L, 2); + int result = FileCopy(srcPath, dstPath); + lua_pushinteger(L, result); + return 1; } -// Vector4 type -static Vector4 LuaGetArgument_Vector4(lua_State *L, int index) +// Move file from one directory to another, dstPath created if it doesn't exist +static int rl_FileMove(lua_State *L) { - Vector4 result = { 0 }; - index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values - luaL_argcheck(L, lua_getfield(L, index, "x") == LUA_TNUMBER, index, "Expected Vector4.x"); - result.x = LuaGetArgument_float(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "y") == LUA_TNUMBER, index, "Expected Vector4.y"); - result.y = LuaGetArgument_float(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "z") == LUA_TNUMBER, index, "Expected Vector4.z"); - result.z = LuaGetArgument_float(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "w") == LUA_TNUMBER, index, "Expected Vector4.w"); - result.w = LuaGetArgument_float(L, -1); - lua_pop(L, 4); - return result; + const char * srcPath = luaL_checkstring(L, 1); + const char * dstPath = luaL_checkstring(L, 2); + int result = FileMove(srcPath, dstPath); + lua_pushinteger(L, result); + return 1; } -static Quaternion LuaGetArgument_Quaternion(lua_State* L, int index) +// Replace text in an existing file +static int rl_FileTextReplace(lua_State *L) { - Quaternion result = { 0 }; - index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values - luaL_argcheck(L, lua_getfield(L, index, "x") == LUA_TNUMBER, index, "Expected Quaternion.x"); - result.x = LuaGetArgument_float(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "y") == LUA_TNUMBER, index, "Expected Quaternion.y"); - result.y = LuaGetArgument_float(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "z") == LUA_TNUMBER, index, "Expected Quaternion.z"); - result.z = LuaGetArgument_float(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "w") == LUA_TNUMBER, index, "Expected Quaternion.w"); - result.w = LuaGetArgument_float(L, -1); - lua_pop(L, 4); - return result; + const char * fileName = luaL_checkstring(L, 1); + const char * search = luaL_checkstring(L, 2); + const char * replacement = luaL_checkstring(L, 3); + int result = FileTextReplace(fileName, search, replacement); + lua_pushinteger(L, result); + return 1; } -// Matrix type -static Matrix LuaGetArgument_Matrix(lua_State* L, int index) +// Find text in existing file +static int rl_FileTextFindIndex(lua_State *L) { - Matrix result = { 0 }; - float* ptr = &result.m0; - index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values + const char * fileName = luaL_checkstring(L, 1); + const char * search = luaL_checkstring(L, 2); + int result = FileTextFindIndex(fileName, search); + lua_pushinteger(L, result); + return 1; +} - for (int i = 0; i < 16; i++) - { - lua_geti(L, index, i+1); - ptr[i] = luaL_checknumber(L, -1); - } - lua_pop(L, 16); - return result; +// Check if file exists +static int rl_FileExists(lua_State *L) +{ + const char * fileName = luaL_checkstring(L, 1); + bool result = FileExists(fileName); + lua_pushboolean(L, result); + return 1; } -// Color type, RGBA (32bit) -static Color LuaGetArgument_Color(lua_State *L, int index) +// Check if a directory path exists +static int rl_DirectoryExists(lua_State *L) { - Color result = { 0 }; - index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values - luaL_argcheck(L, lua_getfield(L, index, "r") == LUA_TNUMBER, index, "Expected Color.r"); - result.r = LuaGetArgument_unsigned(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "g") == LUA_TNUMBER, index, "Expected Color.g"); - result.g = LuaGetArgument_unsigned(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "b") == LUA_TNUMBER, index, "Expected Color.b"); - result.b = LuaGetArgument_unsigned(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "a") == LUA_TNUMBER, index, "Expected Color.a"); - result.a = LuaGetArgument_unsigned(L, -1); - lua_pop(L, 4); - return result; + const char * dirPath = luaL_checkstring(L, 1); + bool result = DirectoryExists(dirPath); + lua_pushboolean(L, result); + return 1; } -// Rectangle type -static Rectangle LuaGetArgument_Rectangle(lua_State *L, int index) +// Check file extension (recommended include point: .png, .wav) +static int rl_IsFileExtension(lua_State *L) { - Rectangle result = { 0 }; - index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values - luaL_argcheck(L, lua_getfield(L, index, "x") == LUA_TNUMBER, index, "Expected Rectangle.x"); - result.x = LuaGetArgument_float(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "y") == LUA_TNUMBER, index, "Expected Rectangle.y"); - result.y = LuaGetArgument_float(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "width") == LUA_TNUMBER, index, "Expected Rectangle.width"); - result.width = LuaGetArgument_float(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "height") == LUA_TNUMBER, index, "Expected Rectangle.height"); - result.height = LuaGetArgument_float(L, -1); - lua_pop(L, 4); - return result; + const char * fileName = luaL_checkstring(L, 1); + const char * ext = luaL_checkstring(L, 2); + bool result = IsFileExtension(fileName, ext); + lua_pushboolean(L, result); + return 1; } -// Image type -> Opaque +// Get file length in bytes (NOTE: GetFileSize() conflicts with windows.h) +static int rl_GetFileLength(lua_State *L) +{ + const char * fileName = luaL_checkstring(L, 1); + int result = GetFileLength(fileName); + lua_pushinteger(L, result); + return 1; +} -// Texture2D type -> Opaque +// Get file modification time (last write time) +static int rl_GetFileModTime(lua_State *L) +{ + const char * fileName = luaL_checkstring(L, 1); + long result = GetFileModTime(fileName); + lua_pushinteger(L, result); + return 1; +} -// RenderTexture2D type -> Opaque +// Get pointer to extension for a filename string (includes dot: '.png') +static int rl_GetFileExtension(lua_State *L) +{ + const char * fileName = luaL_checkstring(L, 1); + const char * result = GetFileExtension(fileName); + lua_pushstring(L, result); + return 1; +} -// Font character info type -static CharInfo LuaGetArgument_CharInfo(lua_State *L, int index) +// Get pointer to filename for a path string +static int rl_GetFileName(lua_State *L) { - CharInfo result = { 0 }; - index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values - luaL_argcheck(L, lua_getfield(L, index, "value") == LUA_TNUMBER, index, "Expected CharInfo.value"); - result.value = LuaGetArgument_int(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "rec") == LUA_TNUMBER, index, "Expected CharInfo.rec"); - result.rec = LuaGetArgument_Rectangle(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "offsetX") == LUA_TNUMBER, index, "Expected CharInfo.offsetX"); - result.offsetX = LuaGetArgument_int(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "offsetY") == LUA_TNUMBER, index, "Expected CharInfo.offsetY"); - result.offsetY = LuaGetArgument_int(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "advanceX") == LUA_TNUMBER, index, "Expected CharInfo.advanceX"); - result.advanceX = LuaGetArgument_int(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "char *data") == LUA_TNUMBER, index, "Expected CharInfo.char *data"); - result.char *data = LuaGetArgument_unsigned(L, -1); - lua_pop(L, 6); - return result; + const char * filePath = luaL_checkstring(L, 1); + const char * result = GetFileName(filePath); + lua_pushstring(L, result); + return 1; } -// Font type -> Opaque - -// Camera type, defines a camera position/orientation in 3d space -static Camera LuaGetArgument_Camera(lua_State *L, int index) -{ - Camera result = { 0 }; - index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values - luaL_argcheck(L, lua_getfield(L, index, "position") == LUA_TNUMBER, index, "Expected Camera.position"); - result.position = LuaGetArgument_Vector3(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "target") == LUA_TNUMBER, index, "Expected Camera.target"); - result.target = LuaGetArgument_Vector3(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "up") == LUA_TNUMBER, index, "Expected Camera.up"); - result.up = LuaGetArgument_Vector3(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "fovy") == LUA_TNUMBER, index, "Expected Camera.fovy"); - result.fovy = LuaGetArgument_float(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "type") == LUA_TNUMBER, index, "Expected Camera.type"); - result.type = LuaGetArgument_int(L, -1); - lua_pop(L, 5); - return result; +// Get filename string without extension (uses static string) +static int rl_GetFileNameWithoutExt(lua_State *L) +{ + const char * filePath = luaL_checkstring(L, 1); + const char * result = GetFileNameWithoutExt(filePath); + lua_pushstring(L, result); + return 1; } -// Camera2D type, defines a 2d camera -static Camera2D LuaGetArgument_Camera2D(lua_State *L, int index) +// Get full path for a given fileName with path (uses static string) +static int rl_GetDirectoryPath(lua_State *L) { - Camera2D result = { 0 }; - index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values - luaL_argcheck(L, lua_getfield(L, index, "offset") == LUA_TNUMBER, index, "Expected Camera2D.offset"); - result.offset = LuaGetArgument_Vector2(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "target") == LUA_TNUMBER, index, "Expected Camera2D.target"); - result.target = LuaGetArgument_Vector2(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "rotation") == LUA_TNUMBER, index, "Expected Camera2D.rotation"); - result.rotation = LuaGetArgument_float(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "zoom") == LUA_TNUMBER, index, "Expected Camera2D.zoom"); - result.zoom = LuaGetArgument_float(L, -1); - lua_pop(L, 4); - return result; + const char * filePath = luaL_checkstring(L, 1); + const char * result = GetDirectoryPath(filePath); + lua_pushstring(L, result); + return 1; } -// Bounding box type -static BoundingBox LuaGetArgument_BoundingBox(lua_State *L, int index) +// Get previous directory path for a given path (uses static string) +static int rl_GetPrevDirectoryPath(lua_State *L) { - BoundingBox result = { 0 }; - index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values - luaL_argcheck(L, lua_getfield(L, index, "min") == LUA_TNUMBER, index, "Expected BoundingBox.min"); - result.min = LuaGetArgument_Vector3(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "max") == LUA_TNUMBER, index, "Expected BoundingBox.max"); - result.max = LuaGetArgument_Vector3(L, -1); - lua_pop(L, 2); - return result; + const char * dirPath = luaL_checkstring(L, 1); + const char * result = GetPrevDirectoryPath(dirPath); + lua_pushstring(L, result); + return 1; } -// Mesh type -> Opaque +// Get current working directory (uses static string) +static int rl_GetWorkingDirectory(lua_State *L) +{ + const char * result = GetWorkingDirectory(); + lua_pushstring(L, result); + return 1; +} -// Shader type -> Opaque +// Get the directory of the running application (uses static string) +static int rl_GetApplicationDirectory(lua_State *L) +{ + const char * result = GetApplicationDirectory(); + lua_pushstring(L, result); + return 1; +} -// Material texture map -static MaterialMap LuaGetArgument_MaterialMap(lua_State *L, int index) +// Create directories (including full path requested), returns 0 on success +static int rl_MakeDirectory(lua_State *L) { - MaterialMap result = { 0 }; - index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values - luaL_argcheck(L, lua_getfield(L, index, "texture") == LUA_TNUMBER, index, "Expected MaterialMap.texture"); - result.texture = LuaGetArgument_Texture2D(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "color") == LUA_TNUMBER, index, "Expected MaterialMap.color"); - result.color = LuaGetArgument_Color(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "value") == LUA_TNUMBER, index, "Expected MaterialMap.value"); - result.value = LuaGetArgument_float(L, -1); - lua_pop(L, 3); - return result; + const char * dirPath = luaL_checkstring(L, 1); + int result = MakeDirectory(dirPath); + lua_pushinteger(L, result); + return 1; } -// Material type -> REVIEW -/* -static Material LuaGetArgument_Material(lua_State *L, int index) +// Change working directory, return true on success +static int rl_ChangeDirectory(lua_State *L) { - Material result = { 0 }; - index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values - luaL_argcheck(L, lua_getfield(L, index, "shader") == LUA_TNUMBER, index, "Expected Material.shader"); - result.shader = LuaGetArgument_Shader(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "maps[MAX_MATERIAL_MAPS]") == LUA_TNUMBER, index, "Expected Material.maps[MAX_MATERIAL_MAPS]"); - result.maps[MAX_MATERIAL_MAPS] = LuaGetArgument_MaterialMap(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "*params") == LUA_TNUMBER, index, "Expected Material.*params"); - result.*params = LuaGetArgument_float(L, -1); - lua_pop(L, 3); - return result; + const char * dirPath = luaL_checkstring(L, 1); + bool result = ChangeDirectory(dirPath); + lua_pushboolean(L, result); + return 1; } -static Material LuaGetArgument_Material(lua_State* L, int index) -{ - Material result; - index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values - luaL_argcheck(L, lua_getfield(L, index, "shader") == LUA_TUSERDATA, index, "Expected Material"); - result.shader = LuaGetArgument_Shader(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "texDiffuse") == LUA_TUSERDATA, index, "Expected Material"); - result.texDiffuse = LuaGetArgument_Texture2D(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "texNormal") == LUA_TUSERDATA, index, "Expected Material"); - result.texNormal = LuaGetArgument_Texture2D(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "texSpecular") == LUA_TUSERDATA, index, "Expected Material"); - result.texSpecular = LuaGetArgument_Texture2D(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "colDiffuse") == LUA_TTABLE, index, "Expected Material"); - result.colDiffuse = LuaGetArgument_Color(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "colAmbient") == LUA_TTABLE, index, "Expected Material"); - result.colAmbient = LuaGetArgument_Color(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "colSpecular") == LUA_TTABLE, index, "Expected Material"); - result.colSpecular = LuaGetArgument_Color(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "glossiness") == LUA_TNUMBER, index, "Expected Material"); - result.glossiness = LuaGetArgument_float(L, -1); - lua_pop(L, 8); - return result; +// Check if a given path is a file or a directory +static int rl_IsPathFile(lua_State *L) +{ + const char * path = luaL_checkstring(L, 1); + bool result = IsPathFile(path); + lua_pushboolean(L, result); + return 1; } -*/ -// Model type -static Model LuaGetArgument_Model(lua_State *L, int index) +// Check if fileName is valid for the platform/OS +static int rl_IsFileNameValid(lua_State *L) { - Model result = { 0 }; - index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values - luaL_argcheck(L, lua_getfield(L, index, "mesh") == LUA_TNUMBER, index, "Expected Model.mesh"); - result.mesh = LuaGetArgument_Mesh(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "transform") == LUA_TNUMBER, index, "Expected Model.transform"); - result.transform = LuaGetArgument_Matrix(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "material") == LUA_TNUMBER, index, "Expected Model.material"); - result.material = LuaGetArgument_Material(L, -1); - lua_pop(L, 3); - return result; + const char * fileName = luaL_checkstring(L, 1); + bool result = IsFileNameValid(fileName); + lua_pushboolean(L, result); + return 1; } -// Ray type (useful for raycast) -static Ray LuaGetArgument_Ray(lua_State *L, int index) +// Load directory filepaths, files and directories, no subdirs scan +static int rl_LoadDirectoryFiles(lua_State *L) { - Ray result = { 0 }; - index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values - luaL_argcheck(L, lua_getfield(L, index, "position") == LUA_TNUMBER, index, "Expected Ray.position"); - result.position = LuaGetArgument_Vector3(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "direction") == LUA_TNUMBER, index, "Expected Ray.direction"); - result.direction = LuaGetArgument_Vector3(L, -1); - lua_pop(L, 2); - return result; + const char * dirPath = luaL_checkstring(L, 1); + FilePathList result = LoadDirectoryFiles(dirPath); + RLUA_PUSH_FilePathList(L, result); + return 1; } -// Raycast hit information -static RayHitInfo LuaGetArgument_RayHitInfo(lua_State *L, int index) -{ - RayHitInfo result = { 0 }; - index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values - luaL_argcheck(L, lua_getfield(L, index, "hit") == LUA_TNUMBER, index, "Expected RayHitInfo.hit"); - result.hit = LuaGetArgument_bool(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "distance") == LUA_TNUMBER, index, "Expected RayHitInfo.distance"); - result.distance = LuaGetArgument_float(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "position") == LUA_TNUMBER, index, "Expected RayHitInfo.position"); - result.position = LuaGetArgument_Vector3(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "normal") == LUA_TNUMBER, index, "Expected RayHitInfo.normal"); - result.normal = LuaGetArgument_Vector3(L, -1); - lua_pop(L, 4); - return result; +// Load directory filepaths with extension filtering and subdir scan; some filters available: "*.*", "FILES*", "DIRS*" +static int rl_LoadDirectoryFilesEx(lua_State *L) +{ + const char * basePath = luaL_checkstring(L, 1); + const char * filter = luaL_checkstring(L, 2); + bool scanSubdirs = lua_toboolean(L, 3); + FilePathList result = LoadDirectoryFilesEx(basePath, filter, scanSubdirs); + RLUA_PUSH_FilePathList(L, result); + return 1; } -// Wave type -> Opaque +// Unload filepaths +static int rl_UnloadDirectoryFiles(lua_State *L) +{ + FilePathList files = RLUA_CHECK_FilePathList(L, 1); + UnloadDirectoryFiles(files); + return 0; +} -// Sound type -> Opaque +// Check if a file has been dropped into window +static int rl_IsFileDropped(lua_State *L) +{ + bool result = IsFileDropped(); + lua_pushboolean(L, result); + return 1; +} -// MusicData type -> Opaque +// Load dropped filepaths +static int rl_LoadDroppedFiles(lua_State *L) +{ + FilePathList result = LoadDroppedFiles(); + RLUA_PUSH_FilePathList(L, result); + return 1; +} -// Head-Mounted-Display device parameters -static VrDeviceInfo LuaGetArgument_VrDeviceInfo(lua_State *L, int index) +// Unload dropped filepaths +static int rl_UnloadDroppedFiles(lua_State *L) { - VrDeviceInfo result = { 0 }; - index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values - luaL_argcheck(L, lua_getfield(L, index, "hResolution") == LUA_TNUMBER, index, "Expected VrDeviceInfo.hResolution"); - result.hResolution = LuaGetArgument_int(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "vResolution") == LUA_TNUMBER, index, "Expected VrDeviceInfo.vResolution"); - result.vResolution = LuaGetArgument_int(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "hScreenSize") == LUA_TNUMBER, index, "Expected VrDeviceInfo.hScreenSize"); - result.hScreenSize = LuaGetArgument_float(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "vScreenSize") == LUA_TNUMBER, index, "Expected VrDeviceInfo.vScreenSize"); - result.vScreenSize = LuaGetArgument_float(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "vScreenCenter") == LUA_TNUMBER, index, "Expected VrDeviceInfo.vScreenCenter"); - result.vScreenCenter = LuaGetArgument_float(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "eyeToScreenDistance") == LUA_TNUMBER, index, "Expected VrDeviceInfo.eyeToScreenDistance"); - result.eyeToScreenDistance = LuaGetArgument_float(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "lensSeparationDistance") == LUA_TNUMBER, index, "Expected VrDeviceInfo.lensSeparationDistance"); - result.lensSeparationDistance = LuaGetArgument_float(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "interpupillaryDistance") == LUA_TNUMBER, index, "Expected VrDeviceInfo.interpupillaryDistance"); - result.interpupillaryDistance = LuaGetArgument_float(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "lensDistortionValues[4]") == LUA_TNUMBER, index, "Expected VrDeviceInfo.lensDistortionValues[4]"); - result.lensDistortionValues[4] = LuaGetArgument_float(L, -1); - luaL_argcheck(L, lua_getfield(L, index, "chromaAbCorrection[4]") == LUA_TNUMBER, index, "Expected VrDeviceInfo.chromaAbCorrection[4]"); - result.chromaAbCorrection[4] = LuaGetArgument_float(L, -1); - lua_pop(L, 10); - return result; + FilePathList files = RLUA_CHECK_FilePathList(L, 1); + UnloadDroppedFiles(files); + return 0; } -//---------------------------------------------------------------------------------- -// LuaPush functions -//---------------------------------------------------------------------------------- -static void LuaPush_Color(lua_State* L, Color color) +// Get the file count in a directory +static int rl_GetDirectoryFileCount(lua_State *L) { - lua_createtable(L, 0, 4); - LuaPush_int(L, color.r); - lua_setfield(L, -2, "r"); - LuaPush_int(L, color.g); - lua_setfield(L, -2, "g"); - LuaPush_int(L, color.b); - lua_setfield(L, -2, "b"); - LuaPush_int(L, color.a); - lua_setfield(L, -2, "a"); + const char * dirPath = luaL_checkstring(L, 1); + unsigned int result = GetDirectoryFileCount(dirPath); + lua_pushinteger(L, result); + return 1; } -static void LuaPush_Vector2(lua_State* L, Vector2 vec) +// Get the file count in a directory with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result +static int rl_GetDirectoryFileCountEx(lua_State *L) { - lua_createtable(L, 0, 2); - LuaPush_float(L, vec.x); - lua_setfield(L, -2, "x"); - LuaPush_float(L, vec.y); - lua_setfield(L, -2, "y"); + const char * basePath = luaL_checkstring(L, 1); + const char * filter = luaL_checkstring(L, 2); + bool scanSubdirs = lua_toboolean(L, 3); + unsigned int result = GetDirectoryFileCountEx(basePath, filter, scanSubdirs); + lua_pushinteger(L, result); + return 1; } -static void LuaPush_Vector3(lua_State* L, Vector3 vec) +// Compression/Encoding functionality +// Compress data (DEFLATE algorithm), memory must be MemFree() +static int rl_CompressData(lua_State *L) { - lua_createtable(L, 0, 3); - LuaPush_float(L, vec.x); - lua_setfield(L, -2, "x"); - LuaPush_float(L, vec.y); - lua_setfield(L, -2, "y"); - LuaPush_float(L, vec.z); - lua_setfield(L, -2, "z"); + const unsigned char * data = (const unsigned char *)lua_touserdata(L, 1); + int dataSize = (int)luaL_checkinteger(L, 2); + int compDataSize = 0; + unsigned char * result = CompressData(data, dataSize, &compDataSize); + RLUA_PUSH_View(L, result, compDataSize, "unsigned char", true); + return 1; } -static void LuaPush_Vector4(lua_State* L, Vector4 vec) +// Decompress data (DEFLATE algorithm), memory must be MemFree() +static int rl_DecompressData(lua_State *L) { - lua_createtable(L, 0, 4); - LuaPush_float(L, vec.x); - lua_setfield(L, -2, "x"); - LuaPush_float(L, vec.y); - lua_setfield(L, -2, "y"); - LuaPush_float(L, vec.z); - lua_setfield(L, -2, "z"); - LuaPush_float(L, vec.w); - lua_setfield(L, -2, "w"); + const unsigned char * compData = (const unsigned char *)lua_touserdata(L, 1); + int compDataSize = (int)luaL_checkinteger(L, 2); + int dataSize = 0; + unsigned char * result = DecompressData(compData, compDataSize, &dataSize); + RLUA_PUSH_View(L, result, dataSize, "unsigned char", true); + return 1; } -static void LuaPush_Quaternion(lua_State* L, Quaternion vec) +// Encode data to Base64 string (includes NULL terminator), memory must be MemFree() +static int rl_EncodeDataBase64(lua_State *L) { - lua_createtable(L, 0, 4); - LuaPush_float(L, vec.x); - lua_setfield(L, -2, "x"); - LuaPush_float(L, vec.y); - lua_setfield(L, -2, "y"); - LuaPush_float(L, vec.z); - lua_setfield(L, -2, "z"); - LuaPush_float(L, vec.w); - lua_setfield(L, -2, "w"); + const unsigned char * data = (const unsigned char *)lua_touserdata(L, 1); + int dataSize = (int)luaL_checkinteger(L, 2); + int outputSize = 0; + char * result = EncodeDataBase64(data, dataSize, &outputSize); + RLUA_PUSH_View(L, result, outputSize, "char", true); + return 1; } -static void LuaPush_Matrix(lua_State* L, Matrix *matrix) +// Decode Base64 string (expected NULL terminated), memory must be MemFree() +static int rl_DecodeDataBase64(lua_State *L) { - int i; - lua_createtable(L, 16, 0); - float* num = (&matrix->m0); - for (i = 0; i < 16; i++) - { - LuaPush_float(L, num[i]); - lua_rawseti(L, -2, i + 1); - } + const char * text = luaL_checkstring(L, 1); + int outputSize = 0; + unsigned char * result = DecodeDataBase64(text, &outputSize); + RLUA_PUSH_View(L, result, outputSize, "unsigned char", true); + return 1; } -static void LuaPush_Rectangle(lua_State* L, Rectangle rect) +// Compute CRC32 hash code +static int rl_ComputeCRC32(lua_State *L) { - lua_createtable(L, 0, 4); - LuaPush_int(L, rect.x); - lua_setfield(L, -2, "x"); - LuaPush_int(L, rect.y); - lua_setfield(L, -2, "y"); - LuaPush_int(L, rect.width); - lua_setfield(L, -2, "width"); - LuaPush_int(L, rect.height); - lua_setfield(L, -2, "height"); + unsigned char * data = (unsigned char *)lua_touserdata(L, 1); + int dataSize = (int)luaL_checkinteger(L, 2); + unsigned int result = ComputeCRC32(data, dataSize); + lua_pushinteger(L, result); + return 1; } -static void LuaPush_Ray(lua_State* L, Ray ray) +// Compute MD5 hash code, returns static int[4] (16 bytes) +static int rl_ComputeMD5(lua_State *L) { - lua_createtable(L, 0, 2); - LuaPush_Vector3(L, ray.position); - lua_setfield(L, -2, "position"); - LuaPush_Vector3(L, ray.direction); - lua_setfield(L, -2, "direction"); + unsigned char * data = (unsigned char *)lua_touserdata(L, 1); + int dataSize = (int)luaL_checkinteger(L, 2); + unsigned int * result = ComputeMD5(data, dataSize); + lua_pushlightuserdata(L, result); + return 1; } -static void LuaPush_RayHitInfo(lua_State* L, RayHitInfo hit) +// Compute SHA1 hash code, returns static int[5] (20 bytes) +static int rl_ComputeSHA1(lua_State *L) { - lua_createtable(L, 0, 4); - LuaPush_int(L, hit.hit); - lua_setfield(L, -2, "hit"); - LuaPush_float(L, hit.distance); - lua_setfield(L, -2, "distance"); - LuaPush_Vector3(L, hit.position); - lua_setfield(L, -2, "position"); - LuaPush_Vector3(L, hit.normal); - lua_setfield(L, -2, "normal"); + unsigned char * data = (unsigned char *)lua_touserdata(L, 1); + int dataSize = (int)luaL_checkinteger(L, 2); + unsigned int * result = ComputeSHA1(data, dataSize); + lua_pushlightuserdata(L, result); + return 1; } -static void LuaPush_BoundingBox(lua_State* L, BoundingBox bb) +// Compute SHA256 hash code, returns static int[8] (32 bytes) +static int rl_ComputeSHA256(lua_State *L) { - lua_createtable(L, 0, 2); - LuaPush_Vector3(L, bb.min); - lua_setfield(L, -2, "min"); - LuaPush_Vector3(L, bb.max); - lua_setfield(L, -2, "max"); + unsigned char * data = (unsigned char *)lua_touserdata(L, 1); + int dataSize = (int)luaL_checkinteger(L, 2); + unsigned int * result = ComputeSHA256(data, dataSize); + lua_pushlightuserdata(L, result); + return 1; } -static void LuaPush_Camera(lua_State* L, Camera cam) +// Automation events functionality +// Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS +static int rl_LoadAutomationEventList(lua_State *L) { - lua_createtable(L, 0, 4); - LuaPush_Vector3(L, cam.position); - lua_setfield(L, -2, "position"); - LuaPush_Vector3(L, cam.target); - lua_setfield(L, -2, "target"); - LuaPush_Vector3(L, cam.up); - lua_setfield(L, -2, "up"); - LuaPush_float(L, cam.fovy); - lua_setfield(L, -2, "fovy"); + const char * fileName = luaL_checkstring(L, 1); + AutomationEventList result = LoadAutomationEventList(fileName); + RLUA_PUSH_AutomationEventList(L, result); + return 1; } -static void LuaPush_Camera2D(lua_State* L, Camera2D cam) +// Unload automation events list from file +static int rl_UnloadAutomationEventList(lua_State *L) { - lua_createtable(L, 0, 4); - LuaPush_Vector2(L, cam.offset); - lua_setfield(L, -2, "offset"); - LuaPush_Vector2(L, cam.target); - lua_setfield(L, -2, "target"); - LuaPush_float(L, cam.rotation); - lua_setfield(L, -2, "rotation"); - LuaPush_float(L, cam.zoom); - lua_setfield(L, -2, "zoom"); + AutomationEventList list = RLUA_CHECK_AutomationEventList(L, 1); + UnloadAutomationEventList(list); + return 0; } -// REVIEW!!! -/* -static void LuaPush_Material(lua_State* L, Material mat) +// Export automation events list as text file +static int rl_ExportAutomationEventList(lua_State *L) { - lua_createtable(L, 0, 8); - LuaPush_Shader(L, mat.shader); - lua_setfield(L, -2, "shader"); - LuaPush_Texture2D(L, mat.texDiffuse); - lua_setfield(L, -2, "texDiffuse"); - LuaPush_Texture2D(L, mat.texNormal); - lua_setfield(L, -2, "texNormal"); - LuaPush_Texture2D(L, mat.texSpecular); - lua_setfield(L, -2, "texSpecular"); - LuaPush_Color(L, mat.colDiffuse); - lua_setfield(L, -2, "colDiffuse"); - LuaPush_Color(L, mat.colAmbient); - lua_setfield(L, -2, "colAmbient"); - LuaPush_Color(L, mat.colSpecular); - lua_setfield(L, -2, "colSpecular"); - LuaPush_float(L, mat.glossiness); - lua_setfield(L, -2, "glossiness"); -} -*/ - -static void LuaPush_Model(lua_State* L, Model mdl) + AutomationEventList list = RLUA_CHECK_AutomationEventList(L, 1); + const char * fileName = luaL_checkstring(L, 2); + bool result = ExportAutomationEventList(list, fileName); + lua_pushboolean(L, result); + return 1; +} + +// Set automation event list to record to +static int rl_SetAutomationEventList(lua_State *L) { - lua_createtable(L, 0, 3); - LuaPush_Mesh(L, mdl.mesh); - lua_setfield(L, -2, "mesh"); - LuaPush_Matrix(L, &mdl.transform); - lua_setfield(L, -2, "transform"); - LuaPush_Material(L, mdl.material); - lua_setfield(L, -2, "material"); + AutomationEventList list = RLUA_CHECK_AutomationEventList(L, 1); + SetAutomationEventList(&list); + RLUA_WRITEBACK_AutomationEventList(L, 1, list); + return 0; } -//---------------------------------------------------------------------------------- -// raylib Lua Structure constructors -//---------------------------------------------------------------------------------- -static int lua_Color(lua_State* L) +// Set automation event internal base frame to start recording +static int rl_SetAutomationEventBaseFrame(lua_State *L) { - LuaPush_Color(L, (Color) { (unsigned char)luaL_checkinteger(L, 1), (unsigned char)luaL_checkinteger(L, 2), (unsigned char)luaL_checkinteger(L, 3), (unsigned char)luaL_checkinteger(L, 4) }); - return 1; + int frame = (int)luaL_checkinteger(L, 1); + SetAutomationEventBaseFrame(frame); + return 0; } -static int lua_Vector2(lua_State* L) +// Start recording automation events (AutomationEventList must be set) +static int rl_StartAutomationEventRecording(lua_State *L) { - LuaPush_Vector2(L, (Vector2) { (float)luaL_checknumber(L, 1), (float)luaL_checknumber(L, 2) }); - return 1; + StartAutomationEventRecording(); + return 0; } -static int lua_Vector3(lua_State* L) +// Stop recording automation events +static int rl_StopAutomationEventRecording(lua_State *L) { - LuaPush_Vector3(L, (Vector3) { (float)luaL_checknumber(L, 1), (float)luaL_checknumber(L, 2), (float)luaL_checknumber(L, 3) }); - return 1; + StopAutomationEventRecording(); + return 0; } -static int lua_Vector4(lua_State* L) +// Play a recorded automation event +static int rl_PlayAutomationEvent(lua_State *L) { - LuaPush_Vector4(L, (Vector4) { (float)luaL_checknumber(L, 1), (float)luaL_checknumber(L, 2), (float)luaL_checknumber(L, 3), (float)luaL_checknumber(L, 4) }); - return 1; + AutomationEvent event = RLUA_CHECK_AutomationEvent(L, 1); + PlayAutomationEvent(event); + return 0; } -static int lua_Quaternion(lua_State* L) +// ------------------------------------------------------------------------------------ +// Input Handling Functions (Module: core) +// ------------------------------------------------------------------------------------ +// Input-related functions: keyboard +// Check if a key has been pressed once +static int rl_IsKeyPressed(lua_State *L) { - LuaPush_Quaternion(L, (Quaternion) { (float)luaL_checknumber(L, 1), (float)luaL_checknumber(L, 2), (float)luaL_checknumber(L, 3), (float)luaL_checknumber(L, 4) }); + int key = (int)luaL_checkinteger(L, 1); + bool result = IsKeyPressed(key); + lua_pushboolean(L, result); return 1; } -static int lua_Rectangle(lua_State* L) +// Check if a key has been pressed again +static int rl_IsKeyPressedRepeat(lua_State *L) { - LuaPush_Rectangle(L, (Rectangle) { (float)luaL_checknumber(L, 1), (float)luaL_checknumber(L, 2), (float)luaL_checknumber(L, 3), (float)luaL_checknumber(L, 4) }); + int key = (int)luaL_checkinteger(L, 1); + bool result = IsKeyPressedRepeat(key); + lua_pushboolean(L, result); return 1; } -static int lua_Ray(lua_State* L) +// Check if a key is being pressed +static int rl_IsKeyDown(lua_State *L) { - Vector3 pos = LuaGetArgument_Vector3(L, 1); - Vector3 dir = LuaGetArgument_Vector3(L, 2); - LuaPush_Ray(L, (Ray) { { pos.x, pos.y, pos.z }, { dir.x, dir.y, dir.z } }); + int key = (int)luaL_checkinteger(L, 1); + bool result = IsKeyDown(key); + lua_pushboolean(L, result); return 1; } -static int lua_RayHitInfo(lua_State* L) +// Check if a key has been released once +static int rl_IsKeyReleased(lua_State *L) { - int hit = LuaGetArgument_int(L, 1); - float dis = LuaGetArgument_float(L, 2); - Vector3 pos = LuaGetArgument_Vector3(L, 3); - Vector3 norm = LuaGetArgument_Vector3(L, 4); - LuaPush_RayHitInfo(L, (RayHitInfo) { hit, dis, { pos.x, pos.y, pos.z }, { norm.x, norm.y, norm.z } }); + int key = (int)luaL_checkinteger(L, 1); + bool result = IsKeyReleased(key); + lua_pushboolean(L, result); return 1; } -static int lua_BoundingBox(lua_State* L) +// Check if a key is NOT being pressed +static int rl_IsKeyUp(lua_State *L) { - Vector3 min = LuaGetArgument_Vector3(L, 1); - Vector3 max = LuaGetArgument_Vector3(L, 2); - LuaPush_BoundingBox(L, (BoundingBox) { { min.x, min.y, min.z }, { max.x, max.y, max.z } }); + int key = (int)luaL_checkinteger(L, 1); + bool result = IsKeyUp(key); + lua_pushboolean(L, result); return 1; } -static int lua_Camera(lua_State* L) +// Get key pressed (keycode), call it multiple times for keys queued, returns 0 when the queue is empty +static int rl_GetKeyPressed(lua_State *L) { - Vector3 pos = LuaGetArgument_Vector3(L, 1); - Vector3 tar = LuaGetArgument_Vector3(L, 2); - Vector3 up = LuaGetArgument_Vector3(L, 3); - float fovy = LuaGetArgument_float(L, 4); - LuaPush_Camera(L, (Camera) { { pos.x, pos.y, pos.z }, { tar.x, tar.y, tar.z }, { up.x, up.y, up.z }, fovy }); + int result = GetKeyPressed(); + lua_pushinteger(L, result); return 1; } -static int lua_Camera2D(lua_State* L) +// Get char pressed (unicode), call it multiple times for chars queued, returns 0 when the queue is empty +static int rl_GetCharPressed(lua_State *L) { - Vector2 off = LuaGetArgument_Vector2(L, 1); - Vector2 tar = LuaGetArgument_Vector2(L, 2); - float rot = LuaGetArgument_float(L, 3); - float zoom = LuaGetArgument_float(L, 4); - LuaPush_Camera2D(L, (Camera2D) { { off.x, off.y }, { tar.x, tar.y }, rot, zoom }); + int result = GetCharPressed(); + lua_pushinteger(L, result); return 1; } -/************************************************************************************* -* -* raylib Lua Functions Bindings -* -**************************************************************************************/ - -//------------------------------------------------------------------------------------ -// raylib [core] module functions - Window and Graphics Device -//------------------------------------------------------------------------------------ - -// Initialize window and OpenGL context -int lua_InitWindow(lua_State *L) +// Get name of a QWERTY key on the current keyboard layout (eg returns string 'q' for KEY_A on an AZERTY keyboard) +static int rl_GetKeyName(lua_State *L) { - int width = LuaGetArgument_int(L, 1); - int height = LuaGetArgument_int(L, 2); - const char *title = LuaGetArgument_string(L, 3); - InitWindow(width, height, title); - return 0; + int key = (int)luaL_checkinteger(L, 1); + const char * result = GetKeyName(key); + lua_pushstring(L, result); + return 1; } -// Close window and unload OpenGL context -int lua_CloseWindow(lua_State *L) +// Set a custom key to exit program (default is ESC) +static int rl_SetExitKey(lua_State *L) { - CloseWindow(); + int key = (int)luaL_checkinteger(L, 1); + SetExitKey(key); return 0; } -// Check if window has been initialized successfully -int lua_IsWindowReady(lua_State *L) +// Input-related functions: gamepads +// Check if a gamepad is available +static int rl_IsGamepadAvailable(lua_State *L) { - bool result = IsWindowReady(); - LuaPush_bool(L, result); + int gamepad = (int)luaL_checkinteger(L, 1); + bool result = IsGamepadAvailable(gamepad); + lua_pushboolean(L, result); return 1; } -// Check if KEY_ESCAPE pressed or Close icon pressed -int lua_WindowShouldClose(lua_State *L) +// Get gamepad internal name id +static int rl_GetGamepadName(lua_State *L) { - bool result = WindowShouldClose(); - LuaPush_bool(L, result); + int gamepad = (int)luaL_checkinteger(L, 1); + const char * result = GetGamepadName(gamepad); + lua_pushstring(L, result); return 1; } -// Check if window has been minimized (or lost focus) -int lua_IsWindowMinimized(lua_State *L) +// Check if a gamepad button has been pressed once +static int rl_IsGamepadButtonPressed(lua_State *L) { - bool result = IsWindowMinimized(); - LuaPush_bool(L, result); + int gamepad = (int)luaL_checkinteger(L, 1); + int button = (int)luaL_checkinteger(L, 2); + bool result = IsGamepadButtonPressed(gamepad, button); + lua_pushboolean(L, result); return 1; } -// Toggle fullscreen mode (only PLATFORM_DESKTOP) -int lua_ToggleFullscreen(lua_State *L) +// Check if a gamepad button is being pressed +static int rl_IsGamepadButtonDown(lua_State *L) { - ToggleFullscreen(); - return 0; + int gamepad = (int)luaL_checkinteger(L, 1); + int button = (int)luaL_checkinteger(L, 2); + bool result = IsGamepadButtonDown(gamepad, button); + lua_pushboolean(L, result); + return 1; } -// Set icon for window (only PLATFORM_DESKTOP) -int lua_SetWindowIcon(lua_State *L) +// Check if a gamepad button has been released once +static int rl_IsGamepadButtonReleased(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - SetWindowIcon(image); - return 0; + int gamepad = (int)luaL_checkinteger(L, 1); + int button = (int)luaL_checkinteger(L, 2); + bool result = IsGamepadButtonReleased(gamepad, button); + lua_pushboolean(L, result); + return 1; } -// Set title for window (only PLATFORM_DESKTOP) -int lua_SetWindowTitle(lua_State *L) +// Check if a gamepad button is NOT being pressed +static int rl_IsGamepadButtonUp(lua_State *L) { - const char *title = LuaGetArgument_string(L, 1); - SetWindowTitle(title); - return 0; + int gamepad = (int)luaL_checkinteger(L, 1); + int button = (int)luaL_checkinteger(L, 2); + bool result = IsGamepadButtonUp(gamepad, button); + lua_pushboolean(L, result); + return 1; } -// Set window position on screen (only PLATFORM_DESKTOP) -int lua_SetWindowPosition(lua_State *L) +// Get the last gamepad button pressed +static int rl_GetGamepadButtonPressed(lua_State *L) { - int x = LuaGetArgument_int(L, 1); - int y = LuaGetArgument_int(L, 2); - SetWindowPosition(x, y); - return 0; + int result = GetGamepadButtonPressed(); + lua_pushinteger(L, result); + return 1; } -// Set monitor for the current window (fullscreen mode) -int lua_SetWindowMonitor(lua_State *L) +// Get axis count for a gamepad +static int rl_GetGamepadAxisCount(lua_State *L) { - int monitor = LuaGetArgument_int(L, 1); - SetWindowMonitor(monitor); - return 0; + int gamepad = (int)luaL_checkinteger(L, 1); + int result = GetGamepadAxisCount(gamepad); + lua_pushinteger(L, result); + return 1; } -// Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE) -int lua_SetWindowMinSize(lua_State *L) +// Get movement value for a gamepad axis +static int rl_GetGamepadAxisMovement(lua_State *L) { - int width = LuaGetArgument_int(L, 1); - int height = LuaGetArgument_int(L, 2); - SetWindowMinSize(width, height); - return 0; + int gamepad = (int)luaL_checkinteger(L, 1); + int axis = (int)luaL_checkinteger(L, 2); + float result = GetGamepadAxisMovement(gamepad, axis); + lua_pushnumber(L, result); + return 1; +} + +// Set internal gamepad mappings (SDL_GameControllerDB) +static int rl_SetGamepadMappings(lua_State *L) +{ + const char * mappings = luaL_checkstring(L, 1); + int result = SetGamepadMappings(mappings); + lua_pushinteger(L, result); + return 1; } -// Set window dimensions -int lua_SetWindowSize(lua_State *L) +// Set gamepad vibration for both motors (duration in seconds) +static int rl_SetGamepadVibration(lua_State *L) { - int width = LuaGetArgument_int(L, 1); - int height = LuaGetArgument_int(L, 2); - SetWindowSize(width, height); + int gamepad = (int)luaL_checkinteger(L, 1); + float leftMotor = (float)luaL_checknumber(L, 2); + float rightMotor = (float)luaL_checknumber(L, 3); + float duration = (float)luaL_checknumber(L, 4); + SetGamepadVibration(gamepad, leftMotor, rightMotor, duration); return 0; } -// Get current screen width -int lua_GetScreenWidth(lua_State *L) +// Input-related functions: mouse +// Check if a mouse button has been pressed once +static int rl_IsMouseButtonPressed(lua_State *L) { - int result = GetScreenWidth(); - LuaPush_int(L, result); + int button = (int)luaL_checkinteger(L, 1); + bool result = IsMouseButtonPressed(button); + lua_pushboolean(L, result); return 1; } -// Get current screen height -int lua_GetScreenHeight(lua_State *L) +// Check if a mouse button is being pressed +static int rl_IsMouseButtonDown(lua_State *L) { - int result = GetScreenHeight(); - LuaPush_int(L, result); + int button = (int)luaL_checkinteger(L, 1); + bool result = IsMouseButtonDown(button); + lua_pushboolean(L, result); return 1; } -// Cursor-related functions -// Shows cursor -int lua_ShowCursor(lua_State *L) +// Check if a mouse button has been released once +static int rl_IsMouseButtonReleased(lua_State *L) { - ShowCursor(); - return 0; + int button = (int)luaL_checkinteger(L, 1); + bool result = IsMouseButtonReleased(button); + lua_pushboolean(L, result); + return 1; } -// Hides cursor -int lua_HideCursor(lua_State *L) +// Check if a mouse button is NOT being pressed +static int rl_IsMouseButtonUp(lua_State *L) { - HideCursor(); - return 0; + int button = (int)luaL_checkinteger(L, 1); + bool result = IsMouseButtonUp(button); + lua_pushboolean(L, result); + return 1; } -// Check if cursor is not visible -int lua_IsCursorHidden(lua_State *L) +// Get mouse position X +static int rl_GetMouseX(lua_State *L) { - bool result = IsCursorHidden(); - LuaPush_bool(L, result); + int result = GetMouseX(); + lua_pushinteger(L, result); return 1; } -// Enables cursor (unlock cursor) -int lua_EnableCursor(lua_State *L) +// Get mouse position Y +static int rl_GetMouseY(lua_State *L) { - EnableCursor(); - return 0; + int result = GetMouseY(); + lua_pushinteger(L, result); + return 1; } -// Disables cursor (lock cursor) -int lua_DisableCursor(lua_State *L) +// Get mouse position XY +static int rl_GetMousePosition(lua_State *L) { - DisableCursor(); - return 0; + Vector2 result = GetMousePosition(); + RLUA_PUSH_Vector2(L, result); + return 1; } -// Drawing-related functions -// Set background color (framebuffer clear color) -int lua_ClearBackground(lua_State *L) +// Get mouse delta between frames +static int rl_GetMouseDelta(lua_State *L) { - Color color = LuaGetArgument_Color(L, 1); - ClearBackground(color); - return 0; + Vector2 result = GetMouseDelta(); + RLUA_PUSH_Vector2(L, result); + return 1; } -// Setup canvas (framebuffer) to start drawing -int lua_BeginDrawing(lua_State *L) +// Set mouse position XY +static int rl_SetMousePosition(lua_State *L) { - BeginDrawing(); + int x = (int)luaL_checkinteger(L, 1); + int y = (int)luaL_checkinteger(L, 2); + SetMousePosition(x, y); return 0; } -// End canvas drawing and swap buffers (double buffering) -int lua_EndDrawing(lua_State *L) +// Set mouse offset +static int rl_SetMouseOffset(lua_State *L) { - EndDrawing(); + int offsetX = (int)luaL_checkinteger(L, 1); + int offsetY = (int)luaL_checkinteger(L, 2); + SetMouseOffset(offsetX, offsetY); return 0; } -// Initialize 2D mode with custom camera (2D) -int lua_BeginMode2D(lua_State *L) +// Set mouse scaling +static int rl_SetMouseScale(lua_State *L) { - Camera2D camera = LuaGetArgument_Camera2D(L, 1); - BeginMode2D(camera); + float scaleX = (float)luaL_checknumber(L, 1); + float scaleY = (float)luaL_checknumber(L, 2); + SetMouseScale(scaleX, scaleY); return 0; } -// Ends 2D mode with custom camera -int lua_EndMode2D(lua_State *L) +// Get mouse wheel movement for X or Y, whichever is larger +static int rl_GetMouseWheelMove(lua_State *L) { - EndMode2D(); - return 0; + float result = GetMouseWheelMove(); + lua_pushnumber(L, result); + return 1; } -// Initializes 3D mode with custom camera (3D) -int lua_BeginMode3D(lua_State *L) +// Get mouse wheel movement for both X and Y +static int rl_GetMouseWheelMoveV(lua_State *L) { - Camera3D camera = LuaGetArgument_Camera3D(L, 1); - BeginMode3D(camera); - return 0; + Vector2 result = GetMouseWheelMoveV(); + RLUA_PUSH_Vector2(L, result); + return 1; } -// Ends 3D mode and returns to default 2D orthographic mode -int lua_EndMode3D(lua_State *L) +// Set mouse cursor +static int rl_SetMouseCursor(lua_State *L) { - EndMode3D(); + int cursor = (int)luaL_checkinteger(L, 1); + SetMouseCursor(cursor); return 0; } -// Initializes render texture for drawing -int lua_BeginTextureMode(lua_State *L) +// Input-related functions: touch +// Get touch position X for touch point 0 (relative to screen size) +static int rl_GetTouchX(lua_State *L) { - RenderTexture2D target = LuaGetArgument_RenderTexture2D(L, 1); - BeginTextureMode(target); - return 0; + int result = GetTouchX(); + lua_pushinteger(L, result); + return 1; } -// Ends drawing to render texture -int lua_EndTextureMode(lua_State *L) +// Get touch position Y for touch point 0 (relative to screen size) +static int rl_GetTouchY(lua_State *L) { - EndTextureMode(); - return 0; + int result = GetTouchY(); + lua_pushinteger(L, result); + return 1; } -// Screen-space-related functions -// Returns a ray trace from mouse position -int lua_GetMouseRay(lua_State *L) +// Get touch position XY for a touch point index (relative to screen size) +static int rl_GetTouchPosition(lua_State *L) { - Vector2 mousePosition = LuaGetArgument_Vector2(L, 1); - Camera camera = LuaGetArgument_Camera(L, 2); - Ray result = GetMouseRay(mousePosition, camera); - LuaPush_Ray(L, result); + int index = (int)luaL_checkinteger(L, 1); + Vector2 result = GetTouchPosition(index); + RLUA_PUSH_Vector2(L, result); return 1; } -// Returns the screen space position for a 3d world space position -int lua_GetWorldToScreen(lua_State *L) +// Get touch point identifier for given index +static int rl_GetTouchPointId(lua_State *L) { - Vector3 position = LuaGetArgument_Vector3(L, 1); - Camera camera = LuaGetArgument_Camera(L, 2); - Vector2 result = GetWorldToScreen(position, camera); - LuaPush_Vector2(L, result); + int index = (int)luaL_checkinteger(L, 1); + int result = GetTouchPointId(index); + lua_pushinteger(L, result); return 1; } -// Returns camera transform matrix (view matrix) -int lua_GetCameraMatrix(lua_State *L) +// Get number of touch points +static int rl_GetTouchPointCount(lua_State *L) { - Camera camera = LuaGetArgument_Camera(L, 1); - Matrix result = GetCameraMatrix(camera); - LuaPush_Matrix(L, result); + int result = GetTouchPointCount(); + lua_pushinteger(L, result); return 1; } -// Timming-related functions -// Set target FPS (maximum) -int lua_SetTargetFPS(lua_State *L) +// ------------------------------------------------------------------------------------ +// Gestures and Touch Handling Functions (Module: rgestures) +// ------------------------------------------------------------------------------------ +// Enable a set of gestures using flags +static int rl_SetGesturesEnabled(lua_State *L) { - int fps = LuaGetArgument_int(L, 1); - SetTargetFPS(fps); + unsigned int flags = (unsigned int)luaL_checkinteger(L, 1); + SetGesturesEnabled(flags); return 0; } -// Returns current FPS -int lua_GetFPS(lua_State *L) +// Check if a gesture have been detected +static int rl_IsGestureDetected(lua_State *L) { - int result = GetFPS(); - LuaPush_int(L, result); + unsigned int gesture = (unsigned int)luaL_checkinteger(L, 1); + bool result = IsGestureDetected(gesture); + lua_pushboolean(L, result); return 1; } -// Returns time in seconds for last frame drawn -int lua_GetFrameTime(lua_State *L) +// Get latest detected gesture +static int rl_GetGestureDetected(lua_State *L) { - float result = GetFrameTime(); - LuaPush_float(L, result); + int result = GetGestureDetected(); + lua_pushinteger(L, result); return 1; } -// Returns elapsed time in seconds since InitWindow() -int lua_GetTime(lua_State *L) +// Get gesture hold time in seconds +static int rl_GetGestureHoldDuration(lua_State *L) { - double result = GetTime(); - LuaPush_double(L, result); + float result = GetGestureHoldDuration(); + lua_pushnumber(L, result); return 1; } -// Color-related functions -// Returns hexadecimal value for a Color -int lua_ColorToInt(lua_State *L) +// Get gesture drag vector +static int rl_GetGestureDragVector(lua_State *L) { - Color color = LuaGetArgument_Color(L, 1); - int result = ColorToInt(color); - LuaPush_int(L, result); + Vector2 result = GetGestureDragVector(); + RLUA_PUSH_Vector2(L, result); return 1; } -// Returns color normalized as float [0..1] -int lua_ColorNormalize(lua_State *L) +// Get gesture drag angle +static int rl_GetGestureDragAngle(lua_State *L) { - Color color = LuaGetArgument_Color(L, 1); - Vector4 result = ColorNormalize(color); - LuaPush_Vector4(L, result); + float result = GetGestureDragAngle(); + lua_pushnumber(L, result); return 1; } -// Returns HSV values for a Color -int lua_ColorToHSV(lua_State *L) +// Get gesture pinch delta +static int rl_GetGesturePinchVector(lua_State *L) { - Color color = LuaGetArgument_Color(L, 1); - Vector3 result = ColorToHSV(color); - LuaPush_Vector3(L, result); + Vector2 result = GetGesturePinchVector(); + RLUA_PUSH_Vector2(L, result); return 1; } -// Returns a Color struct from hexadecimal value -int lua_GetColor(lua_State *L) +// Get gesture pinch angle +static int rl_GetGesturePinchAngle(lua_State *L) { - int hexValue = LuaGetArgument_int(L, 1); - Color result = GetColor(hexValue); - LuaPush_Color(L, result); + float result = GetGesturePinchAngle(); + lua_pushnumber(L, result); return 1; } -// Color fade-in or fade-out, alpha goes from 0.0f to 1.0f -int lua_Fade(lua_State *L) +// ------------------------------------------------------------------------------------ +// Camera System Functions (Module: rcamera) +// ------------------------------------------------------------------------------------ +// Update camera position for selected mode +static int rl_UpdateCamera(lua_State *L) { - Color color = LuaGetArgument_Color(L, 1); - float alpha = LuaGetArgument_float(L, 2); - Color result = Fade(color, alpha); - LuaPush_Color(L, result); - return 1; + Camera camera = RLUA_CHECK_Camera(L, 1); + int mode = (int)luaL_checkinteger(L, 2); + UpdateCamera(&camera, mode); + RLUA_WRITEBACK_Camera(L, 1, camera); + return 0; } -// Misc. functions -// Activate raylib logo at startup (can be done with flags) -int lua_ShowLogo(lua_State *L) +// Update camera movement/rotation +static int rl_UpdateCameraPro(lua_State *L) { - ShowLogo(); + Camera camera = RLUA_CHECK_Camera(L, 1); + Vector3 movement = RLUA_CHECK_Vector3(L, 2); + Vector3 rotation = RLUA_CHECK_Vector3(L, 3); + float zoom = (float)luaL_checknumber(L, 4); + UpdateCameraPro(&camera, movement, rotation, zoom); + RLUA_WRITEBACK_Camera(L, 1, camera); return 0; } -// Setup window configuration flags (view FLAGS) -int lua_SetConfigFlags(lua_State *L) +// ------------------------------------------------------------------------------------ +// Basic Shapes Drawing Functions (Module: shapes) +// ------------------------------------------------------------------------------------ +// Set texture and rectangle to be used on shapes drawing +// NOTE: It can be useful when using basic shapes and one single font, +// defining a font char white rectangle would allow drawing everything in a single draw call +// Set texture and rectangle to be used on shapes drawing +static int rl_SetShapesTexture(lua_State *L) { - unsigned char flags = LuaGetArgument_unsigned(L, 1); - SetConfigFlags(flags); + Texture2D texture = *(Texture2D*)RLUA_CHECK_Resource(L, 1, "Texture2D"); + Rectangle source = RLUA_CHECK_Rectangle(L, 2); + SetShapesTexture(texture, source); return 0; } -// Enable trace log message types (bit flags based) -int lua_SetTraceLog(lua_State *L) +// Get texture that is used for shapes drawing +static int rl_GetShapesTexture(lua_State *L) { - unsigned char types = LuaGetArgument_unsigned(L, 1); - SetTraceLog(types); - return 0; + Texture2D result = GetShapesTexture(); + RLUA_PUSH_Resource(L, &result, sizeof(Texture2D), "Texture2D"); + return 1; } -/* -#if defined(PLATFORM_WEB) -static int LuaDrawLoopFunc; - -static void LuaDrawLoop() +// Get texture source rectangle that is used for shapes drawing +static int rl_GetShapesTextureRectangle(lua_State *L) { - lua_rawgeti(L, LUA_REGISTRYINDEX, LuaDrawLoopFunc); - lua_call(L, 0, 0); + Rectangle result = GetShapesTextureRectangle(); + RLUA_PUSH_Rectangle(L, result); + return 1; } -int lua_SetDrawingLoop(lua_State* L) +// Basic shapes drawing functions +// Draw a pixel using geometry [Can be slow, use with care] +static int rl_DrawPixel(lua_State *L) { - luaL_argcheck(L, lua_isfunction(L, 1), 1, "Loop function expected"); - lua_pushvalue(L, 1); - LuaDrawLoopFunc = luaL_ref(L, LUA_REGISTRYINDEX); - SetDrawingLoop(&LuaDrawLoop); + int posX = (int)luaL_checkinteger(L, 1); + int posY = (int)luaL_checkinteger(L, 2); + Color color = RLUA_CHECK_Color(L, 3); + DrawPixel(posX, posY, color); return 0; } -#else -// Set target FPS (maximum) -int lua_SetTargetFPS(lua_State* L) + +// Draw a pixel using geometry (Vector version) [Can be slow, use with care] +static int rl_DrawPixelV(lua_State *L) { - int arg1 = LuaGetArgument_int(L, 1); - SetTargetFPS(arg1); + Vector2 position = RLUA_CHECK_Vector2(L, 1); + Color color = RLUA_CHECK_Color(L, 2); + DrawPixelV(position, color); return 0; } -#endif -*/ +// Draw a line +static int rl_DrawLine(lua_State *L) +{ + int startPosX = (int)luaL_checkinteger(L, 1); + int startPosY = (int)luaL_checkinteger(L, 2); + int endPosX = (int)luaL_checkinteger(L, 3); + int endPosY = (int)luaL_checkinteger(L, 4); + Color color = RLUA_CHECK_Color(L, 5); + DrawLine(startPosX, startPosY, endPosX, endPosY, color); + return 0; +} -/* -// Converts Color to float array and normalizes -int lua_ColorToFloat(lua_State* L) +// Draw a line (using gl lines) +static int rl_DrawLineV(lua_State *L) { - Color arg1 = LuaGetArgument_Color(L, 1); - float *result = ColorToFloat(arg1); - lua_createtable(L, 4, 0); - for (int i = 0; i < 4; i++) - { - LuaPush_float(L, result[i]); - lua_rawseti(L, -2, i + 1); - } - free(result); - return 1; + Vector2 startPos = RLUA_CHECK_Vector2(L, 1); + Vector2 endPos = RLUA_CHECK_Vector2(L, 2); + Color color = RLUA_CHECK_Color(L, 3); + DrawLineV(startPos, endPos, color); + return 0; } -// Converts Vector3 to float array -int lua_VectorToFloat(lua_State* L) +// Draw a line (using triangles/quads) +static int rl_DrawLineEx(lua_State *L) { - Vector3 arg1 = LuaGetArgument_Vector3(L, 1); - float *result = VectorToFloat(arg1); - lua_createtable(L, 3, 0); - for (int i = 0; i < 3; i++) - { - LuaPush_float(L, result[i]); - lua_rawseti(L, -2, i + 1); - } - free(result); - return 1; + Vector2 startPos = RLUA_CHECK_Vector2(L, 1); + Vector2 endPos = RLUA_CHECK_Vector2(L, 2); + float thick = (float)luaL_checknumber(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + DrawLineEx(startPos, endPos, thick, color); + return 0; } -// Converts Matrix to float array -int lua_MatrixToFloat(lua_State* L) +// Draw lines sequence (using gl lines) +static int rl_DrawLineStrip(lua_State *L) { - Matrix arg1 = LuaGetArgument_Matrix(L, 1); - float *result = MatrixToFloat(arg1); - lua_createtable(L, 16, 0); - for (int i = 0; i < 16; i++) - { - LuaPush_float(L, result[i]); - lua_rawseti(L, -2, i + 1); - } - free(result); - return 1; + const Vector2 * points = (const Vector2 *)lua_touserdata(L, 1); + int pointCount = (int)luaL_checkinteger(L, 2); + Color color = RLUA_CHECK_Color(L, 3); + DrawLineStrip(points, pointCount, color); + return 0; } -*/ -// WARNING: Show trace log messages (INFO, WARNING, ERROR, DEBUG) -int lua_TraceLog(lua_State* L) +// Draw line segment cubic-bezier in-out interpolation +static int rl_DrawLineBezier(lua_State *L) { - int num_args = lua_gettop(L) - 1; - int arg1 = LuaGetArgument_int(L, 1); + Vector2 startPos = RLUA_CHECK_Vector2(L, 1); + Vector2 endPos = RLUA_CHECK_Vector2(L, 2); + float thick = (float)luaL_checknumber(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + DrawLineBezier(startPos, endPos, thick, color); + return 0; +} - /// type, fmt, args... +// Draw a dashed line +static int rl_DrawLineDashed(lua_State *L) +{ + Vector2 startPos = RLUA_CHECK_Vector2(L, 1); + Vector2 endPos = RLUA_CHECK_Vector2(L, 2); + int dashSize = (int)luaL_checkinteger(L, 3); + int spaceSize = (int)luaL_checkinteger(L, 4); + Color color = RLUA_CHECK_Color(L, 5); + DrawLineDashed(startPos, endPos, dashSize, spaceSize, color); + return 0; +} - lua_rotate(L, 1, -1); /// fmt, args..., type - lua_pop(L, 1); /// fmt, args... +// Draw a color-filled circle +static int rl_DrawCircle(lua_State *L) +{ + int centerX = (int)luaL_checkinteger(L, 1); + int centerY = (int)luaL_checkinteger(L, 2); + float radius = (float)luaL_checknumber(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + DrawCircle(centerX, centerY, radius, color); + return 0; +} - lua_getglobal(L, "string"); /// fmt, args..., [string] - lua_getfield(L, 1, "format"); /// fmt, args..., [string], format() - lua_rotate(L, 1, 2); /// [string], format(), fmt, args... - lua_call(L, num_args, 1); /// [string], formatted_string +// Draw a color-filled circle (Vector version) +static int rl_DrawCircleV(lua_State *L) +{ + Vector2 center = RLUA_CHECK_Vector2(L, 1); + float radius = (float)luaL_checknumber(L, 2); + Color color = RLUA_CHECK_Color(L, 3); + DrawCircleV(center, radius, color); + return 0; +} - TraceLog(arg1, "%s", luaL_checkstring(L,-1)); +// Draw a gradient-filled circle +static int rl_DrawCircleGradient(lua_State *L) +{ + Vector2 center = RLUA_CHECK_Vector2(L, 1); + float radius = (float)luaL_checknumber(L, 2); + Color inner = RLUA_CHECK_Color(L, 3); + Color outer = RLUA_CHECK_Color(L, 4); + DrawCircleGradient(center, radius, inner, outer); return 0; } -// Takes a screenshot of current screen (saved a .png) -int lua_TakeScreenshot(lua_State *L) +// Draw a piece of a circle +static int rl_DrawCircleSector(lua_State *L) { - const char *fileName = LuaGetArgument_string(L, 1); - TakeScreenshot(fileName); + Vector2 center = RLUA_CHECK_Vector2(L, 1); + float radius = (float)luaL_checknumber(L, 2); + float startAngle = (float)luaL_checknumber(L, 3); + float endAngle = (float)luaL_checknumber(L, 4); + int segments = (int)luaL_checkinteger(L, 5); + Color color = RLUA_CHECK_Color(L, 6); + DrawCircleSector(center, radius, startAngle, endAngle, segments, color); return 0; } -// Returns a random value between min and max (both included) -int lua_GetRandomValue(lua_State *L) +// Draw circle sector outline +static int rl_DrawCircleSectorLines(lua_State *L) { - int min = LuaGetArgument_int(L, 1); - int max = LuaGetArgument_int(L, 2); - int result = GetRandomValue(min, max); - LuaPush_int(L, result); - return 1; + Vector2 center = RLUA_CHECK_Vector2(L, 1); + float radius = (float)luaL_checknumber(L, 2); + float startAngle = (float)luaL_checknumber(L, 3); + float endAngle = (float)luaL_checknumber(L, 4); + int segments = (int)luaL_checkinteger(L, 5); + Color color = RLUA_CHECK_Color(L, 6); + DrawCircleSectorLines(center, radius, startAngle, endAngle, segments, color); + return 0; } -// Check file extension -int lua_IsFileExtension(lua_State *L) +// Draw circle outline +static int rl_DrawCircleLines(lua_State *L) { - const char *fileName = LuaGetArgument_string(L, 1); - const char *ext = LuaGetArgument_string(L, 2); - bool result = IsFileExtension(fileName, ext); - LuaPush_bool(L, result); - return 1; + int centerX = (int)luaL_checkinteger(L, 1); + int centerY = (int)luaL_checkinteger(L, 2); + float radius = (float)luaL_checknumber(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + DrawCircleLines(centerX, centerY, radius, color); + return 0; } -// WARNING: Get pointer to extension for a filename string -int lua_GetExtension(lua_State *L) +// Draw circle outline (Vector version) +static int rl_DrawCircleLinesV(lua_State *L) { - const char *fileName = LuaGetArgument_string(L, 1); - const char *result = GetExtension(fileName); - LuaPush_string(L, result); - return 1; + Vector2 center = RLUA_CHECK_Vector2(L, 1); + float radius = (float)luaL_checknumber(L, 2); + Color color = RLUA_CHECK_Color(L, 3); + DrawCircleLinesV(center, radius, color); + return 0; } -// Get pointer to filename for a path string -int lua_GetFileName(lua_State *L) +// Draw ellipse +static int rl_DrawEllipse(lua_State *L) { - const char *filePath = LuaGetArgument_string(L, 1); - string result = GetFileName(filePath); - LuaPush_string(L, result); - return 1; + int centerX = (int)luaL_checkinteger(L, 1); + int centerY = (int)luaL_checkinteger(L, 2); + float radiusH = (float)luaL_checknumber(L, 3); + float radiusV = (float)luaL_checknumber(L, 4); + Color color = RLUA_CHECK_Color(L, 5); + DrawEllipse(centerX, centerY, radiusH, radiusV, color); + return 0; } -// Get full path for a given fileName (uses static string) -int lua_GetDirectoryPath(lua_State *L) +// Draw ellipse (Vector version) +static int rl_DrawEllipseV(lua_State *L) { - const char *fileName = LuaGetArgument_string(L, 1); - string result = GetDirectoryPath(fileName); - LuaPush_string(L, result); - return 1; + Vector2 center = RLUA_CHECK_Vector2(L, 1); + float radiusH = (float)luaL_checknumber(L, 2); + float radiusV = (float)luaL_checknumber(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + DrawEllipseV(center, radiusH, radiusV, color); + return 0; } -// Get current working directory (uses static string) -int lua_GetWorkingDirectory(lua_State *L) +// Draw ellipse outline +static int rl_DrawEllipseLines(lua_State *L) { - string result = GetWorkingDirectory(); - LuaPush_string(L, result); - return 1; + int centerX = (int)luaL_checkinteger(L, 1); + int centerY = (int)luaL_checkinteger(L, 2); + float radiusH = (float)luaL_checknumber(L, 3); + float radiusV = (float)luaL_checknumber(L, 4); + Color color = RLUA_CHECK_Color(L, 5); + DrawEllipseLines(centerX, centerY, radiusH, radiusV, color); + return 0; } -// Change working directory, returns true if success -int lua_ChangeDirectory(lua_State *L) +// Draw ellipse outline (Vector version) +static int rl_DrawEllipseLinesV(lua_State *L) { - const char *dir = LuaGetArgument_string(L, 1); - bool result = ChangeDirectory(dir); - LuaPush_bool(L, result); - return 1; + Vector2 center = RLUA_CHECK_Vector2(L, 1); + float radiusH = (float)luaL_checknumber(L, 2); + float radiusV = (float)luaL_checknumber(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + DrawEllipseLinesV(center, radiusH, radiusV, color); + return 0; } -// Check if a file has been dropped into window -int lua_IsFileDropped(lua_State* L) +// Draw ring +static int rl_DrawRing(lua_State *L) { - bool result = IsFileDropped(); - LuaPush_bool(L, result); - return 1; + Vector2 center = RLUA_CHECK_Vector2(L, 1); + float innerRadius = (float)luaL_checknumber(L, 2); + float outerRadius = (float)luaL_checknumber(L, 3); + float startAngle = (float)luaL_checknumber(L, 4); + float endAngle = (float)luaL_checknumber(L, 5); + int segments = (int)luaL_checkinteger(L, 6); + Color color = RLUA_CHECK_Color(L, 7); + DrawRing(center, innerRadius, outerRadius, startAngle, endAngle, segments, color); + return 0; } -// WARNING: Get dropped files names -int lua_GetDroppedFiles(lua_State* L) +// Draw ring outline +static int rl_DrawRingLines(lua_State *L) { - int count = 0; - char **result = GetDroppedFiles(&count); - lua_createtable(L, count, 0); - for (int i = 0; i < count; i++) - { - LuaPush_string(L, result[i]); - lua_rawseti(L, -2, i + 1); - } - return 1; + Vector2 center = RLUA_CHECK_Vector2(L, 1); + float innerRadius = (float)luaL_checknumber(L, 2); + float outerRadius = (float)luaL_checknumber(L, 3); + float startAngle = (float)luaL_checknumber(L, 4); + float endAngle = (float)luaL_checknumber(L, 5); + int segments = (int)luaL_checkinteger(L, 6); + Color color = RLUA_CHECK_Color(L, 7); + DrawRingLines(center, innerRadius, outerRadius, startAngle, endAngle, segments, color); + return 0; } -// Clear dropped files paths buffer -int lua_ClearDroppedFiles(lua_State* L) +// Draw a color-filled rectangle +static int rl_DrawRectangle(lua_State *L) { - ClearDroppedFiles(); + int posX = (int)luaL_checkinteger(L, 1); + int posY = (int)luaL_checkinteger(L, 2); + int width = (int)luaL_checkinteger(L, 3); + int height = (int)luaL_checkinteger(L, 4); + Color color = RLUA_CHECK_Color(L, 5); + DrawRectangle(posX, posY, width, height, color); return 0; } -// Save integer value to storage file (to defined position) -int lua_StorageSaveValue(lua_State *L) +// Draw a color-filled rectangle (Vector version) +static int rl_DrawRectangleV(lua_State *L) { - int position = LuaGetArgument_int(L, 1); - int value = LuaGetArgument_int(L, 2); - StorageSaveValue(position, value); + Vector2 position = RLUA_CHECK_Vector2(L, 1); + Vector2 size = RLUA_CHECK_Vector2(L, 2); + Color color = RLUA_CHECK_Color(L, 3); + DrawRectangleV(position, size, color); return 0; } -// Load integer value from storage file (from defined position) -int lua_StorageLoadValue(lua_State *L) +// Draw a color-filled rectangle +static int rl_DrawRectangleRec(lua_State *L) { - int position = LuaGetArgument_int(L, 1); - int result = StorageLoadValue(position); - LuaPush_int(L, result); - return 1; + Rectangle rec = RLUA_CHECK_Rectangle(L, 1); + Color color = RLUA_CHECK_Color(L, 2); + DrawRectangleRec(rec, color); + return 0; } -//------------------------------------------------------------------------------------ -// raylib [core] module functions - Input Handling -//------------------------------------------------------------------------------------ +// Draw a color-filled rectangle with pro parameters +static int rl_DrawRectanglePro(lua_State *L) +{ + Rectangle rec = RLUA_CHECK_Rectangle(L, 1); + Vector2 origin = RLUA_CHECK_Vector2(L, 2); + float rotation = (float)luaL_checknumber(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + DrawRectanglePro(rec, origin, rotation, color); + return 0; +} -// Detect if a key has been pressed once -int lua_IsKeyPressed(lua_State *L) +// Draw a vertical-gradient-filled rectangle +static int rl_DrawRectangleGradientV(lua_State *L) { - int key = LuaGetArgument_int(L, 1); - bool result = IsKeyPressed(key); - LuaPush_bool(L, result); - return 1; + int posX = (int)luaL_checkinteger(L, 1); + int posY = (int)luaL_checkinteger(L, 2); + int width = (int)luaL_checkinteger(L, 3); + int height = (int)luaL_checkinteger(L, 4); + Color top = RLUA_CHECK_Color(L, 5); + Color bottom = RLUA_CHECK_Color(L, 6); + DrawRectangleGradientV(posX, posY, width, height, top, bottom); + return 0; } -// Detect if a key is being pressed -int lua_IsKeyDown(lua_State *L) +// Draw a horizontal-gradient-filled rectangle +static int rl_DrawRectangleGradientH(lua_State *L) { - int key = LuaGetArgument_int(L, 1); - bool result = IsKeyDown(key); - LuaPush_bool(L, result); - return 1; + int posX = (int)luaL_checkinteger(L, 1); + int posY = (int)luaL_checkinteger(L, 2); + int width = (int)luaL_checkinteger(L, 3); + int height = (int)luaL_checkinteger(L, 4); + Color left = RLUA_CHECK_Color(L, 5); + Color right = RLUA_CHECK_Color(L, 6); + DrawRectangleGradientH(posX, posY, width, height, left, right); + return 0; } -// Detect if a key has been released once -int lua_IsKeyReleased(lua_State *L) +// Draw a gradient-filled rectangle with custom vertex colors +static int rl_DrawRectangleGradientEx(lua_State *L) { - int key = LuaGetArgument_int(L, 1); - bool result = IsKeyReleased(key); - LuaPush_bool(L, result); - return 1; + Rectangle rec = RLUA_CHECK_Rectangle(L, 1); + Color topLeft = RLUA_CHECK_Color(L, 2); + Color bottomLeft = RLUA_CHECK_Color(L, 3); + Color bottomRight = RLUA_CHECK_Color(L, 4); + Color topRight = RLUA_CHECK_Color(L, 5); + DrawRectangleGradientEx(rec, topLeft, bottomLeft, bottomRight, topRight); + return 0; } -// Detect if a key is NOT being pressed -int lua_IsKeyUp(lua_State *L) +// Draw rectangle outline +static int rl_DrawRectangleLines(lua_State *L) { - int key = LuaGetArgument_int(L, 1); - bool result = IsKeyUp(key); - LuaPush_bool(L, result); - return 1; + int posX = (int)luaL_checkinteger(L, 1); + int posY = (int)luaL_checkinteger(L, 2); + int width = (int)luaL_checkinteger(L, 3); + int height = (int)luaL_checkinteger(L, 4); + Color color = RLUA_CHECK_Color(L, 5); + DrawRectangleLines(posX, posY, width, height, color); + return 0; } -// Get latest key pressed -int lua_GetKeyPressed(lua_State *L) +// Draw rectangle outline with extended parameters +static int rl_DrawRectangleLinesEx(lua_State *L) { - int result = GetKeyPressed(); - LuaPush_int(L, result); - return 1; + Rectangle rec = RLUA_CHECK_Rectangle(L, 1); + float lineThick = (float)luaL_checknumber(L, 2); + Color color = RLUA_CHECK_Color(L, 3); + DrawRectangleLinesEx(rec, lineThick, color); + return 0; } -// Set a custom key to exit program (default is ESC) -int lua_SetExitKey(lua_State *L) +// Draw rectangle with rounded edges +static int rl_DrawRectangleRounded(lua_State *L) { - int key = LuaGetArgument_int(L, 1); - SetExitKey(key); + Rectangle rec = RLUA_CHECK_Rectangle(L, 1); + float roundness = (float)luaL_checknumber(L, 2); + int segments = (int)luaL_checkinteger(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + DrawRectangleRounded(rec, roundness, segments, color); return 0; } -// Input-related functions: gamepads -// Detect if a gamepad is available -int lua_IsGamepadAvailable(lua_State *L) +// Draw rectangle lines with rounded edges +static int rl_DrawRectangleRoundedLines(lua_State *L) { - int gamepad = LuaGetArgument_int(L, 1); - bool result = IsGamepadAvailable(gamepad); - LuaPush_bool(L, result); - return 1; + Rectangle rec = RLUA_CHECK_Rectangle(L, 1); + float roundness = (float)luaL_checknumber(L, 2); + int segments = (int)luaL_checkinteger(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + DrawRectangleRoundedLines(rec, roundness, segments, color); + return 0; } -// WARNING: Check gamepad name (if available) -int lua_IsGamepadName(lua_State* L) +// Draw rectangle with rounded edges outline +static int rl_DrawRectangleRoundedLinesEx(lua_State *L) { - int arg1 = LuaGetArgument_int(L, 1); - const char *arg2 = LuaGetArgument_string(L, 2); - bool result = IsGamepadName(arg1, arg2); - LuaPush_bool(L, result); - return 1; + Rectangle rec = RLUA_CHECK_Rectangle(L, 1); + float roundness = (float)luaL_checknumber(L, 2); + int segments = (int)luaL_checkinteger(L, 3); + float lineThick = (float)luaL_checknumber(L, 4); + Color color = RLUA_CHECK_Color(L, 5); + DrawRectangleRoundedLinesEx(rec, roundness, segments, lineThick, color); + return 0; } -// WARNING: Return gamepad internal name id -int lua_GetGamepadName(lua_State* L) +// Draw a color-filled triangle (vertex in counter-clockwise order!) +static int rl_DrawTriangle(lua_State *L) { - int arg1 = LuaGetArgument_int(L, 1); - const char *result = GetGamepadName(arg1); - LuaPush_string(L, result); - return 1; + Vector2 v1 = RLUA_CHECK_Vector2(L, 1); + Vector2 v2 = RLUA_CHECK_Vector2(L, 2); + Vector2 v3 = RLUA_CHECK_Vector2(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + DrawTriangle(v1, v2, v3, color); + return 0; } -// Detect if a gamepad button has been pressed once -int lua_IsGamepadButtonPressed(lua_State *L) +// Draw triangle outline (vertex in counter-clockwise order!) +static int rl_DrawTriangleLines(lua_State *L) { - int gamepad = LuaGetArgument_int(L, 1); - int button = LuaGetArgument_int(L, 2); - bool result = IsGamepadButtonPressed(gamepad, button); - LuaPush_bool(L, result); - return 1; + Vector2 v1 = RLUA_CHECK_Vector2(L, 1); + Vector2 v2 = RLUA_CHECK_Vector2(L, 2); + Vector2 v3 = RLUA_CHECK_Vector2(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + DrawTriangleLines(v1, v2, v3, color); + return 0; } -// Detect if a gamepad button is being pressed -int lua_IsGamepadButtonDown(lua_State *L) +// Draw a triangle fan defined by points (first vertex is the center) +static int rl_DrawTriangleFan(lua_State *L) { - int gamepad = LuaGetArgument_int(L, 1); - int button = LuaGetArgument_int(L, 2); - bool result = IsGamepadButtonDown(gamepad, button); - LuaPush_bool(L, result); - return 1; + const Vector2 * points = (const Vector2 *)lua_touserdata(L, 1); + int pointCount = (int)luaL_checkinteger(L, 2); + Color color = RLUA_CHECK_Color(L, 3); + DrawTriangleFan(points, pointCount, color); + return 0; } -// Detect if a gamepad button has been released once -int lua_IsGamepadButtonReleased(lua_State *L) +// Draw a triangle strip defined by points +static int rl_DrawTriangleStrip(lua_State *L) { - int gamepad = LuaGetArgument_int(L, 1); - int button = LuaGetArgument_int(L, 2); - bool result = IsGamepadButtonReleased(gamepad, button); - LuaPush_bool(L, result); - return 1; + const Vector2 * points = (const Vector2 *)lua_touserdata(L, 1); + int pointCount = (int)luaL_checkinteger(L, 2); + Color color = RLUA_CHECK_Color(L, 3); + DrawTriangleStrip(points, pointCount, color); + return 0; } -// Detect if a gamepad button is NOT being pressed -int lua_IsGamepadButtonUp(lua_State *L) +// Draw a regular polygon (Vector version) +static int rl_DrawPoly(lua_State *L) { - int gamepad = LuaGetArgument_int(L, 1); - int button = LuaGetArgument_int(L, 2); - bool result = IsGamepadButtonUp(gamepad, button); - LuaPush_bool(L, result); - return 1; + Vector2 center = RLUA_CHECK_Vector2(L, 1); + int sides = (int)luaL_checkinteger(L, 2); + float radius = (float)luaL_checknumber(L, 3); + float rotation = (float)luaL_checknumber(L, 4); + Color color = RLUA_CHECK_Color(L, 5); + DrawPoly(center, sides, radius, rotation, color); + return 0; } -// Get the last gamepad button pressed -int lua_GetGamepadButtonPressed(lua_State *L) +// Draw a polygon outline of n sides +static int rl_DrawPolyLines(lua_State *L) { - int result = GetGamepadButtonPressed(); - LuaPush_int(L, result); - return 1; + Vector2 center = RLUA_CHECK_Vector2(L, 1); + int sides = (int)luaL_checkinteger(L, 2); + float radius = (float)luaL_checknumber(L, 3); + float rotation = (float)luaL_checknumber(L, 4); + Color color = RLUA_CHECK_Color(L, 5); + DrawPolyLines(center, sides, radius, rotation, color); + return 0; } -// Return gamepad axis count for a gamepad -int lua_GetGamepadAxisCount(lua_State *L) +// Draw a polygon outline of n sides with extended parameters +static int rl_DrawPolyLinesEx(lua_State *L) { - int gamepad = LuaGetArgument_int(L, 1); - int result = GetGamepadAxisCount(gamepad); - LuaPush_int(L, result); - return 1; + Vector2 center = RLUA_CHECK_Vector2(L, 1); + int sides = (int)luaL_checkinteger(L, 2); + float radius = (float)luaL_checknumber(L, 3); + float rotation = (float)luaL_checknumber(L, 4); + float lineThick = (float)luaL_checknumber(L, 5); + Color color = RLUA_CHECK_Color(L, 6); + DrawPolyLinesEx(center, sides, radius, rotation, lineThick, color); + return 0; } -// Return axis movement value for a gamepad axis -int lua_GetGamepadAxisMovement(lua_State *L) +// Splines drawing functions +// Draw spline: Linear, minimum 2 points +static int rl_DrawSplineLinear(lua_State *L) { - int gamepad = LuaGetArgument_int(L, 1); - int axis = LuaGetArgument_int(L, 2); - float result = GetGamepadAxisMovement(gamepad, axis); - LuaPush_float(L, result); - return 1; + const Vector2 * points = (const Vector2 *)lua_touserdata(L, 1); + int pointCount = (int)luaL_checkinteger(L, 2); + float thick = (float)luaL_checknumber(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + DrawSplineLinear(points, pointCount, thick, color); + return 0; } -// Input-related functions: mouse -// Detect if a mouse button has been pressed once -int lua_IsMouseButtonPressed(lua_State *L) +// Draw spline: B-Spline, minimum 4 points +static int rl_DrawSplineBasis(lua_State *L) { - int button = LuaGetArgument_int(L, 1); - bool result = IsMouseButtonPressed(button); - LuaPush_bool(L, result); - return 1; + const Vector2 * points = (const Vector2 *)lua_touserdata(L, 1); + int pointCount = (int)luaL_checkinteger(L, 2); + float thick = (float)luaL_checknumber(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + DrawSplineBasis(points, pointCount, thick, color); + return 0; } -// Detect if a mouse button is being pressed -int lua_IsMouseButtonDown(lua_State *L) +// Draw spline: Catmull-Rom, minimum 4 points +static int rl_DrawSplineCatmullRom(lua_State *L) { - int button = LuaGetArgument_int(L, 1); - bool result = IsMouseButtonDown(button); - LuaPush_bool(L, result); - return 1; + const Vector2 * points = (const Vector2 *)lua_touserdata(L, 1); + int pointCount = (int)luaL_checkinteger(L, 2); + float thick = (float)luaL_checknumber(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + DrawSplineCatmullRom(points, pointCount, thick, color); + return 0; } -// Detect if a mouse button has been released once -int lua_IsMouseButtonReleased(lua_State *L) +// Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...] +static int rl_DrawSplineBezierQuadratic(lua_State *L) { - int button = LuaGetArgument_int(L, 1); - bool result = IsMouseButtonReleased(button); - LuaPush_bool(L, result); - return 1; + const Vector2 * points = (const Vector2 *)lua_touserdata(L, 1); + int pointCount = (int)luaL_checkinteger(L, 2); + float thick = (float)luaL_checknumber(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + DrawSplineBezierQuadratic(points, pointCount, thick, color); + return 0; } -// Detect if a mouse button is NOT being pressed -int lua_IsMouseButtonUp(lua_State *L) +// Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...] +static int rl_DrawSplineBezierCubic(lua_State *L) { - int button = LuaGetArgument_int(L, 1); - bool result = IsMouseButtonUp(button); - LuaPush_bool(L, result); - return 1; + const Vector2 * points = (const Vector2 *)lua_touserdata(L, 1); + int pointCount = (int)luaL_checkinteger(L, 2); + float thick = (float)luaL_checknumber(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + DrawSplineBezierCubic(points, pointCount, thick, color); + return 0; } -// Returns mouse position X -int lua_GetMouseX(lua_State *L) +// Draw spline segment: Linear, 2 points +static int rl_DrawSplineSegmentLinear(lua_State *L) { - int result = GetMouseX(); - LuaPush_int(L, result); - return 1; + Vector2 p1 = RLUA_CHECK_Vector2(L, 1); + Vector2 p2 = RLUA_CHECK_Vector2(L, 2); + float thick = (float)luaL_checknumber(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + DrawSplineSegmentLinear(p1, p2, thick, color); + return 0; } -// Returns mouse position Y -int lua_GetMouseY(lua_State *L) +// Draw spline segment: B-Spline, 4 points +static int rl_DrawSplineSegmentBasis(lua_State *L) { - int result = GetMouseY(); - LuaPush_int(L, result); - return 1; + Vector2 p1 = RLUA_CHECK_Vector2(L, 1); + Vector2 p2 = RLUA_CHECK_Vector2(L, 2); + Vector2 p3 = RLUA_CHECK_Vector2(L, 3); + Vector2 p4 = RLUA_CHECK_Vector2(L, 4); + float thick = (float)luaL_checknumber(L, 5); + Color color = RLUA_CHECK_Color(L, 6); + DrawSplineSegmentBasis(p1, p2, p3, p4, thick, color); + return 0; } -// Returns mouse position XY -int lua_GetMousePosition(lua_State *L) +// Draw spline segment: Catmull-Rom, 4 points +static int rl_DrawSplineSegmentCatmullRom(lua_State *L) { - Vector2 result = GetMousePosition(); - LuaPush_Vector2(L, result); - return 1; + Vector2 p1 = RLUA_CHECK_Vector2(L, 1); + Vector2 p2 = RLUA_CHECK_Vector2(L, 2); + Vector2 p3 = RLUA_CHECK_Vector2(L, 3); + Vector2 p4 = RLUA_CHECK_Vector2(L, 4); + float thick = (float)luaL_checknumber(L, 5); + Color color = RLUA_CHECK_Color(L, 6); + DrawSplineSegmentCatmullRom(p1, p2, p3, p4, thick, color); + return 0; } -// Set mouse position XY -int lua_SetMousePosition(lua_State *L) +// Draw spline segment: Quadratic Bezier, 2 points, 1 control point +static int rl_DrawSplineSegmentBezierQuadratic(lua_State *L) { - Vector2 position = LuaGetArgument_Vector2(L, 1); - SetMousePosition(position); + Vector2 p1 = RLUA_CHECK_Vector2(L, 1); + Vector2 c2 = RLUA_CHECK_Vector2(L, 2); + Vector2 p3 = RLUA_CHECK_Vector2(L, 3); + float thick = (float)luaL_checknumber(L, 4); + Color color = RLUA_CHECK_Color(L, 5); + DrawSplineSegmentBezierQuadratic(p1, c2, p3, thick, color); return 0; } -// Set mouse scaling -int lua_SetMouseScale(lua_State *L) +// Draw spline segment: Cubic Bezier, 2 points, 2 control points +static int rl_DrawSplineSegmentBezierCubic(lua_State *L) { - float scale = LuaGetArgument_float(L, 1); - SetMouseScale(scale); + Vector2 p1 = RLUA_CHECK_Vector2(L, 1); + Vector2 c2 = RLUA_CHECK_Vector2(L, 2); + Vector2 c3 = RLUA_CHECK_Vector2(L, 3); + Vector2 p4 = RLUA_CHECK_Vector2(L, 4); + float thick = (float)luaL_checknumber(L, 5); + Color color = RLUA_CHECK_Color(L, 6); + DrawSplineSegmentBezierCubic(p1, c2, c3, p4, thick, color); return 0; } -// Returns mouse wheel movement Y -int lua_GetMouseWheelMove(lua_State *L) +// Spline segment point evaluation functions, for a given t [0.0f .. 1.0f] +// Get (evaluate) spline point: Linear +static int rl_GetSplinePointLinear(lua_State *L) { - int result = GetMouseWheelMove(); - LuaPush_int(L, result); + Vector2 startPos = RLUA_CHECK_Vector2(L, 1); + Vector2 endPos = RLUA_CHECK_Vector2(L, 2); + float t = (float)luaL_checknumber(L, 3); + Vector2 result = GetSplinePointLinear(startPos, endPos, t); + RLUA_PUSH_Vector2(L, result); return 1; } -// Input-related functions: touch -// Returns touch position X for touch point 0 (relative to screen size) -int lua_GetTouchX(lua_State *L) +// Get (evaluate) spline point: B-Spline +static int rl_GetSplinePointBasis(lua_State *L) { - int result = GetTouchX(); - LuaPush_int(L, result); + Vector2 p1 = RLUA_CHECK_Vector2(L, 1); + Vector2 p2 = RLUA_CHECK_Vector2(L, 2); + Vector2 p3 = RLUA_CHECK_Vector2(L, 3); + Vector2 p4 = RLUA_CHECK_Vector2(L, 4); + float t = (float)luaL_checknumber(L, 5); + Vector2 result = GetSplinePointBasis(p1, p2, p3, p4, t); + RLUA_PUSH_Vector2(L, result); return 1; } -// Returns touch position Y for touch point 0 (relative to screen size) -int lua_GetTouchY(lua_State *L) +// Get (evaluate) spline point: Catmull-Rom +static int rl_GetSplinePointCatmullRom(lua_State *L) { - int result = GetTouchY(); - LuaPush_int(L, result); + Vector2 p1 = RLUA_CHECK_Vector2(L, 1); + Vector2 p2 = RLUA_CHECK_Vector2(L, 2); + Vector2 p3 = RLUA_CHECK_Vector2(L, 3); + Vector2 p4 = RLUA_CHECK_Vector2(L, 4); + float t = (float)luaL_checknumber(L, 5); + Vector2 result = GetSplinePointCatmullRom(p1, p2, p3, p4, t); + RLUA_PUSH_Vector2(L, result); return 1; } -// Returns touch position XY for a touch point index (relative to screen size) -int lua_GetTouchPosition(lua_State *L) +// Get (evaluate) spline point: Quadratic Bezier +static int rl_GetSplinePointBezierQuad(lua_State *L) { - int index = LuaGetArgument_int(L, 1); - Vector2 result = GetTouchPosition(index); - LuaPush_Vector2(L, result); + Vector2 p1 = RLUA_CHECK_Vector2(L, 1); + Vector2 c2 = RLUA_CHECK_Vector2(L, 2); + Vector2 p3 = RLUA_CHECK_Vector2(L, 3); + float t = (float)luaL_checknumber(L, 4); + Vector2 result = GetSplinePointBezierQuad(p1, c2, p3, t); + RLUA_PUSH_Vector2(L, result); return 1; } -//------------------------------------------------------------------------------------ -// raylib [gestures] module functions - Gestures and Touch Handling -//------------------------------------------------------------------------------------ - -// Enable a set of gestures using flags -int lua_SetGesturesEnabled(lua_State *L) +// Get (evaluate) spline point: Cubic Bezier +static int rl_GetSplinePointBezierCubic(lua_State *L) { - unsigned int gestureFlags = LuaGetArgument_unsigned(L, 1); - SetGesturesEnabled(gestureFlags); - return 0; + Vector2 p1 = RLUA_CHECK_Vector2(L, 1); + Vector2 c2 = RLUA_CHECK_Vector2(L, 2); + Vector2 c3 = RLUA_CHECK_Vector2(L, 3); + Vector2 p4 = RLUA_CHECK_Vector2(L, 4); + float t = (float)luaL_checknumber(L, 5); + Vector2 result = GetSplinePointBezierCubic(p1, c2, c3, p4, t); + RLUA_PUSH_Vector2(L, result); + return 1; } -// Check if a gesture have been detected -int lua_IsGestureDetected(lua_State *L) +// Basic shapes collision detection functions +// Check collision between two rectangles +static int rl_CheckCollisionRecs(lua_State *L) { - int gesture = LuaGetArgument_int(L, 1); - bool result = IsGestureDetected(gesture); - LuaPush_bool(L, result); + Rectangle rec1 = RLUA_CHECK_Rectangle(L, 1); + Rectangle rec2 = RLUA_CHECK_Rectangle(L, 2); + bool result = CheckCollisionRecs(rec1, rec2); + lua_pushboolean(L, result); return 1; } -// Get latest detected gesture -int lua_GetGestureDetected(lua_State *L) +// Check collision between two circles +static int rl_CheckCollisionCircles(lua_State *L) { - int result = GetGestureDetected(); - LuaPush_int(L, result); + Vector2 center1 = RLUA_CHECK_Vector2(L, 1); + float radius1 = (float)luaL_checknumber(L, 2); + Vector2 center2 = RLUA_CHECK_Vector2(L, 3); + float radius2 = (float)luaL_checknumber(L, 4); + bool result = CheckCollisionCircles(center1, radius1, center2, radius2); + lua_pushboolean(L, result); return 1; } -// Get touch points count -int lua_GetTouchPointsCount(lua_State *L) +// Check collision between circle and rectangle +static int rl_CheckCollisionCircleRec(lua_State *L) { - int result = GetTouchPointsCount(); - LuaPush_int(L, result); + Vector2 center = RLUA_CHECK_Vector2(L, 1); + float radius = (float)luaL_checknumber(L, 2); + Rectangle rec = RLUA_CHECK_Rectangle(L, 3); + bool result = CheckCollisionCircleRec(center, radius, rec); + lua_pushboolean(L, result); return 1; } -// Get gesture hold time in milliseconds -int lua_GetGestureHoldDuration(lua_State *L) +// Check if circle collides with a line created betweeen two points [p1] and [p2] +static int rl_CheckCollisionCircleLine(lua_State *L) { - float result = GetGestureHoldDuration(); - LuaPush_float(L, result); + Vector2 center = RLUA_CHECK_Vector2(L, 1); + float radius = (float)luaL_checknumber(L, 2); + Vector2 p1 = RLUA_CHECK_Vector2(L, 3); + Vector2 p2 = RLUA_CHECK_Vector2(L, 4); + bool result = CheckCollisionCircleLine(center, radius, p1, p2); + lua_pushboolean(L, result); return 1; } -// Get gesture drag vector -int lua_GetGestureDragVector(lua_State *L) +// Check if point is inside rectangle +static int rl_CheckCollisionPointRec(lua_State *L) { - Vector2 result = GetGestureDragVector(); - LuaPush_Vector2(L, result); + Vector2 point = RLUA_CHECK_Vector2(L, 1); + Rectangle rec = RLUA_CHECK_Rectangle(L, 2); + bool result = CheckCollisionPointRec(point, rec); + lua_pushboolean(L, result); return 1; } -// Get gesture drag angle -int lua_GetGestureDragAngle(lua_State *L) +// Check if point is inside circle +static int rl_CheckCollisionPointCircle(lua_State *L) { - float result = GetGestureDragAngle(); - LuaPush_float(L, result); + Vector2 point = RLUA_CHECK_Vector2(L, 1); + Vector2 center = RLUA_CHECK_Vector2(L, 2); + float radius = (float)luaL_checknumber(L, 3); + bool result = CheckCollisionPointCircle(point, center, radius); + lua_pushboolean(L, result); return 1; } -// Get gesture pinch delta -int lua_GetGesturePinchVector(lua_State *L) +// Check if point is inside a triangle +static int rl_CheckCollisionPointTriangle(lua_State *L) { - Vector2 result = GetGesturePinchVector(); - LuaPush_Vector2(L, result); + Vector2 point = RLUA_CHECK_Vector2(L, 1); + Vector2 p1 = RLUA_CHECK_Vector2(L, 2); + Vector2 p2 = RLUA_CHECK_Vector2(L, 3); + Vector2 p3 = RLUA_CHECK_Vector2(L, 4); + bool result = CheckCollisionPointTriangle(point, p1, p2, p3); + lua_pushboolean(L, result); return 1; } -// Get gesture pinch angle -int lua_GetGesturePinchAngle(lua_State *L) +// Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold] +static int rl_CheckCollisionPointLine(lua_State *L) { - float result = GetGesturePinchAngle(); - LuaPush_float(L, result); + Vector2 point = RLUA_CHECK_Vector2(L, 1); + Vector2 p1 = RLUA_CHECK_Vector2(L, 2); + Vector2 p2 = RLUA_CHECK_Vector2(L, 3); + int threshold = (int)luaL_checkinteger(L, 4); + bool result = CheckCollisionPointLine(point, p1, p2, threshold); + lua_pushboolean(L, result); return 1; } -//------------------------------------------------------------------------------------ -// raylib [camera] module functions - Camera System -//------------------------------------------------------------------------------------ - -// Set camera mode (multiple camera modes available) -int lua_SetCameraMode(lua_State *L) +// Check if point is within a polygon described by array of vertices +static int rl_CheckCollisionPointPoly(lua_State *L) { - Camera camera = LuaGetArgument_Camera(L, 1); - int mode = LuaGetArgument_int(L, 2); - SetCameraMode(camera, mode); - return 0; + Vector2 point = RLUA_CHECK_Vector2(L, 1); + const Vector2 * points = (const Vector2 *)lua_touserdata(L, 2); + int pointCount = (int)luaL_checkinteger(L, 3); + bool result = CheckCollisionPointPoly(point, points, pointCount); + lua_pushboolean(L, result); + return 1; } -// Update camera position for selected mode -int lua_UpdateCamera(lua_State *L) +// Check the collision between two lines defined by two points each, returns collision point by reference +static int rl_CheckCollisionLines(lua_State *L) { - Camera camera = LuaGetArgument_Camera(L, 1); - UpdateCamera(camera); - return 0; + Vector2 startPos1 = RLUA_CHECK_Vector2(L, 1); + Vector2 endPos1 = RLUA_CHECK_Vector2(L, 2); + Vector2 startPos2 = RLUA_CHECK_Vector2(L, 3); + Vector2 endPos2 = RLUA_CHECK_Vector2(L, 4); + Vector2 collisionPoint = RLUA_CHECK_Vector2(L, 5); + bool result = CheckCollisionLines(startPos1, endPos1, startPos2, endPos2, &collisionPoint); + RLUA_WRITEBACK_Vector2(L, 5, collisionPoint); + lua_pushboolean(L, result); + return 1; } -// Set camera pan key to combine with mouse movement (free camera) -int lua_SetCameraPanControl(lua_State *L) +// Get collision rectangle for two rectangles collision +static int rl_GetCollisionRec(lua_State *L) { - int panKey = LuaGetArgument_int(L, 1); - SetCameraPanControl(panKey); - return 0; + Rectangle rec1 = RLUA_CHECK_Rectangle(L, 1); + Rectangle rec2 = RLUA_CHECK_Rectangle(L, 2); + Rectangle result = GetCollisionRec(rec1, rec2); + RLUA_PUSH_Rectangle(L, result); + return 1; } -// Set camera alt key to combine with mouse movement (free camera) -int lua_SetCameraAltControl(lua_State *L) +// ------------------------------------------------------------------------------------ +// Texture Loading and Drawing Functions (Module: textures) +// ------------------------------------------------------------------------------------ +// Image loading functions +// NOTE: These functions do not require GPU access +// Load image from file into CPU memory (RAM) +static int rl_LoadImage(lua_State *L) { - int altKey = LuaGetArgument_int(L, 1); - SetCameraAltControl(altKey); - return 0; + const char * fileName = luaL_checkstring(L, 1); + Image result = LoadImage(fileName); + RLUA_PUSH_Resource(L, &result, sizeof(Image), "Image"); + return 1; } -// Set camera smooth zoom key to combine with mouse (free camera) -int lua_SetCameraSmoothZoomControl(lua_State *L) +// Load image from RAW file data +static int rl_LoadImageRaw(lua_State *L) { - int szKey = LuaGetArgument_int(L, 1); - SetCameraSmoothZoomControl(szKey); - return 0; + const char * fileName = luaL_checkstring(L, 1); + int width = (int)luaL_checkinteger(L, 2); + int height = (int)luaL_checkinteger(L, 3); + int format = (int)luaL_checkinteger(L, 4); + int headerSize = (int)luaL_checkinteger(L, 5); + Image result = LoadImageRaw(fileName, width, height, format, headerSize); + RLUA_PUSH_Resource(L, &result, sizeof(Image), "Image"); + return 1; } -// Set camera move controls (1st person and 3rd person cameras) -int lua_SetCameraMoveControls(lua_State *L) +// Load image sequence from file (frames appended to image.data) +static int rl_LoadImageAnim(lua_State *L) { - int frontKey = LuaGetArgument_int(L, 1); - int backKey = LuaGetArgument_int(L, 2); - int rightKey = LuaGetArgument_int(L, 3); - int leftKey = LuaGetArgument_int(L, 4); - int upKey = LuaGetArgument_int(L, 5); - int downKey = LuaGetArgument_int(L, 6); - SetCameraMoveControls(frontKey, backKey, rightKey, leftKey, upKey, downKey); - return 0; + const char * fileName = luaL_checkstring(L, 1); + int * frames = (int *)lua_touserdata(L, 2); + Image result = LoadImageAnim(fileName, frames); + RLUA_PUSH_Resource(L, &result, sizeof(Image), "Image"); + return 1; } -//------------------------------------------------------------------------------------ -// raylib [shapes] module functions - Basic Shapes Drawing -//------------------------------------------------------------------------------------ - -// Draw a pixel -int lua_DrawPixel(lua_State *L) +// Load image sequence from memory buffer +static int rl_LoadImageAnimFromMemory(lua_State *L) { - int posX = LuaGetArgument_int(L, 1); - int posY = LuaGetArgument_int(L, 2); - Color color = LuaGetArgument_Color(L, 3); - DrawPixel(posX, posY, color); - return 0; + const char * fileType = luaL_checkstring(L, 1); + const unsigned char * fileData = (const unsigned char *)lua_touserdata(L, 2); + int dataSize = (int)luaL_checkinteger(L, 3); + int * frames = (int *)lua_touserdata(L, 4); + Image result = LoadImageAnimFromMemory(fileType, fileData, dataSize, frames); + RLUA_PUSH_Resource(L, &result, sizeof(Image), "Image"); + return 1; } -// Draw a pixel (Vector version) -int lua_DrawPixelV(lua_State *L) +// Load image from memory buffer, fileType refers to extension: i.e. '.png' +static int rl_LoadImageFromMemory(lua_State *L) { - Vector2 position = LuaGetArgument_Vector2(L, 1); - Color color = LuaGetArgument_Color(L, 2); - DrawPixelV(position, color); - return 0; + const char * fileType = luaL_checkstring(L, 1); + const unsigned char * fileData = (const unsigned char *)lua_touserdata(L, 2); + int dataSize = (int)luaL_checkinteger(L, 3); + Image result = LoadImageFromMemory(fileType, fileData, dataSize); + RLUA_PUSH_Resource(L, &result, sizeof(Image), "Image"); + return 1; } -// Draw a line -int lua_DrawLine(lua_State *L) +// Load image from GPU texture data +static int rl_LoadImageFromTexture(lua_State *L) { - int startPosX = LuaGetArgument_int(L, 1); - int startPosY = LuaGetArgument_int(L, 2); - int endPosX = LuaGetArgument_int(L, 3); - int endPosY = LuaGetArgument_int(L, 4); - Color color = LuaGetArgument_Color(L, 5); - DrawLine(startPosX, startPosY, endPosX, endPosY, color); - return 0; + Texture2D texture = *(Texture2D*)RLUA_CHECK_Resource(L, 1, "Texture2D"); + Image result = LoadImageFromTexture(texture); + RLUA_PUSH_Resource(L, &result, sizeof(Image), "Image"); + return 1; } -// Draw a line (Vector version) -int lua_DrawLineV(lua_State *L) +// Load image from screen buffer and (screenshot) +static int rl_LoadImageFromScreen(lua_State *L) { - Vector2 startPos = LuaGetArgument_Vector2(L, 1); - Vector2 endPos = LuaGetArgument_Vector2(L, 2); - Color color = LuaGetArgument_Color(L, 3); - DrawLineV(startPos, endPos, color); - return 0; + Image result = LoadImageFromScreen(); + RLUA_PUSH_Resource(L, &result, sizeof(Image), "Image"); + return 1; } -// Draw a line defining thickness -int lua_DrawLineEx(lua_State *L) +// Check if an image is valid (data and parameters) +static int rl_IsImageValid(lua_State *L) { - Vector2 startPos = LuaGetArgument_Vector2(L, 1); - Vector2 endPos = LuaGetArgument_Vector2(L, 2); - float thick = LuaGetArgument_float(L, 3); - Color color = LuaGetArgument_Color(L, 4); - DrawLineEx(startPos, endPos, thick, color); - return 0; + Image image = *(Image*)RLUA_CHECK_Resource(L, 1, "Image"); + bool result = IsImageValid(image); + lua_pushboolean(L, result); + return 1; } -// Draw a line using cubic-bezier curves in-out -int lua_DrawLineBezier(lua_State *L) +// Unload image from CPU memory (RAM) +static int rl_UnloadImage(lua_State *L) { - Vector2 startPos = LuaGetArgument_Vector2(L, 1); - Vector2 endPos = LuaGetArgument_Vector2(L, 2); - float thick = LuaGetArgument_float(L, 3); - Color color = LuaGetArgument_Color(L, 4); - DrawLineBezier(startPos, endPos, thick, color); + Image image = *(Image*)RLUA_CHECK_Resource(L, 1, "Image"); + UnloadImage(image); return 0; } -// Draw a color-filled circle -int lua_DrawCircle(lua_State *L) +// Export image data to file, returns true on success +static int rl_ExportImage(lua_State *L) { - int centerX = LuaGetArgument_int(L, 1); - int centerY = LuaGetArgument_int(L, 2); - float radius = LuaGetArgument_float(L, 3); - Color color = LuaGetArgument_Color(L, 4); - DrawCircle(centerX, centerY, radius, color); - return 0; + Image image = *(Image*)RLUA_CHECK_Resource(L, 1, "Image"); + const char * fileName = luaL_checkstring(L, 2); + bool result = ExportImage(image, fileName); + lua_pushboolean(L, result); + return 1; } -// Draw a gradient-filled circle -int lua_DrawCircleGradient(lua_State *L) +// Export image to memory buffer, memory must be MemFree() +static int rl_ExportImageToMemory(lua_State *L) { - int centerX = LuaGetArgument_int(L, 1); - int centerY = LuaGetArgument_int(L, 2); - float radius = LuaGetArgument_float(L, 3); - Color color1 = LuaGetArgument_Color(L, 4); - Color color2 = LuaGetArgument_Color(L, 5); - DrawCircleGradient(centerX, centerY, radius, color1, color2); - return 0; + Image image = *(Image*)RLUA_CHECK_Resource(L, 1, "Image"); + const char * fileType = luaL_checkstring(L, 2); + int fileSize = 0; + unsigned char * result = ExportImageToMemory(image, fileType, &fileSize); + RLUA_PUSH_View(L, result, fileSize, "unsigned char", true); + return 1; } -// Draw a color-filled circle (Vector version) -int lua_DrawCircleV(lua_State *L) +// Export image as code file defining an array of bytes, returns true on success +static int rl_ExportImageAsCode(lua_State *L) { - Vector2 center = LuaGetArgument_Vector2(L, 1); - float radius = LuaGetArgument_float(L, 2); - Color color = LuaGetArgument_Color(L, 3); - DrawCircleV(center, radius, color); - return 0; + Image image = *(Image*)RLUA_CHECK_Resource(L, 1, "Image"); + const char * fileName = luaL_checkstring(L, 2); + bool result = ExportImageAsCode(image, fileName); + lua_pushboolean(L, result); + return 1; } -// Draw circle outline -int lua_DrawCircleLines(lua_State *L) +// Image generation functions +// Generate image: plain color +static int rl_GenImageColor(lua_State *L) { - int centerX = LuaGetArgument_int(L, 1); - int centerY = LuaGetArgument_int(L, 2); - float radius = LuaGetArgument_float(L, 3); - Color color = LuaGetArgument_Color(L, 4); - DrawCircleLines(centerX, centerY, radius, color); - return 0; + int width = (int)luaL_checkinteger(L, 1); + int height = (int)luaL_checkinteger(L, 2); + Color color = RLUA_CHECK_Color(L, 3); + Image result = GenImageColor(width, height, color); + RLUA_PUSH_Resource(L, &result, sizeof(Image), "Image"); + return 1; } -// Draw a color-filled rectangle -int lua_DrawRectangle(lua_State *L) +// Generate image: linear gradient, direction in degrees [0..360], 0=Vertical gradient +static int rl_GenImageGradientLinear(lua_State *L) { - int posX = LuaGetArgument_int(L, 1); - int posY = LuaGetArgument_int(L, 2); - int width = LuaGetArgument_int(L, 3); - int height = LuaGetArgument_int(L, 4); - Color color = LuaGetArgument_Color(L, 5); - DrawRectangle(posX, posY, width, height, color); - return 0; + int width = (int)luaL_checkinteger(L, 1); + int height = (int)luaL_checkinteger(L, 2); + int direction = (int)luaL_checkinteger(L, 3); + Color start = RLUA_CHECK_Color(L, 4); + Color end = RLUA_CHECK_Color(L, 5); + Image result = GenImageGradientLinear(width, height, direction, start, end); + RLUA_PUSH_Resource(L, &result, sizeof(Image), "Image"); + return 1; } -// Draw a color-filled rectangle (Vector version) -int lua_DrawRectangleV(lua_State *L) +// Generate image: radial gradient +static int rl_GenImageGradientRadial(lua_State *L) { - Vector2 position = LuaGetArgument_Vector2(L, 1); - Vector2 size = LuaGetArgument_Vector2(L, 2); - Color color = LuaGetArgument_Color(L, 3); - DrawRectangleV(position, size, color); - return 0; + int width = (int)luaL_checkinteger(L, 1); + int height = (int)luaL_checkinteger(L, 2); + float density = (float)luaL_checknumber(L, 3); + Color inner = RLUA_CHECK_Color(L, 4); + Color outer = RLUA_CHECK_Color(L, 5); + Image result = GenImageGradientRadial(width, height, density, inner, outer); + RLUA_PUSH_Resource(L, &result, sizeof(Image), "Image"); + return 1; } -// Draw a color-filled rectangle -int lua_DrawRectangleRec(lua_State *L) +// Generate image: square gradient +static int rl_GenImageGradientSquare(lua_State *L) { - Rectangle rec = LuaGetArgument_Rectangle(L, 1); - Color color = LuaGetArgument_Color(L, 2); - DrawRectangleRec(rec, color); - return 0; + int width = (int)luaL_checkinteger(L, 1); + int height = (int)luaL_checkinteger(L, 2); + float density = (float)luaL_checknumber(L, 3); + Color inner = RLUA_CHECK_Color(L, 4); + Color outer = RLUA_CHECK_Color(L, 5); + Image result = GenImageGradientSquare(width, height, density, inner, outer); + RLUA_PUSH_Resource(L, &result, sizeof(Image), "Image"); + return 1; } -// Draw a color-filled rectangle with pro parameters -int lua_DrawRectanglePro(lua_State *L) -{ - Rectangle rec = LuaGetArgument_Rectangle(L, 1); - Vector2 origin = LuaGetArgument_Vector2(L, 2); - float rotation = LuaGetArgument_float(L, 3); - Color color = LuaGetArgument_Color(L, 4); - DrawRectanglePro(rec, origin, rotation, color); - return 0; +// Generate image: checked +static int rl_GenImageChecked(lua_State *L) +{ + int width = (int)luaL_checkinteger(L, 1); + int height = (int)luaL_checkinteger(L, 2); + int checksX = (int)luaL_checkinteger(L, 3); + int checksY = (int)luaL_checkinteger(L, 4); + Color col1 = RLUA_CHECK_Color(L, 5); + Color col2 = RLUA_CHECK_Color(L, 6); + Image result = GenImageChecked(width, height, checksX, checksY, col1, col2); + RLUA_PUSH_Resource(L, &result, sizeof(Image), "Image"); + return 1; } -// Draw a vertical-gradient-filled rectangle -int lua_DrawRectangleGradientV(lua_State *L) +// Generate image: white noise +static int rl_GenImageWhiteNoise(lua_State *L) { - int posX = LuaGetArgument_int(L, 1); - int posY = LuaGetArgument_int(L, 2); - int width = LuaGetArgument_int(L, 3); - int height = LuaGetArgument_int(L, 4); - Color color1 = LuaGetArgument_Color(L, 5); - Color color2 = LuaGetArgument_Color(L, 6); - DrawRectangleGradientV(posX, posY, width, height, color1, color2); - return 0; + int width = (int)luaL_checkinteger(L, 1); + int height = (int)luaL_checkinteger(L, 2); + float factor = (float)luaL_checknumber(L, 3); + Image result = GenImageWhiteNoise(width, height, factor); + RLUA_PUSH_Resource(L, &result, sizeof(Image), "Image"); + return 1; } -// Draw a horizontal-gradient-filled rectangle -int lua_DrawRectangleGradientH(lua_State *L) +// Generate image: perlin noise +static int rl_GenImagePerlinNoise(lua_State *L) { - int posX = LuaGetArgument_int(L, 1); - int posY = LuaGetArgument_int(L, 2); - int width = LuaGetArgument_int(L, 3); - int height = LuaGetArgument_int(L, 4); - Color color1 = LuaGetArgument_Color(L, 5); - Color color2 = LuaGetArgument_Color(L, 6); - DrawRectangleGradientH(posX, posY, width, height, color1, color2); - return 0; + int width = (int)luaL_checkinteger(L, 1); + int height = (int)luaL_checkinteger(L, 2); + int offsetX = (int)luaL_checkinteger(L, 3); + int offsetY = (int)luaL_checkinteger(L, 4); + float scale = (float)luaL_checknumber(L, 5); + Image result = GenImagePerlinNoise(width, height, offsetX, offsetY, scale); + RLUA_PUSH_Resource(L, &result, sizeof(Image), "Image"); + return 1; } -// Draw a gradient-filled rectangle with custom vertex colors -int lua_DrawRectangleGradientEx(lua_State *L) +// Generate image: cellular algorithm, bigger tileSize means bigger cells +static int rl_GenImageCellular(lua_State *L) { - Rectangle rec = LuaGetArgument_Rectangle(L, 1); - Color col1 = LuaGetArgument_Color(L, 2); - Color col2 = LuaGetArgument_Color(L, 3); - Color col3 = LuaGetArgument_Color(L, 4); - Color col4 = LuaGetArgument_Color(L, 5); - DrawRectangleGradientEx(rec, col1, col2, col3, col4); - return 0; + int width = (int)luaL_checkinteger(L, 1); + int height = (int)luaL_checkinteger(L, 2); + int tileSize = (int)luaL_checkinteger(L, 3); + Image result = GenImageCellular(width, height, tileSize); + RLUA_PUSH_Resource(L, &result, sizeof(Image), "Image"); + return 1; } -// Draw rectangle outline -int lua_DrawRectangleLines(lua_State *L) +// Generate image: grayscale image from text data +static int rl_GenImageText(lua_State *L) { - int posX = LuaGetArgument_int(L, 1); - int posY = LuaGetArgument_int(L, 2); - int width = LuaGetArgument_int(L, 3); - int height = LuaGetArgument_int(L, 4); - Color color = LuaGetArgument_Color(L, 5); - DrawRectangleLines(posX, posY, width, height, color); - return 0; + int width = (int)luaL_checkinteger(L, 1); + int height = (int)luaL_checkinteger(L, 2); + const char * text = luaL_checkstring(L, 3); + Image result = GenImageText(width, height, text); + RLUA_PUSH_Resource(L, &result, sizeof(Image), "Image"); + return 1; } -// Draw rectangle outline with extended parameters -int lua_DrawRectangleLinesEx(lua_State *L) +// Image manipulation functions +// Create an image duplicate (useful for transformations) +static int rl_ImageCopy(lua_State *L) { - Rectangle rec = LuaGetArgument_Rectangle(L, 1); - int lineThick = LuaGetArgument_int(L, 2); - Color color = LuaGetArgument_Color(L, 3); - DrawRectangleLinesEx(rec, lineThick, color); - return 0; + Image image = *(Image*)RLUA_CHECK_Resource(L, 1, "Image"); + Image result = ImageCopy(image); + RLUA_PUSH_Resource(L, &result, sizeof(Image), "Image"); + return 1; } -// Draw a color-filled triangle -int lua_DrawTriangle(lua_State *L) +// Create an image from another image piece +static int rl_ImageFromImage(lua_State *L) { - Vector2 v1 = LuaGetArgument_Vector2(L, 1); - Vector2 v2 = LuaGetArgument_Vector2(L, 2); - Vector2 v3 = LuaGetArgument_Vector2(L, 3); - Color color = LuaGetArgument_Color(L, 4); - DrawTriangle(v1, v2, v3, color); - return 0; + Image image = *(Image*)RLUA_CHECK_Resource(L, 1, "Image"); + Rectangle rec = RLUA_CHECK_Rectangle(L, 2); + Image result = ImageFromImage(image, rec); + RLUA_PUSH_Resource(L, &result, sizeof(Image), "Image"); + return 1; } -// Draw triangle outline -int lua_DrawTriangleLines(lua_State *L) +// Create an image from a selected channel of another image (GRAYSCALE) +static int rl_ImageFromChannel(lua_State *L) { - Vector2 v1 = LuaGetArgument_Vector2(L, 1); - Vector2 v2 = LuaGetArgument_Vector2(L, 2); - Vector2 v3 = LuaGetArgument_Vector2(L, 3); - Color color = LuaGetArgument_Color(L, 4); - DrawTriangleLines(v1, v2, v3, color); - return 0; + Image image = *(Image*)RLUA_CHECK_Resource(L, 1, "Image"); + int selectedChannel = (int)luaL_checkinteger(L, 2); + Image result = ImageFromChannel(image, selectedChannel); + RLUA_PUSH_Resource(L, &result, sizeof(Image), "Image"); + return 1; } -// Draw a regular polygon (Vector version) -int lua_DrawPoly(lua_State *L) +// Create an image from text (default font) +static int rl_ImageText(lua_State *L) { - Vector2 center = LuaGetArgument_Vector2(L, 1); - int sides = LuaGetArgument_int(L, 2); - float radius = LuaGetArgument_float(L, 3); - float rotation = LuaGetArgument_float(L, 4); - Color color = LuaGetArgument_Color(L, 5); - DrawPoly(center, sides, radius, rotation, color); - return 0; + const char * text = luaL_checkstring(L, 1); + int fontSize = (int)luaL_checkinteger(L, 2); + Color color = RLUA_CHECK_Color(L, 3); + Image result = ImageText(text, fontSize, color); + RLUA_PUSH_Resource(L, &result, sizeof(Image), "Image"); + return 1; } +// Create an image from text (custom sprite font) +static int rl_ImageTextEx(lua_State *L) +{ + Font font = *(Font*)RLUA_CHECK_Resource(L, 1, "Font"); + const char * text = luaL_checkstring(L, 2); + float fontSize = (float)luaL_checknumber(L, 3); + float spacing = (float)luaL_checknumber(L, 4); + Color tint = RLUA_CHECK_Color(L, 5); + Image result = ImageTextEx(font, text, fontSize, spacing, tint); + RLUA_PUSH_Resource(L, &result, sizeof(Image), "Image"); + return 1; +} -// TODO: This thing should be here? -#define GET_TABLE(type, name, index) \ - type* name = 0; \ - size_t name##_size = 0; \ - { \ - size_t sz = 0; \ - luaL_checktype(L, index, LUA_TTABLE); \ - lua_pushnil(L); \ - while (lua_next(L, index)) { \ - LuaGetArgument_##type(L, -1); \ - sz++; \ - lua_pop(L, 1); \ - } \ - name = calloc(sz, sizeof(type)); \ - sz = 0; \ - lua_pushnil(L); \ - while (lua_next(L, index)) { \ - name[sz] = LuaGetArgument_##type(L, -1); \ - sz++; \ - lua_pop(L, 1); \ - } \ - lua_pop(L, 1); \ - name##_size = sz; \ - } - -// WARNING: Draw a closed polygon defined by points -int lua_DrawPolyEx(lua_State* L) +// Convert image data to desired format +static int rl_ImageFormat(lua_State *L) { - GET_TABLE(Vector2, arg1, 1); - Color arg2 = LuaGetArgument_Color(L, 2); - DrawPolyEx(arg1, arg1_size, arg2); - free(arg1); + Image * image = (Image *)lua_touserdata(L, 1); + int newFormat = (int)luaL_checkinteger(L, 2); + ImageFormat(image, newFormat); return 0; } -// WARNING: Draw polygon lines -int lua_DrawPolyExLines(lua_State* L) +// Convert image to POT (power-of-two) +static int rl_ImageToPOT(lua_State *L) { - GET_TABLE(Vector2, arg1, 1); - Color arg2 = LuaGetArgument_Color(L, 2); - DrawPolyExLines(arg1, arg1_size, arg2); - free(arg1); + Image * image = (Image *)lua_touserdata(L, 1); + Color fill = RLUA_CHECK_Color(L, 2); + ImageToPOT(image, fill); return 0; } -// Check collision between two rectangles -int lua_CheckCollisionRecs(lua_State *L) +// Crop an image to a defined rectangle +static int rl_ImageCrop(lua_State *L) { - Rectangle rec1 = LuaGetArgument_Rectangle(L, 1); - Rectangle rec2 = LuaGetArgument_Rectangle(L, 2); - bool result = CheckCollisionRecs(rec1, rec2); - LuaPush_bool(L, result); - return 1; + Image * image = (Image *)lua_touserdata(L, 1); + Rectangle crop = RLUA_CHECK_Rectangle(L, 2); + ImageCrop(image, crop); + return 0; } -// Check collision between two circles -int lua_CheckCollisionCircles(lua_State *L) +// Crop image depending on alpha value +static int rl_ImageAlphaCrop(lua_State *L) { - Vector2 center1 = LuaGetArgument_Vector2(L, 1); - float radius1 = LuaGetArgument_float(L, 2); - Vector2 center2 = LuaGetArgument_Vector2(L, 3); - float radius2 = LuaGetArgument_float(L, 4); - bool result = CheckCollisionCircles(center1, radius1, center2, radius2); - LuaPush_bool(L, result); - return 1; + Image * image = (Image *)lua_touserdata(L, 1); + float threshold = (float)luaL_checknumber(L, 2); + ImageAlphaCrop(image, threshold); + return 0; } -// Check collision between circle and rectangle -int lua_CheckCollisionCircleRec(lua_State *L) +// Clear alpha channel to desired color +static int rl_ImageAlphaClear(lua_State *L) { - Vector2 center = LuaGetArgument_Vector2(L, 1); - float radius = LuaGetArgument_float(L, 2); - Rectangle rec = LuaGetArgument_Rectangle(L, 3); - bool result = CheckCollisionCircleRec(center, radius, rec); - LuaPush_bool(L, result); - return 1; + Image * image = (Image *)lua_touserdata(L, 1); + Color color = RLUA_CHECK_Color(L, 2); + float threshold = (float)luaL_checknumber(L, 3); + ImageAlphaClear(image, color, threshold); + return 0; } -// Get collision rectangle for two rectangles collision -int lua_GetCollisionRec(lua_State *L) +// Apply alpha mask to image +static int rl_ImageAlphaMask(lua_State *L) { - Rectangle rec1 = LuaGetArgument_Rectangle(L, 1); - Rectangle rec2 = LuaGetArgument_Rectangle(L, 2); - Rectangle result = GetCollisionRec(rec1, rec2); - LuaPush_Rectangle(L, result); - return 1; + Image * image = (Image *)lua_touserdata(L, 1); + Image alphaMask = *(Image*)RLUA_CHECK_Resource(L, 2, "Image"); + ImageAlphaMask(image, alphaMask); + return 0; } -// Check if point is inside rectangle -int lua_CheckCollisionPointRec(lua_State *L) +// Premultiply alpha channel +static int rl_ImageAlphaPremultiply(lua_State *L) { - Vector2 point = LuaGetArgument_Vector2(L, 1); - Rectangle rec = LuaGetArgument_Rectangle(L, 2); - bool result = CheckCollisionPointRec(point, rec); - LuaPush_bool(L, result); - return 1; + Image * image = (Image *)lua_touserdata(L, 1); + ImageAlphaPremultiply(image); + return 0; } -// Check if point is inside circle -int lua_CheckCollisionPointCircle(lua_State *L) +// Apply Gaussian blur using a box blur approximation +static int rl_ImageBlurGaussian(lua_State *L) { - Vector2 point = LuaGetArgument_Vector2(L, 1); - Vector2 center = LuaGetArgument_Vector2(L, 2); - float radius = LuaGetArgument_float(L, 3); - bool result = CheckCollisionPointCircle(point, center, radius); - LuaPush_bool(L, result); - return 1; + Image * image = (Image *)lua_touserdata(L, 1); + int blurSize = (int)luaL_checkinteger(L, 2); + ImageBlurGaussian(image, blurSize); + return 0; } -// Check if point is inside a triangle -int lua_CheckCollisionPointTriangle(lua_State *L) +// Apply custom square convolution kernel to image +static int rl_ImageKernelConvolution(lua_State *L) { - Vector2 point = LuaGetArgument_Vector2(L, 1); - Vector2 p1 = LuaGetArgument_Vector2(L, 2); - Vector2 p2 = LuaGetArgument_Vector2(L, 3); - Vector2 p3 = LuaGetArgument_Vector2(L, 4); - bool result = CheckCollisionPointTriangle(point, p1, p2, p3); - LuaPush_bool(L, result); - return 1; + Image * image = (Image *)lua_touserdata(L, 1); + const float * kernel = (const float *)lua_touserdata(L, 2); + int kernelSize = (int)luaL_checkinteger(L, 3); + ImageKernelConvolution(image, kernel, kernelSize); + return 0; } -//------------------------------------------------------------------------------------ -// raylib [textures] module functions - Texture Loading and Drawing -//------------------------------------------------------------------------------------ - -// Load image from file into CPU memory (RAM) -int lua_LoadImage(lua_State *L) +// Resize image (Bicubic scaling algorithm) +static int rl_ImageResize(lua_State *L) { - const char *fileName = LuaGetArgument_string(L, 1); - Image result = LoadImage(fileName); - LuaPush_Image(L, result); - return 1; + Image * image = (Image *)lua_touserdata(L, 1); + int newWidth = (int)luaL_checkinteger(L, 2); + int newHeight = (int)luaL_checkinteger(L, 3); + ImageResize(image, newWidth, newHeight); + return 0; } -// WARNING: Load image from Color array data (RGBA - 32bit) -int lua_LoadImageEx(lua_State* L) +// Resize image (Nearest-Neighbor scaling algorithm) +static int rl_ImageResizeNN(lua_State *L) { - // TODO: arg1 parameter is a Color array... - - GET_TABLE(Color, arg1, 1); // Color *pixels - int arg2 = LuaGetArgument_int(L, 2); - int arg3 = LuaGetArgument_int(L, 3); - Image result = LoadImageEx(arg1, arg2, arg3); // ISSUE: #3 number expected, got no value - LuaPush_Image(L, result); - free(arg1); - return 1; + Image * image = (Image *)lua_touserdata(L, 1); + int newWidth = (int)luaL_checkinteger(L, 2); + int newHeight = (int)luaL_checkinteger(L, 3); + ImageResizeNN(image, newWidth, newHeight); + return 0; } -// WARNING: Load image from raw data with pro parameters -int lua_LoadImagePro(lua_State* L) +// Resize canvas and fill with color +static int rl_ImageResizeCanvas(lua_State *L) { - // TODO: arg1 parameter is a void pointer... - - void *arg1 = LuaGetArgument_ptr(L, 1); - int arg2 = LuaGetArgument_int(L, 2); - int arg3 = LuaGetArgument_int(L, 3); - int arg4 = LuaGetArgument_int(L, 4); - Image result = LoadImagePro(arg1, arg2, arg3, arg4); - LuaPush_Image(L, result); - free(arg1); - return 1; + Image * image = (Image *)lua_touserdata(L, 1); + int newWidth = (int)luaL_checkinteger(L, 2); + int newHeight = (int)luaL_checkinteger(L, 3); + int offsetX = (int)luaL_checkinteger(L, 4); + int offsetY = (int)luaL_checkinteger(L, 5); + Color fill = RLUA_CHECK_Color(L, 6); + ImageResizeCanvas(image, newWidth, newHeight, offsetX, offsetY, fill); + return 0; } -// Load image from RAW file data -int lua_LoadImageRaw(lua_State *L) +// Compute all mipmap levels for a provided image +static int rl_ImageMipmaps(lua_State *L) { - const char *fileName = LuaGetArgument_string(L, 1); - int width = LuaGetArgument_int(L, 2); - int height = LuaGetArgument_int(L, 3); - int format = LuaGetArgument_int(L, 4); - int headerSize = LuaGetArgument_int(L, 5); - Image result = LoadImageRaw(fileName, width, height, format, headerSize); - LuaPush_Image(L, result); - return 1; + Image * image = (Image *)lua_touserdata(L, 1); + ImageMipmaps(image); + return 0; } -// Export image as a PNG file -int lua_ExportImage(lua_State *L) +// Dither image data to 16bpp or lower (Floyd-Steinberg dithering) +static int rl_ImageDither(lua_State *L) { - const char *fileName = LuaGetArgument_string(L, 1); - Image image = LuaGetArgument_Image(L, 2); - ExportImage(fileName, image); + Image * image = (Image *)lua_touserdata(L, 1); + int rBpp = (int)luaL_checkinteger(L, 2); + int gBpp = (int)luaL_checkinteger(L, 3); + int bBpp = (int)luaL_checkinteger(L, 4); + int aBpp = (int)luaL_checkinteger(L, 5); + ImageDither(image, rBpp, gBpp, bBpp, aBpp); return 0; } -// Load texture from file into GPU memory (VRAM) -int lua_LoadTexture(lua_State *L) +// Flip image vertically +static int rl_ImageFlipVertical(lua_State *L) { - const char *fileName = LuaGetArgument_string(L, 1); - Texture2D result = LoadTexture(fileName); - LuaPush_Texture2D(L, result); - return 1; + Image * image = (Image *)lua_touserdata(L, 1); + ImageFlipVertical(image); + return 0; } -// Load texture from image data -int lua_LoadTextureFromImage(lua_State *L) +// Flip image horizontally +static int rl_ImageFlipHorizontal(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - Texture2D result = LoadTextureFromImage(image); - LuaPush_Texture2D(L, result); - return 1; + Image * image = (Image *)lua_touserdata(L, 1); + ImageFlipHorizontal(image); + return 0; } -// Load texture for rendering (framebuffer) -int lua_LoadRenderTexture(lua_State *L) +// Rotate image by input angle in degrees (-359 to 359) +static int rl_ImageRotate(lua_State *L) { - int width = LuaGetArgument_int(L, 1); - int height = LuaGetArgument_int(L, 2); - RenderTexture2D result = LoadRenderTexture(width, height); - LuaPush_RenderTexture2D(L, result); - return 1; + Image * image = (Image *)lua_touserdata(L, 1); + int degrees = (int)luaL_checkinteger(L, 2); + ImageRotate(image, degrees); + return 0; } -// Unload image from CPU memory (RAM) -int lua_UnloadImage(lua_State *L) +// Rotate image clockwise 90deg +static int rl_ImageRotateCW(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - UnloadImage(image); + Image * image = (Image *)lua_touserdata(L, 1); + ImageRotateCW(image); return 0; } -// Unload texture from GPU memory (VRAM) -int lua_UnloadTexture(lua_State *L) +// Rotate image counter-clockwise 90deg +static int rl_ImageRotateCCW(lua_State *L) { - Texture2D texture = LuaGetArgument_Texture2D(L, 1); - UnloadTexture(texture); + Image * image = (Image *)lua_touserdata(L, 1); + ImageRotateCCW(image); return 0; } -// Unload render texture from GPU memory (VRAM) -int lua_UnloadRenderTexture(lua_State *L) +// Modify image color: tint +static int rl_ImageColorTint(lua_State *L) { - RenderTexture2D target = LuaGetArgument_RenderTexture2D(L, 1); - UnloadRenderTexture(target); + Image * image = (Image *)lua_touserdata(L, 1); + Color color = RLUA_CHECK_Color(L, 2); + ImageColorTint(image, color); return 0; } -// WARNING: Get pixel data from image as a Color struct array -int lua_GetImageData(lua_State* L) +// Modify image color: invert +static int rl_ImageColorInvert(lua_State *L) { - // TODO: return value is a Color array - - Image arg1 = LuaGetArgument_Image(L, 1); - Color *result = GetImageData(arg1); - lua_createtable(L, arg1.width*arg1.height, 0); - for (int i = 0; i < arg1.width*arg1.height; i++) - { - LuaPush_Color(L, result[i]); - lua_rawseti(L, -2, i + 1); - } - free(result); - return 1; + Image * image = (Image *)lua_touserdata(L, 1); + ImageColorInvert(image); + return 0; } -// WARNING: Get pixel data from image as Vector4 array (float normalized) -int lua_GetImageDataNormalized(lua_State *L) +// Modify image color: grayscale +static int rl_ImageColorGrayscale(lua_State *L) { - // TODO. - - return 1; + Image * image = (Image *)lua_touserdata(L, 1); + ImageColorGrayscale(image); + return 0; } -// Get pixel data size in bytes (image or texture) -int lua_GetPixelDataSize(lua_State *L) +// Modify image color: contrast (-100 to 100) +static int rl_ImageColorContrast(lua_State *L) { - int width = LuaGetArgument_int(L, 1); - int height = LuaGetArgument_int(L, 2); - int format = LuaGetArgument_int(L, 3); - int result = GetPixelDataSize(width, height, format); - LuaPush_int(L, result); - return 1; + Image * image = (Image *)lua_touserdata(L, 1); + float contrast = (float)luaL_checknumber(L, 2); + ImageColorContrast(image, contrast); + return 0; } -// Get pixel data from GPU texture and return an Image -int lua_GetTextureData(lua_State *L) +// Modify image color: brightness (-255 to 255) +static int rl_ImageColorBrightness(lua_State *L) { - Texture2D texture = LuaGetArgument_Texture2D(L, 1); - Image result = GetTextureData(texture); - LuaPush_Image(L, result); - return 1; + Image * image = (Image *)lua_touserdata(L, 1); + int brightness = (int)luaL_checkinteger(L, 2); + ImageColorBrightness(image, brightness); + return 0; } - -// WARNING: Update GPU texture with new data -int lua_UpdateTexture(lua_State* L) +// Modify image color: replace color +static int rl_ImageColorReplace(lua_State *L) { - // TODO: arg2 parameters is a void pointer... - - Texture2D arg1 = LuaGetArgument_Texture2D(L, 1); - void *arg2 = LuaGetArgument_ptr(L, 2); - UpdateTexture(arg1, arg2); // ISSUE: #2 string expected, got table -> GetImageData() returns a table! + Image * image = (Image *)lua_touserdata(L, 1); + Color color = RLUA_CHECK_Color(L, 2); + Color replace = RLUA_CHECK_Color(L, 3); + ImageColorReplace(image, color, replace); return 0; } -//---------------------------------------------------------------------------------- -// Image manipulation functions -//---------------------------------------------------------------------------------- - -// Create an image duplicate (useful for transformations) -int lua_ImageCopy(lua_State *L) +// Load color data from image as a Color array (RGBA - 32bit) +static int rl_LoadImageColors(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - Image result = ImageCopy(image); - LuaPush_Image(L, result); + Image image = *(Image*)RLUA_CHECK_Resource(L, 1, "Image"); + Color * result = LoadImageColors(image); + lua_pushlightuserdata(L, result); return 1; } -// Convert image to POT (power-of-two) -int lua_ImageToPOT(lua_State *L) +// Load colors palette from image as a Color array (RGBA - 32bit) +static int rl_LoadImagePalette(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - Color fillColor = LuaGetArgument_Color(L, 2); - ImageToPOT(image, fillColor); - return 0; + Image image = *(Image*)RLUA_CHECK_Resource(L, 1, "Image"); + int maxPaletteSize = (int)luaL_checkinteger(L, 2); + int colorCount = 0; + Color * result = LoadImagePalette(image, maxPaletteSize, &colorCount); + RLUA_PUSH_View(L, result, colorCount, "Color", true); + return 1; } -// Convert image data to desired format -int lua_ImageFormat(lua_State *L) +// Unload color data loaded with LoadImageColors() +static int rl_UnloadImageColors(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - int newFormat = LuaGetArgument_int(L, 2); - ImageFormat(image, newFormat); + Color * colors = (Color *)lua_touserdata(L, 1); + UnloadImageColors(colors); return 0; } -// Apply alpha mask to image -int lua_ImageAlphaMask(lua_State *L) +// Unload colors palette loaded with LoadImagePalette() +static int rl_UnloadImagePalette(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - Image alphaMask = LuaGetArgument_Image(L, 2); - ImageAlphaMask(image, alphaMask); + Color * colors = (Color *)lua_touserdata(L, 1); + UnloadImagePalette(colors); return 0; } -// Clear alpha channel to desired color -int lua_ImageAlphaClear(lua_State *L) +// Get image alpha border rectangle +static int rl_GetImageAlphaBorder(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - Color color = LuaGetArgument_Color(L, 2); - float threshold = LuaGetArgument_float(L, 3); - ImageAlphaClear(image, color, threshold); - return 0; + Image image = *(Image*)RLUA_CHECK_Resource(L, 1, "Image"); + float threshold = (float)luaL_checknumber(L, 2); + Rectangle result = GetImageAlphaBorder(image, threshold); + RLUA_PUSH_Rectangle(L, result); + return 1; } -// Crop image depending on alpha value -int lua_ImageAlphaCrop(lua_State *L) +// Get image pixel color at (x, y) position +static int rl_GetImageColor(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - float threshold = LuaGetArgument_float(L, 2); - ImageAlphaCrop(image, threshold); - return 0; + Image image = *(Image*)RLUA_CHECK_Resource(L, 1, "Image"); + int x = (int)luaL_checkinteger(L, 2); + int y = (int)luaL_checkinteger(L, 3); + Color result = GetImageColor(image, x, y); + RLUA_PUSH_Color(L, result); + return 1; } -// Premultiply alpha channel -int lua_ImageAlphaPremultiply(lua_State *L) +// Image drawing functions +// NOTE: Image software-rendering functions (CPU) +// Clear image background with given color +static int rl_ImageClearBackground(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - ImageAlphaPremultiply(image); + Image * dst = (Image *)lua_touserdata(L, 1); + Color color = RLUA_CHECK_Color(L, 2); + ImageClearBackground(dst, color); return 0; } -// Crop an image to a defined rectangle -int lua_ImageCrop(lua_State *L) +// Draw pixel within an image +static int rl_ImageDrawPixel(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - Rectangle crop = LuaGetArgument_Rectangle(L, 2); - ImageCrop(image, crop); + Image * dst = (Image *)lua_touserdata(L, 1); + int posX = (int)luaL_checkinteger(L, 2); + int posY = (int)luaL_checkinteger(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + ImageDrawPixel(dst, posX, posY, color); return 0; } -// Resize image (bilinear filtering) -int lua_ImageResize(lua_State *L) +// Draw pixel within an image (Vector version) +static int rl_ImageDrawPixelV(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - int newWidth = LuaGetArgument_int(L, 2); - int newHeight = LuaGetArgument_int(L, 3); - ImageResize(image, newWidth, newHeight); + Image * dst = (Image *)lua_touserdata(L, 1); + Vector2 position = RLUA_CHECK_Vector2(L, 2); + Color color = RLUA_CHECK_Color(L, 3); + ImageDrawPixelV(dst, position, color); return 0; } -// Resize image (Nearest-Neighbor scaling algorithm) -int lua_ImageResizeNN(lua_State *L) +// Draw line within an image +static int rl_ImageDrawLine(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - int newWidth = LuaGetArgument_int(L, 2); - int newHeight = LuaGetArgument_int(L, 3); - ImageResizeNN(image, newWidth, newHeight); + Image * dst = (Image *)lua_touserdata(L, 1); + int startPosX = (int)luaL_checkinteger(L, 2); + int startPosY = (int)luaL_checkinteger(L, 3); + int endPosX = (int)luaL_checkinteger(L, 4); + int endPosY = (int)luaL_checkinteger(L, 5); + Color color = RLUA_CHECK_Color(L, 6); + ImageDrawLine(dst, startPosX, startPosY, endPosX, endPosY, color); return 0; } -// Resize canvas and fill with color -int lua_ImageResizeCanvas(lua_State *L) +// Draw line within an image (Vector version) +static int rl_ImageDrawLineV(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - int newWidth = LuaGetArgument_int(L, 2); - int newHeight = LuaGetArgument_int(L, 3); - int offsetX = LuaGetArgument_int(L, 4); - int offsetY = LuaGetArgument_int(L, 5); - Color color = LuaGetArgument_Color(L, 6); - ImageResizeCanvas(image, newWidth, newHeight, offsetX, offsetY, color); + Image * dst = (Image *)lua_touserdata(L, 1); + Vector2 start = RLUA_CHECK_Vector2(L, 2); + Vector2 end = RLUA_CHECK_Vector2(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + ImageDrawLineV(dst, start, end, color); return 0; } -// Generate all mipmap levels for a provided image -int lua_ImageMipmaps(lua_State *L) +// Draw a line defining thickness within an image +static int rl_ImageDrawLineEx(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - ImageMipmaps(image); + Image * dst = (Image *)lua_touserdata(L, 1); + Vector2 start = RLUA_CHECK_Vector2(L, 2); + Vector2 end = RLUA_CHECK_Vector2(L, 3); + int thick = (int)luaL_checkinteger(L, 4); + Color color = RLUA_CHECK_Color(L, 5); + ImageDrawLineEx(dst, start, end, thick, color); return 0; } -// Dither image data to 16bpp or lower (Floyd-Steinberg dithering) -int lua_ImageDither(lua_State *L) +// Draw a filled circle within an image +static int rl_ImageDrawCircle(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - int rBpp = LuaGetArgument_int(L, 2); - int gBpp = LuaGetArgument_int(L, 3); - int bBpp = LuaGetArgument_int(L, 4); - int aBpp = LuaGetArgument_int(L, 5); - ImageDither(image, rBpp, gBpp, bBpp, aBpp); + Image * dst = (Image *)lua_touserdata(L, 1); + int centerX = (int)luaL_checkinteger(L, 2); + int centerY = (int)luaL_checkinteger(L, 3); + int radius = (int)luaL_checkinteger(L, 4); + Color color = RLUA_CHECK_Color(L, 5); + ImageDrawCircle(dst, centerX, centerY, radius, color); return 0; } -// Create an image from text (default font) -int lua_ImageText(lua_State *L) +// Draw a filled circle within an image (Vector version) +static int rl_ImageDrawCircleV(lua_State *L) { - const char *text = LuaGetArgument_string(L, 1); - int fontSize = LuaGetArgument_int(L, 2); - Color color = LuaGetArgument_Color(L, 3); - Image result = ImageText(text, fontSize, color); - LuaPush_Image(L, result); - return 1; + Image * dst = (Image *)lua_touserdata(L, 1); + Vector2 center = RLUA_CHECK_Vector2(L, 2); + int radius = (int)luaL_checkinteger(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + ImageDrawCircleV(dst, center, radius, color); + return 0; } -// Create an image from text (custom sprite font) -int lua_ImageTextEx(lua_State *L) +// Draw circle outline within an image +static int rl_ImageDrawCircleLines(lua_State *L) { - Font font = LuaGetArgument_Font(L, 1); - const char *text = LuaGetArgument_string(L, 2); - float fontSize = LuaGetArgument_float(L, 3); - float spacing = LuaGetArgument_float(L, 4); - Color tint = LuaGetArgument_Color(L, 5); - Image result = ImageTextEx(font, text, fontSize, spacing, tint); - LuaPush_Image(L, result); - return 1; + Image * dst = (Image *)lua_touserdata(L, 1); + int centerX = (int)luaL_checkinteger(L, 2); + int centerY = (int)luaL_checkinteger(L, 3); + int radius = (int)luaL_checkinteger(L, 4); + Color color = RLUA_CHECK_Color(L, 5); + ImageDrawCircleLines(dst, centerX, centerY, radius, color); + return 0; } -// Draw a source image within a destination image -int lua_ImageDraw(lua_State *L) +// Draw circle outline within an image (Vector version) +static int rl_ImageDrawCircleLinesV(lua_State *L) { - Image dst = LuaGetArgument_Image(L, 1); - Image src = LuaGetArgument_Image(L, 2); - Rectangle srcRec = LuaGetArgument_Rectangle(L, 3); - Rectangle dstRec = LuaGetArgument_Rectangle(L, 4); - ImageDraw(&dst, src, srcRec, dstRec); // WARNING: & required! + Image * dst = (Image *)lua_touserdata(L, 1); + Vector2 center = RLUA_CHECK_Vector2(L, 2); + int radius = (int)luaL_checkinteger(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + ImageDrawCircleLinesV(dst, center, radius, color); return 0; } // Draw rectangle within an image -int lua_ImageDrawRectangle(lua_State *L) +static int rl_ImageDrawRectangle(lua_State *L) { - Image dst = LuaGetArgument_Image(L, 1); - Vector2 position = LuaGetArgument_Vector2(L, 2); - Rectangle rec = LuaGetArgument_Rectangle(L, 3); - Color color = LuaGetArgument_Color(L, 4); - ImageDrawRectangle(dst, position, rec, color); + Image * dst = (Image *)lua_touserdata(L, 1); + int posX = (int)luaL_checkinteger(L, 2); + int posY = (int)luaL_checkinteger(L, 3); + int width = (int)luaL_checkinteger(L, 4); + int height = (int)luaL_checkinteger(L, 5); + Color color = RLUA_CHECK_Color(L, 6); + ImageDrawRectangle(dst, posX, posY, width, height, color); return 0; } -// Draw text (default font) within an image (destination) -int lua_ImageDrawText(lua_State *L) +// Draw rectangle within an image (Vector version) +static int rl_ImageDrawRectangleV(lua_State *L) { - Image dst = LuaGetArgument_Image(L, 1); - Vector2 position = LuaGetArgument_Vector2(L, 2); - const char *text = LuaGetArgument_string(L, 3); // WARNING: all const char require * - int fontSize = LuaGetArgument_int(L, 4); - Color color = LuaGetArgument_Color(L, 5); - ImageDrawText(&dst, position, text, fontSize, color); + Image * dst = (Image *)lua_touserdata(L, 1); + Vector2 position = RLUA_CHECK_Vector2(L, 2); + Vector2 size = RLUA_CHECK_Vector2(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + ImageDrawRectangleV(dst, position, size, color); return 0; } -// Draw text (custom sprite font) within an image (destination) -int lua_ImageDrawTextEx(lua_State *L) +// Draw rectangle within an image +static int rl_ImageDrawRectangleRec(lua_State *L) { - Image dst = LuaGetArgument_Image(L, 1); - Vector2 position = LuaGetArgument_Vector2(L, 2); - Font font = LuaGetArgument_Font(L, 3); - const char *text = LuaGetArgument_string(L, 4); - float fontSize = LuaGetArgument_float(L, 5); - float spacing = LuaGetArgument_float(L, 6); - Color color = LuaGetArgument_Color(L, 7); - ImageDrawTextEx(&dst, position, font, text, fontSize, spacing, color); + Image * dst = (Image *)lua_touserdata(L, 1); + Rectangle rec = RLUA_CHECK_Rectangle(L, 2); + Color color = RLUA_CHECK_Color(L, 3); + ImageDrawRectangleRec(dst, rec, color); return 0; } -// Flip image vertically -int lua_ImageFlipVertical(lua_State *L) +// Draw rectangle lines within an image +static int rl_ImageDrawRectangleLines(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - ImageFlipVertical(image); + Image * dst = (Image *)lua_touserdata(L, 1); + Rectangle rec = RLUA_CHECK_Rectangle(L, 2); + int thick = (int)luaL_checkinteger(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + ImageDrawRectangleLines(dst, rec, thick, color); return 0; } -// Flip image horizontally -int lua_ImageFlipHorizontal(lua_State *L) +// Draw triangle within an image +static int rl_ImageDrawTriangle(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - ImageFlipHorizontal(image); + Image * dst = (Image *)lua_touserdata(L, 1); + Vector2 v1 = RLUA_CHECK_Vector2(L, 2); + Vector2 v2 = RLUA_CHECK_Vector2(L, 3); + Vector2 v3 = RLUA_CHECK_Vector2(L, 4); + Color color = RLUA_CHECK_Color(L, 5); + ImageDrawTriangle(dst, v1, v2, v3, color); return 0; } -// Rotate image clockwise 90deg -int lua_ImageRotateCW(lua_State *L) +// Draw triangle with interpolated colors within an image +static int rl_ImageDrawTriangleEx(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - ImageRotateCW(image); + Image * dst = (Image *)lua_touserdata(L, 1); + Vector2 v1 = RLUA_CHECK_Vector2(L, 2); + Vector2 v2 = RLUA_CHECK_Vector2(L, 3); + Vector2 v3 = RLUA_CHECK_Vector2(L, 4); + Color c1 = RLUA_CHECK_Color(L, 5); + Color c2 = RLUA_CHECK_Color(L, 6); + Color c3 = RLUA_CHECK_Color(L, 7); + ImageDrawTriangleEx(dst, v1, v2, v3, c1, c2, c3); return 0; } -// Rotate image counter-clockwise 90deg -int lua_ImageRotateCCW(lua_State *L) +// Draw triangle outline within an image +static int rl_ImageDrawTriangleLines(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - ImageRotateCCW(image); + Image * dst = (Image *)lua_touserdata(L, 1); + Vector2 v1 = RLUA_CHECK_Vector2(L, 2); + Vector2 v2 = RLUA_CHECK_Vector2(L, 3); + Vector2 v3 = RLUA_CHECK_Vector2(L, 4); + Color color = RLUA_CHECK_Color(L, 5); + ImageDrawTriangleLines(dst, v1, v2, v3, color); return 0; } -// Modify image color: tint -int lua_ImageColorTint(lua_State *L) +// Draw a triangle fan defined by points within an image (first vertex is the center) +static int rl_ImageDrawTriangleFan(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - Color color = LuaGetArgument_Color(L, 2); - ImageColorTint(image, color); + Image * dst = (Image *)lua_touserdata(L, 1); + const Vector2 * points = (const Vector2 *)lua_touserdata(L, 2); + int pointCount = (int)luaL_checkinteger(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + ImageDrawTriangleFan(dst, points, pointCount, color); return 0; } -// Modify image color: invert -int lua_ImageColorInvert(lua_State *L) +// Draw a triangle strip defined by points within an image +static int rl_ImageDrawTriangleStrip(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - ImageColorInvert(image); + Image * dst = (Image *)lua_touserdata(L, 1); + const Vector2 * points = (const Vector2 *)lua_touserdata(L, 2); + int pointCount = (int)luaL_checkinteger(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + ImageDrawTriangleStrip(dst, points, pointCount, color); return 0; } -// Modify image color: grayscale -int lua_ImageColorGrayscale(lua_State *L) +// Draw a source image within a destination image (tint applied to source) +static int rl_ImageDraw(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - ImageColorGrayscale(image); + Image * dst = (Image *)lua_touserdata(L, 1); + Image src = *(Image*)RLUA_CHECK_Resource(L, 2, "Image"); + Rectangle srcRec = RLUA_CHECK_Rectangle(L, 3); + Rectangle dstRec = RLUA_CHECK_Rectangle(L, 4); + Color tint = RLUA_CHECK_Color(L, 5); + ImageDraw(dst, src, srcRec, dstRec, tint); return 0; } -// Modify image color: contrast (-100 to 100) -int lua_ImageColorContrast(lua_State *L) +// Draw text (using default font) within an image (destination) +static int rl_ImageDrawText(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - float contrast = LuaGetArgument_float(L, 2); - ImageColorContrast(image, contrast); + Image * dst = (Image *)lua_touserdata(L, 1); + const char * text = luaL_checkstring(L, 2); + int posX = (int)luaL_checkinteger(L, 3); + int posY = (int)luaL_checkinteger(L, 4); + int fontSize = (int)luaL_checkinteger(L, 5); + Color color = RLUA_CHECK_Color(L, 6); + ImageDrawText(dst, text, posX, posY, fontSize, color); return 0; } -// Modify image color: brightness (-255 to 255) -int lua_ImageColorBrightness(lua_State *L) +// Draw text (custom sprite font) within an image (destination) +static int rl_ImageDrawTextEx(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - int brightness = LuaGetArgument_int(L, 2); - ImageColorBrightness(image, brightness); + Image * dst = (Image *)lua_touserdata(L, 1); + Font font = *(Font*)RLUA_CHECK_Resource(L, 2, "Font"); + const char * text = luaL_checkstring(L, 3); + Vector2 position = RLUA_CHECK_Vector2(L, 4); + float fontSize = (float)luaL_checknumber(L, 5); + float spacing = (float)luaL_checknumber(L, 6); + Color tint = RLUA_CHECK_Color(L, 7); + ImageDrawTextEx(dst, font, text, position, fontSize, spacing, tint); return 0; } -// Modify image color: replace color -int lua_ImageColorReplace(lua_State *L) +// Texture loading functions +// NOTE: These functions require GPU access +// Load texture from file into GPU memory (VRAM) +static int rl_LoadTexture(lua_State *L) { - Image image = LuaGetArgument_Image(L, 1); - Color color = LuaGetArgument_Color(L, 2); - Color replace = LuaGetArgument_Color(L, 3); - ImageColorReplace(image, color, replace); - return 0; + const char * fileName = luaL_checkstring(L, 1); + Texture2D result = LoadTexture(fileName); + RLUA_PUSH_Resource(L, &result, sizeof(Texture2D), "Texture2D"); + return 1; } -// Image generation functions -// Generate image: plain color -int lua_GenImageColor(lua_State *L) +// Load texture from image data +static int rl_LoadTextureFromImage(lua_State *L) { - int width = LuaGetArgument_int(L, 1); - int height = LuaGetArgument_int(L, 2); - Color color = LuaGetArgument_Color(L, 3); - Image result = GenImageColor(width, height, color); - LuaPush_Image(L, result); + Image image = *(Image*)RLUA_CHECK_Resource(L, 1, "Image"); + Texture2D result = LoadTextureFromImage(image); + RLUA_PUSH_Resource(L, &result, sizeof(Texture2D), "Texture2D"); return 1; } -// Generate image: vertical gradient -int lua_GenImageGradientV(lua_State *L) +// Load cubemap from image, multiple image cubemap layouts supported +static int rl_LoadTextureCubemap(lua_State *L) { - int width = LuaGetArgument_int(L, 1); - int height = LuaGetArgument_int(L, 2); - Color top = LuaGetArgument_Color(L, 3); - Color bottom = LuaGetArgument_Color(L, 4); - Image result = GenImageGradientV(width, height, top, bottom); - LuaPush_Image(L, result); + Image image = *(Image*)RLUA_CHECK_Resource(L, 1, "Image"); + int layout = (int)luaL_checkinteger(L, 2); + TextureCubemap result = LoadTextureCubemap(image, layout); + RLUA_PUSH_Resource(L, &result, sizeof(TextureCubemap), "TextureCubemap"); return 1; } -// Generate image: horizontal gradient -int lua_GenImageGradientH(lua_State *L) +// Load texture for rendering (framebuffer) +static int rl_LoadRenderTexture(lua_State *L) { - int width = LuaGetArgument_int(L, 1); - int height = LuaGetArgument_int(L, 2); - Color left = LuaGetArgument_Color(L, 3); - Color right = LuaGetArgument_Color(L, 4); - Image result = GenImageGradientH(width, height, left, right); - LuaPush_Image(L, result); + int width = (int)luaL_checkinteger(L, 1); + int height = (int)luaL_checkinteger(L, 2); + RenderTexture2D result = LoadRenderTexture(width, height); + RLUA_PUSH_Resource(L, &result, sizeof(RenderTexture2D), "RenderTexture2D"); return 1; } -// Generate image: radial gradient -int lua_GenImageGradientRadial(lua_State *L) +// Check if a texture is valid (loaded in GPU) +static int rl_IsTextureValid(lua_State *L) { - int width = LuaGetArgument_int(L, 1); - int height = LuaGetArgument_int(L, 2); - float density = LuaGetArgument_float(L, 3); - Color inner = LuaGetArgument_Color(L, 4); - Color outer = LuaGetArgument_Color(L, 5); - Image result = GenImageGradientRadial(width, height, density, inner, outer); - LuaPush_Image(L, result); + Texture2D texture = *(Texture2D*)RLUA_CHECK_Resource(L, 1, "Texture2D"); + bool result = IsTextureValid(texture); + lua_pushboolean(L, result); return 1; } -// Generate image: checked -int lua_GenImageChecked(lua_State *L) -{ - int width = LuaGetArgument_int(L, 1); - int height = LuaGetArgument_int(L, 2); - int checksX = LuaGetArgument_int(L, 3); - int checksY = LuaGetArgument_int(L, 4); - Color col1 = LuaGetArgument_Color(L, 5); - Color col2 = LuaGetArgument_Color(L, 6); - Image result = GenImageChecked(width, height, checksX, checksY, col1, col2); - LuaPush_Image(L, result); - return 1; +// Unload texture from GPU memory (VRAM) +static int rl_UnloadTexture(lua_State *L) +{ + Texture2D texture = *(Texture2D*)RLUA_CHECK_Resource(L, 1, "Texture2D"); + UnloadTexture(texture); + return 0; } -// Generate image: white noise -int lua_GenImageWhiteNoise(lua_State *L) +// Check if a render texture is valid (loaded in GPU) +static int rl_IsRenderTextureValid(lua_State *L) { - int width = LuaGetArgument_int(L, 1); - int height = LuaGetArgument_int(L, 2); - float factor = LuaGetArgument_float(L, 3); - Image result = GenImageWhiteNoise(width, height, factor); - LuaPush_Image(L, result); + RenderTexture2D target = *(RenderTexture2D*)RLUA_CHECK_Resource(L, 1, "RenderTexture2D"); + bool result = IsRenderTextureValid(target); + lua_pushboolean(L, result); return 1; } -// Generate image: perlin noise -int lua_GenImagePerlinNoise(lua_State *L) +// Unload render texture from GPU memory (VRAM) +static int rl_UnloadRenderTexture(lua_State *L) { - int width = LuaGetArgument_int(L, 1); - int height = LuaGetArgument_int(L, 2); - int offsetX = LuaGetArgument_int(L, 3); - int offsetY = LuaGetArgument_int(L, 4); - float scale = LuaGetArgument_float(L, 5); - Image result = GenImagePerlinNoise(width, height, offsetX, offsetY, scale); - LuaPush_Image(L, result); - return 1; + RenderTexture2D target = *(RenderTexture2D*)RLUA_CHECK_Resource(L, 1, "RenderTexture2D"); + UnloadRenderTexture(target); + return 0; } -// Generate image: cellular algorithm. Bigger tileSize means bigger cells -int lua_GenImageCellular(lua_State *L) +// Update GPU texture with new data (pixels should be able to fill texture) +static int rl_UpdateTexture(lua_State *L) { - int width = LuaGetArgument_int(L, 1); - int height = LuaGetArgument_int(L, 2); - int tileSize = LuaGetArgument_int(L, 3); - Image result = GenImageCellular(width, height, tileSize); - LuaPush_Image(L, result); - return 1; + Texture2D texture = *(Texture2D*)RLUA_CHECK_Resource(L, 1, "Texture2D"); + const void * pixels = (const void *)lua_touserdata(L, 2); + UpdateTexture(texture, pixels); + return 0; } -// Texture2D configuration functions +// Update GPU texture rectangle with new data (pixels and rec should fit in texture) +static int rl_UpdateTextureRec(lua_State *L) +{ + Texture2D texture = *(Texture2D*)RLUA_CHECK_Resource(L, 1, "Texture2D"); + Rectangle rec = RLUA_CHECK_Rectangle(L, 2); + const void * pixels = (const void *)lua_touserdata(L, 3); + UpdateTextureRec(texture, rec, pixels); + return 0; +} +// Texture configuration functions // Generate GPU mipmaps for a texture -int lua_GenTextureMipmaps(lua_State *L) +static int rl_GenTextureMipmaps(lua_State *L) { - Texture2D texture = LuaGetArgument_Texture2D(L, 1); + Texture2D * texture = (Texture2D *)lua_touserdata(L, 1); GenTextureMipmaps(texture); return 0; } // Set texture scaling filter mode -int lua_SetTextureFilter(lua_State *L) +static int rl_SetTextureFilter(lua_State *L) { - Texture2D texture = LuaGetArgument_Texture2D(L, 1); - int filterMode = LuaGetArgument_int(L, 2); - SetTextureFilter(texture, filterMode); + Texture2D texture = *(Texture2D*)RLUA_CHECK_Resource(L, 1, "Texture2D"); + int filter = (int)luaL_checkinteger(L, 2); + SetTextureFilter(texture, filter); return 0; } // Set texture wrapping mode -int lua_SetTextureWrap(lua_State *L) +static int rl_SetTextureWrap(lua_State *L) { - Texture2D texture = LuaGetArgument_Texture2D(L, 1); - int wrapMode = LuaGetArgument_int(L, 2); - SetTextureWrap(texture, wrapMode); + Texture2D texture = *(Texture2D*)RLUA_CHECK_Resource(L, 1, "Texture2D"); + int wrap = (int)luaL_checkinteger(L, 2); + SetTextureWrap(texture, wrap); return 0; } -// Texture2D drawing functions - +// Texture drawing functions // Draw a Texture2D -int lua_DrawTexture(lua_State *L) +static int rl_DrawTexture(lua_State *L) { - Texture2D texture = LuaGetArgument_Texture2D(L, 1); - int posX = LuaGetArgument_int(L, 2); - int posY = LuaGetArgument_int(L, 3); - Color tint = LuaGetArgument_Color(L, 4); + Texture2D texture = *(Texture2D*)RLUA_CHECK_Resource(L, 1, "Texture2D"); + int posX = (int)luaL_checkinteger(L, 2); + int posY = (int)luaL_checkinteger(L, 3); + Color tint = RLUA_CHECK_Color(L, 4); DrawTexture(texture, posX, posY, tint); return 0; } // Draw a Texture2D with position defined as Vector2 -int lua_DrawTextureV(lua_State *L) +static int rl_DrawTextureV(lua_State *L) { - Texture2D texture = LuaGetArgument_Texture2D(L, 1); - Vector2 position = LuaGetArgument_Vector2(L, 2); - Color tint = LuaGetArgument_Color(L, 3); + Texture2D texture = *(Texture2D*)RLUA_CHECK_Resource(L, 1, "Texture2D"); + Vector2 position = RLUA_CHECK_Vector2(L, 2); + Color tint = RLUA_CHECK_Color(L, 3); DrawTextureV(texture, position, tint); return 0; } // Draw a Texture2D with extended parameters -int lua_DrawTextureEx(lua_State *L) +static int rl_DrawTextureEx(lua_State *L) { - Texture2D texture = LuaGetArgument_Texture2D(L, 1); - Vector2 position = LuaGetArgument_Vector2(L, 2); - float rotation = LuaGetArgument_float(L, 3); - float scale = LuaGetArgument_float(L, 4); - Color tint = LuaGetArgument_Color(L, 5); + Texture2D texture = *(Texture2D*)RLUA_CHECK_Resource(L, 1, "Texture2D"); + Vector2 position = RLUA_CHECK_Vector2(L, 2); + float rotation = (float)luaL_checknumber(L, 3); + float scale = (float)luaL_checknumber(L, 4); + Color tint = RLUA_CHECK_Color(L, 5); DrawTextureEx(texture, position, rotation, scale, tint); return 0; } // Draw a part of a texture defined by a rectangle -int lua_DrawTextureRec(lua_State *L) +static int rl_DrawTextureRec(lua_State *L) { - Texture2D texture = LuaGetArgument_Texture2D(L, 1); - Rectangle sourceRec = LuaGetArgument_Rectangle(L, 2); - Vector2 position = LuaGetArgument_Vector2(L, 3); - Color tint = LuaGetArgument_Color(L, 4); - DrawTextureRec(texture, sourceRec, position, tint); + Texture2D texture = *(Texture2D*)RLUA_CHECK_Resource(L, 1, "Texture2D"); + Rectangle source = RLUA_CHECK_Rectangle(L, 2); + Vector2 position = RLUA_CHECK_Vector2(L, 3); + Color tint = RLUA_CHECK_Color(L, 4); + DrawTextureRec(texture, source, position, tint); return 0; } // Draw a part of a texture defined by a rectangle with 'pro' parameters -int lua_DrawTexturePro(lua_State *L) +static int rl_DrawTexturePro(lua_State *L) { - Texture2D texture = LuaGetArgument_Texture2D(L, 1); - Rectangle sourceRec = LuaGetArgument_Rectangle(L, 2); - Rectangle destRec = LuaGetArgument_Rectangle(L, 3); - Vector2 origin = LuaGetArgument_Vector2(L, 4); - float rotation = LuaGetArgument_float(L, 5); - Color tint = LuaGetArgument_Color(L, 6); - DrawTexturePro(texture, sourceRec, destRec, origin, rotation, tint); + Texture2D texture = *(Texture2D*)RLUA_CHECK_Resource(L, 1, "Texture2D"); + Rectangle source = RLUA_CHECK_Rectangle(L, 2); + Rectangle dest = RLUA_CHECK_Rectangle(L, 3); + Vector2 origin = RLUA_CHECK_Vector2(L, 4); + float rotation = (float)luaL_checknumber(L, 5); + Color tint = RLUA_CHECK_Color(L, 6); + DrawTexturePro(texture, source, dest, origin, rotation, tint); return 0; } -//------------------------------------------------------------------------------------ -// raylib [text] module functions - Font Loading and Text Drawing -//------------------------------------------------------------------------------------ - -// Get the default Font -int lua_GetFontDefault(lua_State *L) +// Draws a texture (or part of it) that stretches or shrinks nicely +static int rl_DrawTextureNPatch(lua_State *L) { - Font result = GetFontDefault(); - LuaPush_Font(L, result); - return 1; + Texture2D texture = *(Texture2D*)RLUA_CHECK_Resource(L, 1, "Texture2D"); + NPatchInfo nPatchInfo = RLUA_CHECK_NPatchInfo(L, 2); + Rectangle dest = RLUA_CHECK_Rectangle(L, 3); + Vector2 origin = RLUA_CHECK_Vector2(L, 4); + float rotation = (float)luaL_checknumber(L, 5); + Color tint = RLUA_CHECK_Color(L, 6); + DrawTextureNPatch(texture, nPatchInfo, dest, origin, rotation, tint); + return 0; } -// Load font from file into GPU memory (VRAM) -int lua_LoadFont(lua_State *L) +// Color/pixel related functions +// Check if two colors are equal +static int rl_ColorIsEqual(lua_State *L) { - const char *fileName = LuaGetArgument_string(L, 1); - Font result = LoadFont(fileName); - LuaPush_Font(L, result); + Color col1 = RLUA_CHECK_Color(L, 1); + Color col2 = RLUA_CHECK_Color(L, 2); + bool result = ColorIsEqual(col1, col2); + lua_pushboolean(L, result); return 1; } -// Load font from file with extended parameters -int lua_LoadFontEx(lua_State *L) +// Get color with alpha applied, alpha goes from 0.0f to 1.0f +static int rl_Fade(lua_State *L) { - const char *fileName = LuaGetArgument_string(L, 1); - int fontSize = LuaGetArgument_int(L, 2); - int charsCount = LuaGetArgument_int(L, 3); - int fontChars = LuaGetArgument_int(L, 4); - Font result = LoadFontEx(fileName, fontSize, charsCount, fontChars); - LuaPush_Font(L, result); + Color color = RLUA_CHECK_Color(L, 1); + float alpha = (float)luaL_checknumber(L, 2); + Color result = Fade(color, alpha); + RLUA_PUSH_Color(L, result); return 1; } -// Load font data for further use -int lua_LoadFontData(lua_State *L) +// Get hexadecimal value for a Color (0xRRGGBBAA) +static int rl_ColorToInt(lua_State *L) { - const char *fileName = LuaGetArgument_string(L, 1); - int fontSize = LuaGetArgument_int(L, 2); - int fontChars = LuaGetArgument_int(L, 3); - int charsCount = LuaGetArgument_int(L, 4); - bool sdf = LuaGetArgument_bool(L, 5); - CharInfo result = LoadFontData(fileName, fontSize, fontChars, charsCount, sdf); - LuaPush_CharInfo(L, result); + Color color = RLUA_CHECK_Color(L, 1); + int result = ColorToInt(color); + lua_pushinteger(L, result); return 1; } -// Generate image font atlas using chars info -int lua_GenImageFontAtlas(lua_State *L) +// Get Color normalized as float [0..1] +static int rl_ColorNormalize(lua_State *L) { - CharInfo chars = LuaGetArgument_CharInfo(L, 1); - int fontSize = LuaGetArgument_int(L, 2); - int charsCount = LuaGetArgument_int(L, 3); - int padding = LuaGetArgument_int(L, 4); - int packMethod = LuaGetArgument_int(L, 5); - Image result = GenImageFontAtlas(chars, fontSize, charsCount, padding, packMethod); - LuaPush_Image(L, result); + Color color = RLUA_CHECK_Color(L, 1); + Vector4 result = ColorNormalize(color); + RLUA_PUSH_Vector4(L, result); return 1; } -// Unload Font from GPU memory (VRAM) -int lua_UnloadFont(lua_State *L) +// Get Color from normalized values [0..1] +static int rl_ColorFromNormalized(lua_State *L) { - Font font = LuaGetArgument_Font(L, 1); - UnloadFont(font); - return 0; + Vector4 normalized = RLUA_CHECK_Vector4(L, 1); + Color result = ColorFromNormalized(normalized); + RLUA_PUSH_Color(L, result); + return 1; } -// Text drawing functions -// Shows current FPS -int lua_DrawFPS(lua_State *L) +// Get HSV values for a Color, hue [0..360], saturation/value [0..1] +static int rl_ColorToHSV(lua_State *L) { - int posX = LuaGetArgument_int(L, 1); - int posY = LuaGetArgument_int(L, 2); - DrawFPS(posX, posY); - return 0; + Color color = RLUA_CHECK_Color(L, 1); + Vector3 result = ColorToHSV(color); + RLUA_PUSH_Vector3(L, result); + return 1; } -// Draw text (using default font) -int lua_DrawText(lua_State *L) +// Get a Color from HSV values, hue [0..360], saturation/value [0..1] +static int rl_ColorFromHSV(lua_State *L) { - const char *text = LuaGetArgument_string(L, 1); - int posX = LuaGetArgument_int(L, 2); - int posY = LuaGetArgument_int(L, 3); - int fontSize = LuaGetArgument_int(L, 4); - Color color = LuaGetArgument_Color(L, 5); - DrawText(text, posX, posY, fontSize, color); - return 0; + float hue = (float)luaL_checknumber(L, 1); + float saturation = (float)luaL_checknumber(L, 2); + float value = (float)luaL_checknumber(L, 3); + Color result = ColorFromHSV(hue, saturation, value); + RLUA_PUSH_Color(L, result); + return 1; } -// WARNING: Draw text using font and additional parameters -int lua_DrawTextEx(lua_State *L) +// Get color multiplied with another color +static int rl_ColorTint(lua_State *L) { - Font font = LuaGetArgument_Font(L, 1); - const char *text = LuaGetArgument_string(L, 2); - Vector2 position = LuaGetArgument_Vector2(L, 3); - float fontSize = LuaGetArgument_float(L, 4); - float spacing = LuaGetArgument_float(L, 5); - Color tint = LuaGetArgument_Color(L, 6); - DrawTextEx(font, text, position, fontSize, spacing, tint); - return 0; + Color color = RLUA_CHECK_Color(L, 1); + Color tint = RLUA_CHECK_Color(L, 2); + Color result = ColorTint(color, tint); + RLUA_PUSH_Color(L, result); + return 1; } -// Text misc. functions -// Measure string width for default font -int lua_MeasureText(lua_State *L) +// Get color with brightness correction, brightness factor goes from -1.0f to 1.0f +static int rl_ColorBrightness(lua_State *L) { - const char *text = LuaGetArgument_string(L, 1); - int fontSize = LuaGetArgument_int(L, 2); - int result = MeasureText(text, fontSize); - LuaPush_int(L, result); + Color color = RLUA_CHECK_Color(L, 1); + float factor = (float)luaL_checknumber(L, 2); + Color result = ColorBrightness(color, factor); + RLUA_PUSH_Color(L, result); return 1; } -// Measure string size for Font -int lua_MeasureTextEx(lua_State *L) +// Get color with contrast correction, contrast values between -1.0f and 1.0f +static int rl_ColorContrast(lua_State *L) { - Font font = LuaGetArgument_Font(L, 1); - const char *text = LuaGetArgument_string(L, 2); - float fontSize = LuaGetArgument_float(L, 3); - float spacing = LuaGetArgument_float(L, 4); - Vector2 result = MeasureTextEx(font, text, fontSize, spacing); - LuaPush_Vector2(L, result); + Color color = RLUA_CHECK_Color(L, 1); + float contrast = (float)luaL_checknumber(L, 2); + Color result = ColorContrast(color, contrast); + RLUA_PUSH_Color(L, result); return 1; } -// WARNING: FormatText() can be replaced by Lua function: string.format() -// WARNING: SubText() can be replaced by Lua function: string.sub() - -// Get index position for a unicode character on font -int lua_GetGlyphIndex(lua_State *L) +// Get color with alpha applied, alpha goes from 0.0f to 1.0f +static int rl_ColorAlpha(lua_State *L) { - Font font = LuaGetArgument_Font(L, 1); - int character = LuaGetArgument_int(L, 2); - int result = GetGlyphIndex(font, character); - LuaPush_int(L, result); + Color color = RLUA_CHECK_Color(L, 1); + float alpha = (float)luaL_checknumber(L, 2); + Color result = ColorAlpha(color, alpha); + RLUA_PUSH_Color(L, result); return 1; } -//------------------------------------------------------------------------------------ -// raylib [models] module functions - Basic 3d Shapes Drawing Functions -//------------------------------------------------------------------------------------ - -// Draw a line in 3D world space -int lua_DrawLine3D(lua_State *L) +// Get src alpha-blended into dst color with tint +static int rl_ColorAlphaBlend(lua_State *L) { - Vector3 startPos = LuaGetArgument_Vector3(L, 1); - Vector3 endPos = LuaGetArgument_Vector3(L, 2); - Color color = LuaGetArgument_Color(L, 3); - DrawLine3D(startPos, endPos, color); - return 0; + Color dst = RLUA_CHECK_Color(L, 1); + Color src = RLUA_CHECK_Color(L, 2); + Color tint = RLUA_CHECK_Color(L, 3); + Color result = ColorAlphaBlend(dst, src, tint); + RLUA_PUSH_Color(L, result); + return 1; } -// Draw a circle in 3D world space -int lua_DrawCircle3D(lua_State *L) +// Get color lerp interpolation between two colors, factor [0.0f..1.0f] +static int rl_ColorLerp(lua_State *L) { - Vector3 center = LuaGetArgument_Vector3(L, 1); - float radius = LuaGetArgument_float(L, 2); - Vector3 rotationAxis = LuaGetArgument_Vector3(L, 3); - float rotationAngle = LuaGetArgument_float(L, 4); - Color color = LuaGetArgument_Color(L, 5); - DrawCircle3D(center, radius, rotationAxis, rotationAngle, color); - return 0; + Color color1 = RLUA_CHECK_Color(L, 1); + Color color2 = RLUA_CHECK_Color(L, 2); + float factor = (float)luaL_checknumber(L, 3); + Color result = ColorLerp(color1, color2, factor); + RLUA_PUSH_Color(L, result); + return 1; } -// Draw cube -int lua_DrawCube(lua_State *L) +// Get Color structure from hexadecimal value +static int rl_GetColor(lua_State *L) { - Vector3 position = LuaGetArgument_Vector3(L, 1); - float width = LuaGetArgument_float(L, 2); - float height = LuaGetArgument_float(L, 3); - float length = LuaGetArgument_float(L, 4); - Color color = LuaGetArgument_Color(L, 5); - DrawCube(position, width, height, length, color); - return 0; + unsigned int hexValue = (unsigned int)luaL_checkinteger(L, 1); + Color result = GetColor(hexValue); + RLUA_PUSH_Color(L, result); + return 1; } -// Draw cube (Vector version) -int lua_DrawCubeV(lua_State *L) +// Get Color from a source pixel pointer of certain format +static int rl_GetPixelColor(lua_State *L) { - Vector3 position = LuaGetArgument_Vector3(L, 1); - Vector3 size = LuaGetArgument_Vector3(L, 2); - Color color = LuaGetArgument_Color(L, 3); - DrawCubeV(position, size, color); - return 0; + void * srcPtr = lua_touserdata(L, 1); + int format = (int)luaL_checkinteger(L, 2); + Color result = GetPixelColor(srcPtr, format); + RLUA_PUSH_Color(L, result); + return 1; } -// Draw cube wires -int lua_DrawCubeWires(lua_State *L) +// Set color formatted into destination pixel pointer +static int rl_SetPixelColor(lua_State *L) { - Vector3 position = LuaGetArgument_Vector3(L, 1); - float width = LuaGetArgument_float(L, 2); - float height = LuaGetArgument_float(L, 3); - float length = LuaGetArgument_float(L, 4); - Color color = LuaGetArgument_Color(L, 5); - DrawCubeWires(position, width, height, length, color); + void * dstPtr = lua_touserdata(L, 1); + Color color = RLUA_CHECK_Color(L, 2); + int format = (int)luaL_checkinteger(L, 3); + SetPixelColor(dstPtr, color, format); return 0; } -// Draw cube textured -int lua_DrawCubeTexture(lua_State *L) +// Get pixel data size in bytes for certain format +static int rl_GetPixelDataSize(lua_State *L) { - Texture2D texture = LuaGetArgument_Texture2D(L, 1); - Vector3 position = LuaGetArgument_Vector3(L, 2); - float width = LuaGetArgument_float(L, 3); - float height = LuaGetArgument_float(L, 4); - float length = LuaGetArgument_float(L, 5); - Color color = LuaGetArgument_Color(L, 6); - DrawCubeTexture(texture, position, width, height, length, color); - return 0; + int width = (int)luaL_checkinteger(L, 1); + int height = (int)luaL_checkinteger(L, 2); + int format = (int)luaL_checkinteger(L, 3); + int result = GetPixelDataSize(width, height, format); + lua_pushinteger(L, result); + return 1; } -// Draw sphere -int lua_DrawSphere(lua_State *L) +// ------------------------------------------------------------------------------------ +// Font Loading and Text Drawing Functions (Module: text) +// ------------------------------------------------------------------------------------ +// Font loading/unloading functions +// Get the default Font +static int rl_GetFontDefault(lua_State *L) { - Vector3 centerPos = LuaGetArgument_Vector3(L, 1); - float radius = LuaGetArgument_float(L, 2); - Color color = LuaGetArgument_Color(L, 3); - DrawSphere(centerPos, radius, color); - return 0; + Font result = GetFontDefault(); + RLUA_PUSH_Resource(L, &result, sizeof(Font), "Font"); + return 1; } -// Draw sphere with extended parameters -int lua_DrawSphereEx(lua_State *L) +// Load font from file into GPU memory (VRAM) +static int rl_LoadFont(lua_State *L) { - Vector3 centerPos = LuaGetArgument_Vector3(L, 1); - float radius = LuaGetArgument_float(L, 2); - int rings = LuaGetArgument_int(L, 3); - int slices = LuaGetArgument_int(L, 4); - Color color = LuaGetArgument_Color(L, 5); - DrawSphereEx(centerPos, radius, rings, slices, color); - return 0; + const char * fileName = luaL_checkstring(L, 1); + Font result = LoadFont(fileName); + RLUA_PUSH_Resource(L, &result, sizeof(Font), "Font"); + return 1; } -// Draw sphere wires -int lua_DrawSphereWires(lua_State *L) +// Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height +static int rl_LoadFontEx(lua_State *L) { - Vector3 centerPos = LuaGetArgument_Vector3(L, 1); - float radius = LuaGetArgument_float(L, 2); - int rings = LuaGetArgument_int(L, 3); - int slices = LuaGetArgument_int(L, 4); - Color color = LuaGetArgument_Color(L, 5); - DrawSphereWires(centerPos, radius, rings, slices, color); - return 0; -} - -// Draw a cylinder/cone -int lua_DrawCylinder(lua_State *L) -{ - Vector3 position = LuaGetArgument_Vector3(L, 1); - float radiusTop = LuaGetArgument_float(L, 2); - float radiusBottom = LuaGetArgument_float(L, 3); - float height = LuaGetArgument_float(L, 4); - int slices = LuaGetArgument_int(L, 5); - Color color = LuaGetArgument_Color(L, 6); - DrawCylinder(position, radiusTop, radiusBottom, height, slices, color); - return 0; -} - -// Draw a cylinder/cone wires -int lua_DrawCylinderWires(lua_State *L) -{ - Vector3 position = LuaGetArgument_Vector3(L, 1); - float radiusTop = LuaGetArgument_float(L, 2); - float radiusBottom = LuaGetArgument_float(L, 3); - float height = LuaGetArgument_float(L, 4); - int slices = LuaGetArgument_int(L, 5); - Color color = LuaGetArgument_Color(L, 6); - DrawCylinderWires(position, radiusTop, radiusBottom, height, slices, color); - return 0; + const char * fileName = luaL_checkstring(L, 1); + int fontSize = (int)luaL_checkinteger(L, 2); + const int * codepoints = (const int *)lua_touserdata(L, 3); + int codepointCount = (int)luaL_checkinteger(L, 4); + Font result = LoadFontEx(fileName, fontSize, codepoints, codepointCount); + RLUA_PUSH_Resource(L, &result, sizeof(Font), "Font"); + return 1; } -// Draw a plane XZ -int lua_DrawPlane(lua_State *L) +// Load font from Image (XNA style) +static int rl_LoadFontFromImage(lua_State *L) { - Vector3 centerPos = LuaGetArgument_Vector3(L, 1); - Vector2 size = LuaGetArgument_Vector2(L, 2); - Color color = LuaGetArgument_Color(L, 3); - DrawPlane(centerPos, size, color); - return 0; + Image image = *(Image*)RLUA_CHECK_Resource(L, 1, "Image"); + Color key = RLUA_CHECK_Color(L, 2); + int firstChar = (int)luaL_checkinteger(L, 3); + Font result = LoadFontFromImage(image, key, firstChar); + RLUA_PUSH_Resource(L, &result, sizeof(Font), "Font"); + return 1; } -// Draw a ray line -int lua_DrawRay(lua_State *L) +// Load font from memory buffer, fileType refers to extension: i.e. '.ttf' +static int rl_LoadFontFromMemory(lua_State *L) { - Ray ray = LuaGetArgument_Ray(L, 1); - Color color = LuaGetArgument_Color(L, 2); - DrawRay(ray, color); - return 0; + const char * fileType = luaL_checkstring(L, 1); + const unsigned char * fileData = (const unsigned char *)lua_touserdata(L, 2); + int dataSize = (int)luaL_checkinteger(L, 3); + int fontSize = (int)luaL_checkinteger(L, 4); + const int * codepoints = (const int *)lua_touserdata(L, 5); + int codepointCount = (int)luaL_checkinteger(L, 6); + Font result = LoadFontFromMemory(fileType, fileData, dataSize, fontSize, codepoints, codepointCount); + RLUA_PUSH_Resource(L, &result, sizeof(Font), "Font"); + return 1; } -// Draw a grid (centered at (0, 0, 0)) -int lua_DrawGrid(lua_State *L) +// Check if a font is valid (font data loaded, WARNING: GPU texture not checked) +static int rl_IsFontValid(lua_State *L) { - int slices = LuaGetArgument_int(L, 1); - float spacing = LuaGetArgument_float(L, 2); - DrawGrid(slices, spacing); - return 0; + Font font = *(Font*)RLUA_CHECK_Resource(L, 1, "Font"); + bool result = IsFontValid(font); + lua_pushboolean(L, result); + return 1; } -// Draw simple gizmo -int lua_DrawGizmo(lua_State *L) +// Load font data for further use +static int rl_LoadFontData(lua_State *L) { - Vector3 position = LuaGetArgument_Vector3(L, 1); - DrawGizmo(position); - return 0; + const unsigned char * fileData = (const unsigned char *)lua_touserdata(L, 1); + int dataSize = (int)luaL_checkinteger(L, 2); + int fontSize = (int)luaL_checkinteger(L, 3); + const int * codepoints = (const int *)lua_touserdata(L, 4); + int codepointCount = (int)luaL_checkinteger(L, 5); + int type = (int)luaL_checkinteger(L, 6); + int glyphCount = 0; + GlyphInfo * result = LoadFontData(fileData, dataSize, fontSize, codepoints, codepointCount, type, &glyphCount); + RLUA_PUSH_View(L, result, glyphCount, "GlyphInfo", true); + return 1; } -//------------------------------------------------------------------------------------ -// raylib [models] module functions -//------------------------------------------------------------------------------------ - -// Load model from files (mesh and material) -int lua_LoadModel(lua_State *L) +// Generate image font atlas using chars info +static int rl_GenImageFontAtlas(lua_State *L) { - const char *fileName = LuaGetArgument_string(L, 1); - Model result = LoadModel(fileName); - LuaPush_Model(L, result); + const GlyphInfo * glyphs = (const GlyphInfo *)lua_touserdata(L, 1); + Rectangle ** glyphRecs = (Rectangle **)lua_touserdata(L, 2); + int glyphCount = (int)luaL_checkinteger(L, 3); + int fontSize = (int)luaL_checkinteger(L, 4); + int padding = (int)luaL_checkinteger(L, 5); + int packMethod = (int)luaL_checkinteger(L, 6); + Image result = GenImageFontAtlas(glyphs, glyphRecs, glyphCount, fontSize, padding, packMethod); + RLUA_PUSH_Resource(L, &result, sizeof(Image), "Image"); return 1; } -// Load model from generated mesh -int lua_LoadModelFromMesh(lua_State *L) +// Unload font chars info data (RAM) +static int rl_UnloadFontData(lua_State *L) { - Mesh mesh = LuaGetArgument_Mesh(L, 1); - Model result = LoadModelFromMesh(mesh); - LuaPush_Model(L, result); - return 1; + GlyphInfo * glyphs = (GlyphInfo *)lua_touserdata(L, 1); + int glyphCount = (int)luaL_checkinteger(L, 2); + UnloadFontData(glyphs, glyphCount); + return 0; } -// Unload model from memory (RAM and/or VRAM) -int lua_UnloadModel(lua_State *L) +// Unload font from GPU memory (VRAM) +static int rl_UnloadFont(lua_State *L) { - Model model = LuaGetArgument_Model(L, 1); - UnloadModel(model); + Font font = *(Font*)RLUA_CHECK_Resource(L, 1, "Font"); + UnloadFont(font); return 0; } -// Mesh loading/unloading functions -// Load mesh from file -int lua_LoadMesh(lua_State *L) +// Export font as code file, returns true on success +static int rl_ExportFontAsCode(lua_State *L) { - const char *fileName = LuaGetArgument_string(L, 1); - Mesh result = LoadMesh(fileName); - LuaPush_Mesh(L, result); + Font font = *(Font*)RLUA_CHECK_Resource(L, 1, "Font"); + const char * fileName = luaL_checkstring(L, 2); + bool result = ExportFontAsCode(font, fileName); + lua_pushboolean(L, result); return 1; } -// Unload mesh from memory (RAM and/or VRAM) -int lua_UnloadMesh(lua_State *L) +// Text drawing functions +// Draw current FPS +static int rl_DrawFPS(lua_State *L) { - Mesh mesh = LuaGetArgument_Mesh(L, 1); - UnloadMesh(mesh); + int posX = (int)luaL_checkinteger(L, 1); + int posY = (int)luaL_checkinteger(L, 2); + DrawFPS(posX, posY); return 0; } -// Export mesh as an OBJ file -int lua_ExportMesh(lua_State *L) +// Draw text (using default font) +static int rl_DrawText(lua_State *L) { - const char *fileName = LuaGetArgument_string(L, 1); - Mesh mesh = LuaGetArgument_Mesh(L, 2); - ExportMesh(fileName, mesh); + const char * text = luaL_checkstring(L, 1); + int posX = (int)luaL_checkinteger(L, 2); + int posY = (int)luaL_checkinteger(L, 3); + int fontSize = (int)luaL_checkinteger(L, 4); + Color color = RLUA_CHECK_Color(L, 5); + DrawText(text, posX, posY, fontSize, color); return 0; } -// Mesh manipulation functions -// Compute mesh bounding box limits -int lua_MeshBoundingBox(lua_State *L) -{ - Mesh mesh = LuaGetArgument_Mesh(L, 1); - BoundingBox result = MeshBoundingBox(mesh); - LuaPush_BoundingBox(L, result); - return 1; -} - -// Compute mesh tangents -int lua_MeshTangents(lua_State *L) +// Draw text using font and additional parameters +static int rl_DrawTextEx(lua_State *L) { - Mesh mesh = LuaGetArgument_Mesh(L, 1); - MeshTangents(mesh); + Font font = *(Font*)RLUA_CHECK_Resource(L, 1, "Font"); + const char * text = luaL_checkstring(L, 2); + Vector2 position = RLUA_CHECK_Vector2(L, 3); + float fontSize = (float)luaL_checknumber(L, 4); + float spacing = (float)luaL_checknumber(L, 5); + Color tint = RLUA_CHECK_Color(L, 6); + DrawTextEx(font, text, position, fontSize, spacing, tint); return 0; } -// Compute mesh binormals -int lua_MeshBinormals(lua_State *L) +// Draw text using Font and pro parameters (rotation) +static int rl_DrawTextPro(lua_State *L) { - Mesh mesh = LuaGetArgument_Mesh(L, 1); - MeshBinormals(mesh); + Font font = *(Font*)RLUA_CHECK_Resource(L, 1, "Font"); + const char * text = luaL_checkstring(L, 2); + Vector2 position = RLUA_CHECK_Vector2(L, 3); + Vector2 origin = RLUA_CHECK_Vector2(L, 4); + float rotation = (float)luaL_checknumber(L, 5); + float fontSize = (float)luaL_checknumber(L, 6); + float spacing = (float)luaL_checknumber(L, 7); + Color tint = RLUA_CHECK_Color(L, 8); + DrawTextPro(font, text, position, origin, rotation, fontSize, spacing, tint); return 0; } -// Mesh generation functions - -// Generate plane mesh (with subdivisions) -int lua_GenMeshPlane(lua_State *L) -{ - float width = LuaGetArgument_float(L, 1); - float length = LuaGetArgument_float(L, 2); - int resX = LuaGetArgument_int(L, 3); - int resZ = LuaGetArgument_int(L, 4); - Mesh result = GenMeshPlane(width, length, resX, resZ); - LuaPush_Mesh(L, result); - return 1; -} - -// Generate cuboid mesh -int lua_GenMeshCube(lua_State *L) +// Draw one character (codepoint) +static int rl_DrawTextCodepoint(lua_State *L) { - float width = LuaGetArgument_float(L, 1); - float height = LuaGetArgument_float(L, 2); - float length = LuaGetArgument_float(L, 3); - Mesh result = GenMeshCube(width, height, length); - LuaPush_Mesh(L, result); - return 1; + Font font = *(Font*)RLUA_CHECK_Resource(L, 1, "Font"); + int codepoint = (int)luaL_checkinteger(L, 2); + Vector2 position = RLUA_CHECK_Vector2(L, 3); + float fontSize = (float)luaL_checknumber(L, 4); + Color tint = RLUA_CHECK_Color(L, 5); + DrawTextCodepoint(font, codepoint, position, fontSize, tint); + return 0; } -// Generate sphere mesh (standard sphere) -int lua_GenMeshSphere(lua_State *L) +// Draw multiple character (codepoint) +static int rl_DrawTextCodepoints(lua_State *L) { - float radius = LuaGetArgument_float(L, 1); - int rings = LuaGetArgument_int(L, 2); - int slices = LuaGetArgument_int(L, 3); - Mesh result = GenMeshSphere(radius, rings, slices); - LuaPush_Mesh(L, result); - return 1; + Font font = *(Font*)RLUA_CHECK_Resource(L, 1, "Font"); + const int * codepoints = (const int *)lua_touserdata(L, 2); + int codepointCount = (int)luaL_checkinteger(L, 3); + Vector2 position = RLUA_CHECK_Vector2(L, 4); + float fontSize = (float)luaL_checknumber(L, 5); + float spacing = (float)luaL_checknumber(L, 6); + Color tint = RLUA_CHECK_Color(L, 7); + DrawTextCodepoints(font, codepoints, codepointCount, position, fontSize, spacing, tint); + return 0; } -// Generate half-sphere mesh (no bottom cap) -int lua_GenMeshHemiSphere(lua_State *L) +// Text font info functions +// Set vertical line spacing when drawing with line-breaks +static int rl_SetTextLineSpacing(lua_State *L) { - float radius = LuaGetArgument_float(L, 1); - int rings = LuaGetArgument_int(L, 2); - int slices = LuaGetArgument_int(L, 3); - Mesh result = GenMeshHemiSphere(radius, rings, slices); - LuaPush_Mesh(L, result); - return 1; + int spacing = (int)luaL_checkinteger(L, 1); + SetTextLineSpacing(spacing); + return 0; } -// Generate cylinder mesh -int lua_GenMeshCylinder(lua_State *L) +// Measure string width for default font +static int rl_MeasureText(lua_State *L) { - float radius = LuaGetArgument_float(L, 1); - float height = LuaGetArgument_float(L, 2); - int slices = LuaGetArgument_int(L, 3); - Mesh result = GenMeshCylinder(radius, height, slices); - LuaPush_Mesh(L, result); + const char * text = luaL_checkstring(L, 1); + int fontSize = (int)luaL_checkinteger(L, 2); + int result = MeasureText(text, fontSize); + lua_pushinteger(L, result); return 1; } -// Generate torus mesh -int lua_GenMeshTorus(lua_State *L) +// Measure string size for Font +static int rl_MeasureTextEx(lua_State *L) { - float radius = LuaGetArgument_float(L, 1); - float size = LuaGetArgument_float(L, 2); - int radSeg = LuaGetArgument_int(L, 3); - int sides = LuaGetArgument_int(L, 4); - Mesh result = GenMeshTorus(radius, size, radSeg, sides); - LuaPush_Mesh(L, result); + Font font = *(Font*)RLUA_CHECK_Resource(L, 1, "Font"); + const char * text = luaL_checkstring(L, 2); + float fontSize = (float)luaL_checknumber(L, 3); + float spacing = (float)luaL_checknumber(L, 4); + Vector2 result = MeasureTextEx(font, text, fontSize, spacing); + RLUA_PUSH_Vector2(L, result); return 1; } -// Generate trefoil knot mesh -int lua_GenMeshKnot(lua_State *L) +// Measure string size for an existing array of codepoints for Font +static int rl_MeasureTextCodepoints(lua_State *L) { - float radius = LuaGetArgument_float(L, 1); - float size = LuaGetArgument_float(L, 2); - int radSeg = LuaGetArgument_int(L, 3); - int sides = LuaGetArgument_int(L, 4); - Mesh result = GenMeshKnot(radius, size, radSeg, sides); - LuaPush_Mesh(L, result); + Font font = *(Font*)RLUA_CHECK_Resource(L, 1, "Font"); + const int * codepoints = (const int *)lua_touserdata(L, 2); + int length = (int)luaL_checkinteger(L, 3); + float fontSize = (float)luaL_checknumber(L, 4); + float spacing = (float)luaL_checknumber(L, 5); + Vector2 result = MeasureTextCodepoints(font, codepoints, length, fontSize, spacing); + RLUA_PUSH_Vector2(L, result); return 1; } -// Generate heightmap mesh from image data -int lua_GenMeshHeightmap(lua_State *L) +// Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found +static int rl_GetGlyphIndex(lua_State *L) { - Image heightmap = LuaGetArgument_Image(L, 1); - Vector3 size = LuaGetArgument_Vector3(L, 2); - Mesh result = GenMeshHeightmap(heightmap, size); - LuaPush_Mesh(L, result); + Font font = *(Font*)RLUA_CHECK_Resource(L, 1, "Font"); + int codepoint = (int)luaL_checkinteger(L, 2); + int result = GetGlyphIndex(font, codepoint); + lua_pushinteger(L, result); return 1; } -// Generate cubes-based map mesh from image data -int lua_GenMeshCubicmap(lua_State *L) +// Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found +static int rl_GetGlyphInfo(lua_State *L) { - Image cubicmap = LuaGetArgument_Image(L, 1); - Vector3 cubeSize = LuaGetArgument_Vector3(L, 2); - Mesh result = GenMeshCubicmap(cubicmap, cubeSize); - LuaPush_Mesh(L, result); + Font font = *(Font*)RLUA_CHECK_Resource(L, 1, "Font"); + int codepoint = (int)luaL_checkinteger(L, 2); + GlyphInfo result = GetGlyphInfo(font, codepoint); + RLUA_PUSH_GlyphInfo(L, result); return 1; } -// Material loading/unloading functions -// Load material from file -int lua_LoadMaterial(lua_State *L) +// Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found +static int rl_GetGlyphAtlasRec(lua_State *L) { - const char *fileName = LuaGetArgument_string(L, 1); - Material result = LoadMaterial(fileName); - LuaPush_Material(L, result); + Font font = *(Font*)RLUA_CHECK_Resource(L, 1, "Font"); + int codepoint = (int)luaL_checkinteger(L, 2); + Rectangle result = GetGlyphAtlasRec(font, codepoint); + RLUA_PUSH_Rectangle(L, result); return 1; } -// Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) -int lua_LoadMaterialDefault(lua_State *L) +// Text codepoints management functions (unicode characters) +// Load UTF-8 text encoded from codepoints array +static int rl_LoadUTF8(lua_State *L) { - Material result = LoadMaterialDefault(); - LuaPush_Material(L, result); + const int * codepoints = (const int *)lua_touserdata(L, 1); + int length = (int)luaL_checkinteger(L, 2); + char * result = LoadUTF8(codepoints, length); + lua_pushstring(L, result); return 1; } -// Unload material from GPU memory (VRAM) -int lua_UnloadMaterial(lua_State *L) +// Unload UTF-8 text encoded from codepoints array +static int rl_UnloadUTF8(lua_State *L) { - Material material = LuaGetArgument_Material(L, 1); - UnloadMaterial(material); + const char * text = luaL_checkstring(L, 1); + UnloadUTF8((char *)text); return 0; } -// Model drawing functions -// Draw a model (with texture if set) -int lua_DrawModel(lua_State *L) +// Load all codepoints from a UTF-8 text string, codepoints count returned by parameter +static int rl_LoadCodepoints(lua_State *L) { - Model model = LuaGetArgument_Model(L, 1); - Vector3 position = LuaGetArgument_Vector3(L, 2); - float scale = LuaGetArgument_float(L, 3); - Color tint = LuaGetArgument_Color(L, 4); - DrawModel(model, position, scale, tint); - return 0; + const char * text = luaL_checkstring(L, 1); + int count = 0; + int * result = LoadCodepoints(text, &count); + RLUA_PUSH_View(L, result, count, "int", true); + return 1; } -// Draw a model with extended parameters -int lua_DrawModelEx(lua_State *L) -{ - Model model = LuaGetArgument_Model(L, 1); - Vector3 position = LuaGetArgument_Vector3(L, 2); - Vector3 rotationAxis = LuaGetArgument_Vector3(L, 3); - float rotationAngle = LuaGetArgument_float(L, 4); - Vector3 scale = LuaGetArgument_Vector3(L, 5); - Color tint = LuaGetArgument_Color(L, 6); - DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint); +// Unload codepoints data from memory +static int rl_UnloadCodepoints(lua_State *L) +{ + int * codepoints = (int *)lua_touserdata(L, 1); + UnloadCodepoints(codepoints); return 0; } -// Draw a model wires (with texture if set) -int lua_DrawModelWires(lua_State *L) +// Get total number of codepoints in a UTF-8 encoded string +static int rl_GetCodepointCount(lua_State *L) { - Model model = LuaGetArgument_Model(L, 1); - Vector3 position = LuaGetArgument_Vector3(L, 2); - float scale = LuaGetArgument_float(L, 3); - Color tint = LuaGetArgument_Color(L, 4); - DrawModelWires(model, position, scale, tint); - return 0; + const char * text = luaL_checkstring(L, 1); + int result = GetCodepointCount(text); + lua_pushinteger(L, result); + return 1; } -// Draw a model wires (with texture if set) with extended parameters -int lua_DrawModelWiresEx(lua_State *L) -{ - Model model = LuaGetArgument_Model(L, 1); - Vector3 position = LuaGetArgument_Vector3(L, 2); - Vector3 rotationAxis = LuaGetArgument_Vector3(L, 3); - float rotationAngle = LuaGetArgument_float(L, 4); - Vector3 scale = LuaGetArgument_Vector3(L, 5); - Color tint = LuaGetArgument_Color(L, 6); - DrawModelWiresEx(model, position, rotationAxis, rotationAngle, scale, tint); - return 0; +// Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure +static int rl_GetCodepoint(lua_State *L) +{ + const char * text = luaL_checkstring(L, 1); + int * codepointSize = (int *)lua_touserdata(L, 2); + int result = GetCodepoint(text, codepointSize); + lua_pushinteger(L, result); + return 1; } -// Draw bounding box (wires) -int lua_DrawBoundingBox(lua_State *L) +// Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure +static int rl_GetCodepointNext(lua_State *L) { - BoundingBox box = LuaGetArgument_BoundingBox(L, 1); - Color color = LuaGetArgument_Color(L, 2); - DrawBoundingBox(box, color); - return 0; + const char * text = luaL_checkstring(L, 1); + int * codepointSize = (int *)lua_touserdata(L, 2); + int result = GetCodepointNext(text, codepointSize); + lua_pushinteger(L, result); + return 1; } -// Draw a billboard texture -int lua_DrawBillboard(lua_State *L) +// Get previous codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure +static int rl_GetCodepointPrevious(lua_State *L) { - Camera camera = LuaGetArgument_Camera(L, 1); - Texture2D texture = LuaGetArgument_Texture2D(L, 2); - Vector3 center = LuaGetArgument_Vector3(L, 3); - float size = LuaGetArgument_float(L, 4); - Color tint = LuaGetArgument_Color(L, 5); - DrawBillboard(camera, texture, center, size, tint); - return 0; + const char * text = luaL_checkstring(L, 1); + int * codepointSize = (int *)lua_touserdata(L, 2); + int result = GetCodepointPrevious(text, codepointSize); + lua_pushinteger(L, result); + return 1; } -// Draw a billboard texture defined by sourceRec -int lua_DrawBillboardRec(lua_State *L) +// Encode one codepoint into UTF-8 byte array (array length returned as parameter) +static int rl_CodepointToUTF8(lua_State *L) { - Camera camera = LuaGetArgument_Camera(L, 1); - Texture2D texture = LuaGetArgument_Texture2D(L, 2); - Rectangle sourceRec = LuaGetArgument_Rectangle(L, 3); - Vector3 center = LuaGetArgument_Vector3(L, 4); - float size = LuaGetArgument_float(L, 5); - Color tint = LuaGetArgument_Color(L, 6); - DrawBillboardRec(camera, texture, sourceRec, center, size, tint); - return 0; + int codepoint = (int)luaL_checkinteger(L, 1); + int utf8Size = 0; + const char * result = CodepointToUTF8(codepoint, &utf8Size); + RLUA_PUSH_View(L, result, utf8Size, "const char", true); + return 1; } -// Collision detection functions -// Detect collision between two spheres -int lua_CheckCollisionSpheres(lua_State *L) +// Text strings management functions (no UTF-8 strings, only byte chars) +// WARNING 1: Most of these functions use internal static buffers[], it's recommended to store returned data on user-side for re-use +// WARNING 2: Some functions allocate memory internally for the returned strings, those strings must be freed by user using MemFree() +// Load text as separate lines ('\n') +static int rl_LoadTextLines(lua_State *L) { - Vector3 centerA = LuaGetArgument_Vector3(L, 1); - float radiusA = LuaGetArgument_float(L, 2); - Vector3 centerB = LuaGetArgument_Vector3(L, 3); - float radiusB = LuaGetArgument_float(L, 4); - bool result = CheckCollisionSpheres(centerA, radiusA, centerB, radiusB); - LuaPush_bool(L, result); + const char * text = luaL_checkstring(L, 1); + int count = 0; + char ** result = LoadTextLines(text, &count); + RLUA_PUSH_View(L, result, count, "char *", true); return 1; } -// Detect collision between two bounding boxes -int lua_CheckCollisionBoxes(lua_State *L) +// Unload text lines +static int rl_UnloadTextLines(lua_State *L) { - BoundingBox box1 = LuaGetArgument_BoundingBox(L, 1); - BoundingBox box2 = LuaGetArgument_BoundingBox(L, 2); - bool result = CheckCollisionBoxes(box1, box2); - LuaPush_bool(L, result); - return 1; + char ** text = (char **)lua_touserdata(L, 1); + int lineCount = (int)luaL_checkinteger(L, 2); + UnloadTextLines(text, lineCount); + return 0; } -// Detect collision between box and sphere -int lua_CheckCollisionBoxSphere(lua_State *L) +// Copy one string to another, returns bytes copied +static int rl_TextCopy(lua_State *L) { - BoundingBox box = LuaGetArgument_BoundingBox(L, 1); - Vector3 centerSphere = LuaGetArgument_Vector3(L, 2); - float radiusSphere = LuaGetArgument_float(L, 3); - bool result = CheckCollisionBoxSphere(box, centerSphere, radiusSphere); - LuaPush_bool(L, result); + const char * dst = luaL_checkstring(L, 1); + const char * src = luaL_checkstring(L, 2); + int result = TextCopy((char *)dst, src); + lua_pushinteger(L, result); return 1; } -// Detect collision between ray and sphere -int lua_CheckCollisionRaySphere(lua_State *L) +// Check if two text string are equal +static int rl_TextIsEqual(lua_State *L) { - Ray ray = LuaGetArgument_Ray(L, 1); - Vector3 spherePosition = LuaGetArgument_Vector3(L, 2); - float sphereRadius = LuaGetArgument_float(L, 3); - bool result = CheckCollisionRaySphere(ray, spherePosition, sphereRadius); - LuaPush_bool(L, result); + const char * text1 = luaL_checkstring(L, 1); + const char * text2 = luaL_checkstring(L, 2); + bool result = TextIsEqual(text1, text2); + lua_pushboolean(L, result); return 1; } -// Detect collision between ray and sphere, returns collision point -int lua_CheckCollisionRaySphereEx(lua_State *L) +// Get text length, checks for '\0' ending +static int rl_TextLength(lua_State *L) { - Ray ray = LuaGetArgument_Ray(L, 1); - Vector3 spherePosition = LuaGetArgument_Vector3(L, 2); - float sphereRadius = LuaGetArgument_float(L, 3); - Vector3 collisionPoint = LuaGetArgument_Vector3(L, 4); - bool result = CheckCollisionRaySphereEx(ray, spherePosition, sphereRadius, collisionPoint); - LuaPush_bool(L, result); + const char * text = luaL_checkstring(L, 1); + unsigned int result = TextLength(text); + lua_pushinteger(L, result); return 1; } -// Detect collision between ray and box -int lua_CheckCollisionRayBox(lua_State *L) +// Text formatting with variables (sprintf() style) +static int rl_TextFormat(lua_State *L) { - Ray ray = LuaGetArgument_Ray(L, 1); - BoundingBox box = LuaGetArgument_BoundingBox(L, 2); - bool result = CheckCollisionRayBox(ray, box); - LuaPush_bool(L, result); + int n = lua_gettop(L); + if (n < 1) return luaL_error(L, "TextFormat requires at least 1 argument"); + if (n == 1) { + lua_pushstring(L, TextFormat("%s", luaL_checkstring(L, 1))); + } else { + lua_getglobal(L, "string"); + lua_getfield(L, -1, "format"); + for (int i = 1; i <= n; i++) lua_pushvalue(L, i); + lua_call(L, n, 1); + const char *formatted = lua_tostring(L, -1); + lua_pushstring(L, TextFormat("%s", formatted)); + lua_insert(L, 1); + lua_settop(L, 1); + } return 1; } -// Get collision info between ray and model -int lua_GetCollisionRayModel(lua_State *L) +// Get a piece of a text string +static int rl_TextSubtext(lua_State *L) { - Ray ray = LuaGetArgument_Ray(L, 1); - Model model = LuaGetArgument_Model(L, 2); - RayHitInfo result = GetCollisionRayModel(ray, model); - LuaPush_RayHitInfo(L, result); + const char * text = luaL_checkstring(L, 1); + int position = (int)luaL_checkinteger(L, 2); + int length = (int)luaL_checkinteger(L, 3); + const char * result = TextSubtext(text, position, length); + lua_pushstring(L, result); return 1; } -// Get collision info between ray and triangle -int lua_GetCollisionRayTriangle(lua_State *L) +// Remove text spaces, concat words +static int rl_TextRemoveSpaces(lua_State *L) { - Ray ray = LuaGetArgument_Ray(L, 1); - Vector3 p1 = LuaGetArgument_Vector3(L, 2); - Vector3 p2 = LuaGetArgument_Vector3(L, 3); - Vector3 p3 = LuaGetArgument_Vector3(L, 4); - RayHitInfo result = GetCollisionRayTriangle(ray, p1, p2, p3); - LuaPush_RayHitInfo(L, result); + const char * text = luaL_checkstring(L, 1); + const char * result = TextRemoveSpaces(text); + lua_pushstring(L, result); return 1; } -// Get collision info between ray and ground plane (Y-normal plane) -int lua_GetCollisionRayGround(lua_State *L) +// Get text between two strings +static int rl_GetTextBetween(lua_State *L) { - Ray ray = LuaGetArgument_Ray(L, 1); - float groundHeight = LuaGetArgument_float(L, 2); - RayHitInfo result = GetCollisionRayGround(ray, groundHeight); - LuaPush_RayHitInfo(L, result); + const char * text = luaL_checkstring(L, 1); + const char * begin = luaL_checkstring(L, 2); + const char * end = luaL_checkstring(L, 3); + char * result = GetTextBetween(text, begin, end); + lua_pushstring(L, result); return 1; } -//------------------------------------------------------------------------------------ -// raylib [raymath] module functions - Shaders -//------------------------------------------------------------------------------------ - -// WARNING: Load chars array from text file -int lua_LoadText(lua_State *L) +// Replace text string with new string +static int rl_TextReplace(lua_State *L) { - const char *fileName = LuaGetArgument_string(L, 1); - char *result = LoadText(fileName); - LuaPush_string(L, result); // WARNING_ LuaPush_char not valid + const char * text = luaL_checkstring(L, 1); + const char * search = luaL_checkstring(L, 2); + const char * replacement = luaL_checkstring(L, 3); + char * result = TextReplace(text, search, replacement); + lua_pushstring(L, result); return 1; } -// Load shader from files and bind default locations -int lua_LoadShader(lua_State *L) +// Replace text string with new string, memory must be MemFree() +static int rl_TextReplaceAlloc(lua_State *L) { - const char *vsFileName = LuaGetArgument_string(L, 1); - const char *fsFileName = LuaGetArgument_string(L, 2); - Shader result = LoadShader(vsFileName, fsFileName); - LuaPush_Shader(L, result); + const char * text = luaL_checkstring(L, 1); + const char * search = luaL_checkstring(L, 2); + const char * replacement = luaL_checkstring(L, 3); + char * result = TextReplaceAlloc(text, search, replacement); + lua_pushstring(L, result); return 1; } -// Load shader from code strings and bind default locations -int lua_LoadShaderCode(lua_State *L) +// Replace text between two specific strings +static int rl_TextReplaceBetween(lua_State *L) { - char *vsCode = LuaGetArgument_char(L, 1); - char *fsCode = LuaGetArgument_char(L, 2); - Shader result = LoadShaderCode(vsCode, fsCode); - LuaPush_Shader(L, result); + const char * text = luaL_checkstring(L, 1); + const char * begin = luaL_checkstring(L, 2); + const char * end = luaL_checkstring(L, 3); + const char * replacement = luaL_checkstring(L, 4); + char * result = TextReplaceBetween(text, begin, end, replacement); + lua_pushstring(L, result); return 1; } -// Unload shader from GPU memory (VRAM) -int lua_UnloadShader(lua_State *L) +// Replace text between two specific strings, memory must be MemFree() +static int rl_TextReplaceBetweenAlloc(lua_State *L) { - Shader shader = LuaGetArgument_Shader(L, 1); - UnloadShader(shader); - return 0; + const char * text = luaL_checkstring(L, 1); + const char * begin = luaL_checkstring(L, 2); + const char * end = luaL_checkstring(L, 3); + const char * replacement = luaL_checkstring(L, 4); + char * result = TextReplaceBetweenAlloc(text, begin, end, replacement); + lua_pushstring(L, result); + return 1; } -// Get default shader -int lua_GetShaderDefault(lua_State *L) +// Insert text in a defined byte position +static int rl_TextInsert(lua_State *L) { - Shader result = GetShaderDefault(); - LuaPush_Shader(L, result); + const char * text = luaL_checkstring(L, 1); + const char * insert = luaL_checkstring(L, 2); + int position = (int)luaL_checkinteger(L, 3); + char * result = TextInsert(text, insert, position); + lua_pushstring(L, result); return 1; } -// Get default texture -int lua_GetTextureDefault(lua_State *L) +// Insert text in a defined byte position, memory must be MemFree() +static int rl_TextInsertAlloc(lua_State *L) { - Texture2D result = GetTextureDefault(); - LuaPush_Texture2D(L, result); + const char * text = luaL_checkstring(L, 1); + const char * insert = luaL_checkstring(L, 2); + int position = (int)luaL_checkinteger(L, 3); + char * result = TextInsertAlloc(text, insert, position); + lua_pushstring(L, result); return 1; } -// Shader configuration functions - -// Get shader uniform location -int lua_GetShaderLocation(lua_State *L) +// Join text strings with delimiter +static int rl_TextJoin(lua_State *L) { - Shader shader = LuaGetArgument_Shader(L, 1); - const char *uniformName = LuaGetArgument_string(L, 2); - int result = GetShaderLocation(shader, uniformName); - LuaPush_int(L, result); + char ** textList = (char **)lua_touserdata(L, 1); + int count = (int)luaL_checkinteger(L, 2); + const char * delimiter = luaL_checkstring(L, 3); + char * result = TextJoin(textList, count, delimiter); + lua_pushstring(L, result); return 1; } -// WARNING: Set shader uniform values (float) -int lua_SetShaderValue(lua_State* L) +// Split text into multiple strings, using MAX_TEXTSPLIT_COUNT static strings +static int rl_TextSplit(lua_State *L) { - Shader arg1 = LuaGetArgument_Shader(L, 1); - int arg2 = LuaGetArgument_int(L, 2); - GET_TABLE(float, arg3, 3); - SetShaderValue(arg1, arg2, arg3, arg3_size); - free(arg3); - return 0; + const char * text = luaL_checkstring(L, 1); + char delimiter = (char)luaL_checkinteger(L, 2); + int count = 0; + char ** result = TextSplit(text, delimiter, &count); + RLUA_PUSH_View(L, result, count, "char *", true); + return 1; } -// WARNING: Set shader uniform values (int) -int lua_SetShaderValuei(lua_State* L) +// Append text at specific position and move cursor +static int rl_TextAppend(lua_State *L) { - Shader arg1 = LuaGetArgument_Shader(L, 1); - int arg2 = LuaGetArgument_int(L, 2); - GET_TABLE(int, arg3, 3); - SetShaderValuei(arg1, arg2, arg3, arg3_size); - free(arg3); + const char * text = luaL_checkstring(L, 1); + const char * append = luaL_checkstring(L, 2); + int * position = (int *)lua_touserdata(L, 3); + TextAppend((char *)text, append, position); return 0; } -// Set shader uniform value (matrix 4x4) -int lua_SetShaderValueMatrix(lua_State *L) +// Find first text occurrence within a string, -1 if not found +static int rl_TextFindIndex(lua_State *L) { - Shader shader = LuaGetArgument_Shader(L, 1); - int uniformLoc = LuaGetArgument_int(L, 2); - Matrix mat = LuaGetArgument_Matrix(L, 3); - SetShaderValueMatrix(shader, uniformLoc, mat); - return 0; + const char * text = luaL_checkstring(L, 1); + const char * search = luaL_checkstring(L, 2); + int result = TextFindIndex(text, search); + lua_pushinteger(L, result); + return 1; } -// Set a custom projection matrix (replaces internal projection matrix) -int lua_SetMatrixProjection(lua_State *L) +// Get upper case version of provided string +static int rl_TextToUpper(lua_State *L) { - Matrix proj = LuaGetArgument_Matrix(L, 1); - SetMatrixProjection(proj); - return 0; + const char * text = luaL_checkstring(L, 1); + char * result = TextToUpper(text); + lua_pushstring(L, result); + return 1; } -// Set a custom modelview matrix (replaces internal modelview matrix) -int lua_SetMatrixModelview(lua_State *L) +// Get lower case version of provided string +static int rl_TextToLower(lua_State *L) { - Matrix view = LuaGetArgument_Matrix(L, 1); - SetMatrixModelview(view); - return 0; + const char * text = luaL_checkstring(L, 1); + char * result = TextToLower(text); + lua_pushstring(L, result); + return 1; } -// Get internal modelview matrix -int lua_GetMatrixModelview(lua_State *L) +// Get Pascal case notation version of provided string +static int rl_TextToPascal(lua_State *L) { - Matrix view = LuaGetArgument_Matrix(L, 1); - Matrix result = GetMatrixModelview(view); - LuaPush_Matrix(L, result); + const char * text = luaL_checkstring(L, 1); + char * result = TextToPascal(text); + lua_pushstring(L, result); return 1; } -// Texture maps generation (PBR) -// NOTE: Required shaders should be provided -// Generate cubemap texture from HDR texture -int lua_GenTextureCubemap(lua_State *L) +// Get Snake case notation version of provided string +static int rl_TextToSnake(lua_State *L) { - Shader shader = LuaGetArgument_Shader(L, 1); - Texture2D skyHDR = LuaGetArgument_Texture2D(L, 2); - int size = LuaGetArgument_int(L, 3); - Texture2D result = GenTextureCubemap(shader, skyHDR, size); - LuaPush_Texture2D(L, result); + const char * text = luaL_checkstring(L, 1); + char * result = TextToSnake(text); + lua_pushstring(L, result); return 1; } -// Generate irradiance texture using cubemap data -int lua_GenTextureIrradiance(lua_State *L) +// Get Camel case notation version of provided string +static int rl_TextToCamel(lua_State *L) { - Shader shader = LuaGetArgument_Shader(L, 1); - Texture2D cubemap = LuaGetArgument_Texture2D(L, 2); - int size = LuaGetArgument_int(L, 3); - Texture2D result = GenTextureIrradiance(shader, cubemap, size); - LuaPush_Texture2D(L, result); + const char * text = luaL_checkstring(L, 1); + char * result = TextToCamel(text); + lua_pushstring(L, result); return 1; } -// Generate prefilter texture using cubemap data -int lua_GenTexturePrefilter(lua_State *L) +// Get integer value from text +static int rl_TextToInteger(lua_State *L) { - Shader shader = LuaGetArgument_Shader(L, 1); - Texture2D cubemap = LuaGetArgument_Texture2D(L, 2); - int size = LuaGetArgument_int(L, 3); - Texture2D result = GenTexturePrefilter(shader, cubemap, size); - LuaPush_Texture2D(L, result); + const char * text = luaL_checkstring(L, 1); + int result = TextToInteger(text); + lua_pushinteger(L, result); return 1; } -// Generate BRDF texture using cubemap data -int lua_GenTextureBRDF(lua_State *L) +// Get float value from text +static int rl_TextToFloat(lua_State *L) { - Shader shader = LuaGetArgument_Shader(L, 1); - Texture2D cubemap = LuaGetArgument_Texture2D(L, 2); - int size = LuaGetArgument_int(L, 3); - Texture2D result = GenTextureBRDF(shader, cubemap, size); - LuaPush_Texture2D(L, result); + const char * text = luaL_checkstring(L, 1); + float result = TextToFloat(text); + lua_pushnumber(L, result); return 1; } -// Shading begin/end functions -// Begin custom shader drawing -int lua_BeginShaderMode(lua_State *L) +// ------------------------------------------------------------------------------------ +// Basic 3d Shapes Drawing Functions (Module: models) +// ------------------------------------------------------------------------------------ +// Basic geometric 3D shapes drawing functions +// Draw a line in 3D world space +static int rl_DrawLine3D(lua_State *L) { - Shader shader = LuaGetArgument_Shader(L, 1); - BeginShaderMode(shader); + Vector3 startPos = RLUA_CHECK_Vector3(L, 1); + Vector3 endPos = RLUA_CHECK_Vector3(L, 2); + Color color = RLUA_CHECK_Color(L, 3); + DrawLine3D(startPos, endPos, color); return 0; } -// End custom shader drawing (use default shader) -int lua_EndShaderMode(lua_State *L) +// Draw a point in 3D space, actually a small line +static int rl_DrawPoint3D(lua_State *L) { - EndShaderMode(); + Vector3 position = RLUA_CHECK_Vector3(L, 1); + Color color = RLUA_CHECK_Color(L, 2); + DrawPoint3D(position, color); return 0; } -// Begin blending mode (alpha, additive, multiplied) -int lua_BeginBlendMode(lua_State *L) +// Draw a circle in 3D world space +static int rl_DrawCircle3D(lua_State *L) { - int mode = LuaGetArgument_int(L, 1); - BeginBlendMode(mode); + Vector3 center = RLUA_CHECK_Vector3(L, 1); + float radius = (float)luaL_checknumber(L, 2); + Vector3 rotationAxis = RLUA_CHECK_Vector3(L, 3); + float rotationAngle = (float)luaL_checknumber(L, 4); + Color color = RLUA_CHECK_Color(L, 5); + DrawCircle3D(center, radius, rotationAxis, rotationAngle, color); return 0; } -// End blending mode (reset to default: alpha blending) -int lua_EndBlendMode(lua_State *L) +// Draw a color-filled triangle (vertex in counter-clockwise order!) +static int rl_DrawTriangle3D(lua_State *L) { - EndBlendMode(); + Vector3 v1 = RLUA_CHECK_Vector3(L, 1); + Vector3 v2 = RLUA_CHECK_Vector3(L, 2); + Vector3 v3 = RLUA_CHECK_Vector3(L, 3); + Color color = RLUA_CHECK_Color(L, 4); + DrawTriangle3D(v1, v2, v3, color); return 0; } -//------------------------------------------------------------------------------------ -// raylib [rlgl] module functions - VR experience -//------------------------------------------------------------------------------------ - -// Get VR device information for some standard devices -int lua_GetVrDeviceInfo(lua_State *L) +// Draw a triangle strip defined by points +static int rl_DrawTriangleStrip3D(lua_State *L) { - int vrDeviceType = LuaGetArgument_int(L, 1); - VrDeviceInfo result = GetVrDeviceInfo(vrDeviceType); - LuaPush_VrDeviceInfo(L, result); - return 1; + const Vector3 * points = (const Vector3 *)lua_touserdata(L, 1); + int pointCount = (int)luaL_checkinteger(L, 2); + Color color = RLUA_CHECK_Color(L, 3); + DrawTriangleStrip3D(points, pointCount, color); + return 0; } -// Init VR simulator for selected device parameters -int lua_InitVrSimulator(lua_State *L) +// Draw cube +static int rl_DrawCube(lua_State *L) { - VrDeviceInfo info = LuaGetArgument_VrDeviceInfo(L, 1); - InitVrSimulator(info); + Vector3 position = RLUA_CHECK_Vector3(L, 1); + float width = (float)luaL_checknumber(L, 2); + float height = (float)luaL_checknumber(L, 3); + float length = (float)luaL_checknumber(L, 4); + Color color = RLUA_CHECK_Color(L, 5); + DrawCube(position, width, height, length, color); return 0; } -// Close VR simulator for current device -int lua_CloseVrSimulator(lua_State *L) +// Draw cube (Vector version) +static int rl_DrawCubeV(lua_State *L) { - CloseVrSimulator(); + Vector3 position = RLUA_CHECK_Vector3(L, 1); + Vector3 size = RLUA_CHECK_Vector3(L, 2); + Color color = RLUA_CHECK_Color(L, 3); + DrawCubeV(position, size, color); return 0; } -// Detect if VR simulator is ready -int lua_IsVrSimulatorReady(lua_State *L) +// Draw cube wires +static int rl_DrawCubeWires(lua_State *L) { - bool result = IsVrSimulatorReady(); - LuaPush_bool(L, result); - return 1; + Vector3 position = RLUA_CHECK_Vector3(L, 1); + float width = (float)luaL_checknumber(L, 2); + float height = (float)luaL_checknumber(L, 3); + float length = (float)luaL_checknumber(L, 4); + Color color = RLUA_CHECK_Color(L, 5); + DrawCubeWires(position, width, height, length, color); + return 0; } -// Set VR distortion shader for stereoscopic rendering -int lua_SetVrDistortionShader(lua_State *L) +// Draw cube wires (Vector version) +static int rl_DrawCubeWiresV(lua_State *L) { - Shader shader = LuaGetArgument_Shader(L, 1); - SetVrDistortionShader(shader); + Vector3 position = RLUA_CHECK_Vector3(L, 1); + Vector3 size = RLUA_CHECK_Vector3(L, 2); + Color color = RLUA_CHECK_Color(L, 3); + DrawCubeWiresV(position, size, color); return 0; } -// Update VR tracking (position and orientation) and camera -int lua_UpdateVrTracking(lua_State *L) +// Draw sphere +static int rl_DrawSphere(lua_State *L) { - Camera camera = LuaGetArgument_Camera(L, 1); - UpdateVrTracking(camera); + Vector3 centerPos = RLUA_CHECK_Vector3(L, 1); + float radius = (float)luaL_checknumber(L, 2); + Color color = RLUA_CHECK_Color(L, 3); + DrawSphere(centerPos, radius, color); return 0; } -// Enable/Disable VR experience -int lua_ToggleVrMode(lua_State *L) +// Draw sphere with extended parameters +static int rl_DrawSphereEx(lua_State *L) { - ToggleVrMode(); + Vector3 centerPos = RLUA_CHECK_Vector3(L, 1); + float radius = (float)luaL_checknumber(L, 2); + int rings = (int)luaL_checkinteger(L, 3); + int slices = (int)luaL_checkinteger(L, 4); + Color color = RLUA_CHECK_Color(L, 5); + DrawSphereEx(centerPos, radius, rings, slices, color); return 0; } -// Begin VR simulator stereo rendering -int lua_BeginVrDrawing(lua_State *L) +// Draw sphere wires +static int rl_DrawSphereWires(lua_State *L) { - BeginVrDrawing(); + Vector3 centerPos = RLUA_CHECK_Vector3(L, 1); + float radius = (float)luaL_checknumber(L, 2); + int rings = (int)luaL_checkinteger(L, 3); + int slices = (int)luaL_checkinteger(L, 4); + Color color = RLUA_CHECK_Color(L, 5); + DrawSphereWires(centerPos, radius, rings, slices, color); + return 0; +} + +// Draw a cylinder/cone +static int rl_DrawCylinder(lua_State *L) +{ + Vector3 position = RLUA_CHECK_Vector3(L, 1); + float radiusTop = (float)luaL_checknumber(L, 2); + float radiusBottom = (float)luaL_checknumber(L, 3); + float height = (float)luaL_checknumber(L, 4); + int slices = (int)luaL_checkinteger(L, 5); + Color color = RLUA_CHECK_Color(L, 6); + DrawCylinder(position, radiusTop, radiusBottom, height, slices, color); return 0; } -// End VR simulator stereo rendering -int lua_EndVrDrawing(lua_State *L) +// Draw a cylinder with base at startPos and top at endPos +static int rl_DrawCylinderEx(lua_State *L) { - EndVrDrawing(); + Vector3 startPos = RLUA_CHECK_Vector3(L, 1); + Vector3 endPos = RLUA_CHECK_Vector3(L, 2); + float startRadius = (float)luaL_checknumber(L, 3); + float endRadius = (float)luaL_checknumber(L, 4); + int sides = (int)luaL_checkinteger(L, 5); + Color color = RLUA_CHECK_Color(L, 6); + DrawCylinderEx(startPos, endPos, startRadius, endRadius, sides, color); return 0; } -//------------------------------------------------------------------------------------ -// raylib [audio] module functions - Audio Loading and Playing -//------------------------------------------------------------------------------------ +// Draw a cylinder/cone wires +static int rl_DrawCylinderWires(lua_State *L) +{ + Vector3 position = RLUA_CHECK_Vector3(L, 1); + float radiusTop = (float)luaL_checknumber(L, 2); + float radiusBottom = (float)luaL_checknumber(L, 3); + float height = (float)luaL_checknumber(L, 4); + int slices = (int)luaL_checkinteger(L, 5); + Color color = RLUA_CHECK_Color(L, 6); + DrawCylinderWires(position, radiusTop, radiusBottom, height, slices, color); + return 0; +} -// Initialize audio device and context -int lua_InitAudioDevice(lua_State *L) +// Draw a cylinder wires with base at startPos and top at endPos +static int rl_DrawCylinderWiresEx(lua_State *L) { - InitAudioDevice(); + Vector3 startPos = RLUA_CHECK_Vector3(L, 1); + Vector3 endPos = RLUA_CHECK_Vector3(L, 2); + float startRadius = (float)luaL_checknumber(L, 3); + float endRadius = (float)luaL_checknumber(L, 4); + int sides = (int)luaL_checkinteger(L, 5); + Color color = RLUA_CHECK_Color(L, 6); + DrawCylinderWiresEx(startPos, endPos, startRadius, endRadius, sides, color); return 0; } -// Close the audio device and context -int lua_CloseAudioDevice(lua_State *L) +// Draw a capsule with the center of its sphere caps at startPos and endPos +static int rl_DrawCapsule(lua_State *L) { - CloseAudioDevice(); + Vector3 startPos = RLUA_CHECK_Vector3(L, 1); + Vector3 endPos = RLUA_CHECK_Vector3(L, 2); + float radius = (float)luaL_checknumber(L, 3); + int slices = (int)luaL_checkinteger(L, 4); + int rings = (int)luaL_checkinteger(L, 5); + Color color = RLUA_CHECK_Color(L, 6); + DrawCapsule(startPos, endPos, radius, slices, rings, color); return 0; } -// Check if audio device has been initialized successfully -int lua_IsAudioDeviceReady(lua_State *L) +// Draw capsule wireframe with the center of its sphere caps at startPos and endPos +static int rl_DrawCapsuleWires(lua_State *L) { - bool result = IsAudioDeviceReady(); - LuaPush_bool(L, result); - return 1; + Vector3 startPos = RLUA_CHECK_Vector3(L, 1); + Vector3 endPos = RLUA_CHECK_Vector3(L, 2); + float radius = (float)luaL_checknumber(L, 3); + int slices = (int)luaL_checkinteger(L, 4); + int rings = (int)luaL_checkinteger(L, 5); + Color color = RLUA_CHECK_Color(L, 6); + DrawCapsuleWires(startPos, endPos, radius, slices, rings, color); + return 0; } -// Set master volume (listener) -int lua_SetMasterVolume(lua_State *L) +// Draw a plane XZ +static int rl_DrawPlane(lua_State *L) { - float volume = LuaGetArgument_float(L, 1); - SetMasterVolume(volume); + Vector3 centerPos = RLUA_CHECK_Vector3(L, 1); + Vector2 size = RLUA_CHECK_Vector2(L, 2); + Color color = RLUA_CHECK_Color(L, 3); + DrawPlane(centerPos, size, color); return 0; } -// Wave/Sound loading/unloading functions -// Load wave data from file -int lua_LoadWave(lua_State *L) +// Draw a ray line +static int rl_DrawRay(lua_State *L) { - const char *fileName = LuaGetArgument_string(L, 1); - Wave result = LoadWave(fileName); - LuaPush_Wave(L, result); - return 1; + Ray ray = RLUA_CHECK_Ray(L, 1); + Color color = RLUA_CHECK_Color(L, 2); + DrawRay(ray, color); + return 0; } -// WARNING: Load wave data from raw array data -int lua_LoadWaveEx(lua_State* L) +// Draw a grid (centered at (0, 0, 0)) +static int rl_DrawGrid(lua_State *L) +{ + int slices = (int)luaL_checkinteger(L, 1); + float spacing = (float)luaL_checknumber(L, 2); + DrawGrid(slices, spacing); + return 0; +} + +// ------------------------------------------------------------------------------------ +// Model 3d Loading and Drawing Functions (Module: models) +// ------------------------------------------------------------------------------------ +// Model management functions +// Load model from files (meshes and materials) +static int rl_LoadModel(lua_State *L) { - // TODO: arg1 parameter should be a float arrat... - - float *arg1 = 0; - int arg2 = LuaGetArgument_int(L, 2); - int arg3 = LuaGetArgument_int(L, 3); - int arg4 = LuaGetArgument_int(L, 4); - int arg5 = LuaGetArgument_int(L, 5); - Wave result = LoadWaveEx(arg1, arg2, arg3, arg4, arg5); - LuaPush_Wave(L, result); + const char * fileName = luaL_checkstring(L, 1); + Model result = LoadModel(fileName); + RLUA_PUSH_Resource(L, &result, sizeof(Model), "Model"); return 1; } -// Load sound from file -int lua_LoadSound(lua_State *L) +// Load model from generated mesh (default material) +static int rl_LoadModelFromMesh(lua_State *L) { - const char *fileName = LuaGetArgument_string(L, 1); - Sound result = LoadSound(fileName); - LuaPush_Sound(L, result); + Mesh mesh = *(Mesh*)RLUA_CHECK_Resource(L, 1, "Mesh"); + Model result = LoadModelFromMesh(mesh); + RLUA_PUSH_Resource(L, &result, sizeof(Model), "Model"); return 1; } -// Load sound from wave data -int lua_LoadSoundFromWave(lua_State *L) +// Check if a model is valid (loaded in GPU, VAO/VBOs) +static int rl_IsModelValid(lua_State *L) { - Wave wave = LuaGetArgument_Wave(L, 1); - Sound result = LoadSoundFromWave(wave); - LuaPush_Sound(L, result); + Model model = *(Model*)RLUA_CHECK_Resource(L, 1, "Model"); + bool result = IsModelValid(model); + lua_pushboolean(L, result); return 1; } -// WARNING: Update sound buffer with new data -int lua_UpdateSound(lua_State* L) +// Unload model (including meshes) from memory (RAM and/or VRAM) +static int rl_UnloadModel(lua_State *L) { - // TODO: arg2 parameter is a void pointer... - - Sound arg1 = LuaGetArgument_Sound(L, 1); - void *arg2 = LuaGetArgument_ptr(L, 2); - int arg3 = LuaGetArgument_int(L, 3); - UpdateSound(arg1, arg2, arg3); + Model model = *(Model*)RLUA_CHECK_Resource(L, 1, "Model"); + UnloadModel(model); return 0; } -// Unload wave data -int lua_UnloadWave(lua_State *L) +// Compute model bounding box limits (considers all meshes) +static int rl_GetModelBoundingBox(lua_State *L) { - Wave wave = LuaGetArgument_Wave(L, 1); - UnloadWave(wave); - return 0; + Model model = *(Model*)RLUA_CHECK_Resource(L, 1, "Model"); + BoundingBox result = GetModelBoundingBox(model); + RLUA_PUSH_BoundingBox(L, result); + return 1; } -// Unload sound -int lua_UnloadSound(lua_State *L) +// Model drawing functions +// Draw a model (with texture if set) +static int rl_DrawModel(lua_State *L) { - Sound sound = LuaGetArgument_Sound(L, 1); - UnloadSound(sound); + Model model = *(Model*)RLUA_CHECK_Resource(L, 1, "Model"); + Vector3 position = RLUA_CHECK_Vector3(L, 2); + float scale = (float)luaL_checknumber(L, 3); + Color tint = RLUA_CHECK_Color(L, 4); + DrawModel(model, position, scale, tint); return 0; } -// Wave/Sound management functions -// Play a sound -int lua_PlaySound(lua_State *L) -{ - Sound sound = LuaGetArgument_Sound(L, 1); - PlaySound(sound); +// Draw a model with extended parameters +static int rl_DrawModelEx(lua_State *L) +{ + Model model = *(Model*)RLUA_CHECK_Resource(L, 1, "Model"); + Vector3 position = RLUA_CHECK_Vector3(L, 2); + Vector3 rotationAxis = RLUA_CHECK_Vector3(L, 3); + float rotationAngle = (float)luaL_checknumber(L, 4); + Vector3 scale = RLUA_CHECK_Vector3(L, 5); + Color tint = RLUA_CHECK_Color(L, 6); + DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint); return 0; } -// Pause a sound -int lua_PauseSound(lua_State *L) +// Draw a model wires (with texture if set) +static int rl_DrawModelWires(lua_State *L) { - Sound sound = LuaGetArgument_Sound(L, 1); - PauseSound(sound); + Model model = *(Model*)RLUA_CHECK_Resource(L, 1, "Model"); + Vector3 position = RLUA_CHECK_Vector3(L, 2); + float scale = (float)luaL_checknumber(L, 3); + Color tint = RLUA_CHECK_Color(L, 4); + DrawModelWires(model, position, scale, tint); return 0; } -// Resume a paused sound -int lua_ResumeSound(lua_State *L) -{ - Sound sound = LuaGetArgument_Sound(L, 1); - ResumeSound(sound); +// Draw a model wires (with texture if set) with extended parameters +static int rl_DrawModelWiresEx(lua_State *L) +{ + Model model = *(Model*)RLUA_CHECK_Resource(L, 1, "Model"); + Vector3 position = RLUA_CHECK_Vector3(L, 2); + Vector3 rotationAxis = RLUA_CHECK_Vector3(L, 3); + float rotationAngle = (float)luaL_checknumber(L, 4); + Vector3 scale = RLUA_CHECK_Vector3(L, 5); + Color tint = RLUA_CHECK_Color(L, 6); + DrawModelWiresEx(model, position, rotationAxis, rotationAngle, scale, tint); return 0; } -// Stop playing a sound -int lua_StopSound(lua_State *L) +// Draw bounding box (wires) +static int rl_DrawBoundingBox(lua_State *L) { - Sound sound = LuaGetArgument_Sound(L, 1); - StopSound(sound); + BoundingBox box = RLUA_CHECK_BoundingBox(L, 1); + Color color = RLUA_CHECK_Color(L, 2); + DrawBoundingBox(box, color); return 0; } -// Check if a sound is currently playing -int lua_IsSoundPlaying(lua_State *L) +// Draw a billboard texture +static int rl_DrawBillboard(lua_State *L) { - Sound sound = LuaGetArgument_Sound(L, 1); - bool result = IsSoundPlaying(sound); - LuaPush_bool(L, result); - return 1; + Camera camera = RLUA_CHECK_Camera(L, 1); + Texture2D texture = *(Texture2D*)RLUA_CHECK_Resource(L, 2, "Texture2D"); + Vector3 position = RLUA_CHECK_Vector3(L, 3); + float scale = (float)luaL_checknumber(L, 4); + Color tint = RLUA_CHECK_Color(L, 5); + DrawBillboard(camera, texture, position, scale, tint); + return 0; } -// Set volume for a sound (1.0 is max level) -int lua_SetSoundVolume(lua_State *L) +// Draw a billboard texture defined by source +static int rl_DrawBillboardRec(lua_State *L) { - Sound sound = LuaGetArgument_Sound(L, 1); - float volume = LuaGetArgument_float(L, 2); - SetSoundVolume(sound, volume); + Camera camera = RLUA_CHECK_Camera(L, 1); + Texture2D texture = *(Texture2D*)RLUA_CHECK_Resource(L, 2, "Texture2D"); + Rectangle source = RLUA_CHECK_Rectangle(L, 3); + Vector3 position = RLUA_CHECK_Vector3(L, 4); + Vector2 size = RLUA_CHECK_Vector2(L, 5); + Color tint = RLUA_CHECK_Color(L, 6); + DrawBillboardRec(camera, texture, source, position, size, tint); return 0; } -// Set pitch for a sound (1.0 is base level) -int lua_SetSoundPitch(lua_State *L) +// Draw a billboard texture defined by source and rotation +static int rl_DrawBillboardPro(lua_State *L) { - Sound sound = LuaGetArgument_Sound(L, 1); - float pitch = LuaGetArgument_float(L, 2); - SetSoundPitch(sound, pitch); + Camera camera = RLUA_CHECK_Camera(L, 1); + Texture2D texture = *(Texture2D*)RLUA_CHECK_Resource(L, 2, "Texture2D"); + Rectangle source = RLUA_CHECK_Rectangle(L, 3); + Vector3 position = RLUA_CHECK_Vector3(L, 4); + Vector3 up = RLUA_CHECK_Vector3(L, 5); + Vector2 size = RLUA_CHECK_Vector2(L, 6); + Vector2 origin = RLUA_CHECK_Vector2(L, 7); + float rotation = (float)luaL_checknumber(L, 8); + Color tint = RLUA_CHECK_Color(L, 9); + DrawBillboardPro(camera, texture, source, position, up, size, origin, rotation, tint); return 0; } -// Convert wave data to desired format -int lua_WaveFormat(lua_State *L) +// Mesh management functions +// Upload mesh vertex data in GPU and provide VAO/VBO ids +static int rl_UploadMesh(lua_State *L) { - Wave wave = LuaGetArgument_Wave(L, 1); - int sampleRate = LuaGetArgument_int(L, 2); - int sampleSize = LuaGetArgument_int(L, 3); - int channels = LuaGetArgument_int(L, 4); - WaveFormat(wave, sampleRate, sampleSize, channels); + Mesh * mesh = (Mesh *)lua_touserdata(L, 1); + bool dynamic = lua_toboolean(L, 2); + UploadMesh(mesh, dynamic); return 0; } -// Copy a wave to a new wave -int lua_WaveCopy(lua_State *L) +// Update mesh vertex data in GPU for a specific buffer index +static int rl_UpdateMeshBuffer(lua_State *L) { - Wave wave = LuaGetArgument_Wave(L, 1); - Wave result = WaveCopy(wave); - LuaPush_Wave(L, result); - return 1; + Mesh mesh = *(Mesh*)RLUA_CHECK_Resource(L, 1, "Mesh"); + int index = (int)luaL_checkinteger(L, 2); + const void * data = (const void *)lua_touserdata(L, 3); + int dataSize = (int)luaL_checkinteger(L, 4); + int offset = (int)luaL_checkinteger(L, 5); + UpdateMeshBuffer(mesh, index, data, dataSize, offset); + return 0; } -// Crop a wave to defined samples range -int lua_WaveCrop(lua_State *L) +// Unload mesh data from CPU and GPU +static int rl_UnloadMesh(lua_State *L) { - Wave wave = LuaGetArgument_Wave(L, 1); - int initSample = LuaGetArgument_int(L, 2); - int finalSample = LuaGetArgument_int(L, 3); - WaveCrop(wave, initSample, finalSample); + Mesh mesh = *(Mesh*)RLUA_CHECK_Resource(L, 1, "Mesh"); + UnloadMesh(mesh); return 0; } -// WARNING: Get samples data from wave as a floats array -int lua_GetWaveData(lua_State* L) +// Draw a 3d mesh with material and transform +static int rl_DrawMesh(lua_State *L) { - // TODO: return value should be a float array... - - Wave arg1 = LuaGetArgument_Wave(L, 1); - float *result = GetWaveData(arg1); - //LuaPush_float(L, result); - //LuaPush_float(L, result); + Mesh mesh = *(Mesh*)RLUA_CHECK_Resource(L, 1, "Mesh"); + Material material = *(Material*)RLUA_CHECK_Resource(L, 2, "Material"); + Matrix transform = RLUA_CHECK_Matrix(L, 3); + DrawMesh(mesh, material, transform); return 0; } -// Music management functions +// Draw multiple mesh instances with material and different transforms +static int rl_DrawMeshInstanced(lua_State *L) +{ + Mesh mesh = *(Mesh*)RLUA_CHECK_Resource(L, 1, "Mesh"); + Material material = *(Material*)RLUA_CHECK_Resource(L, 2, "Material"); + const Matrix * transforms = (const Matrix *)lua_touserdata(L, 3); + int instances = (int)luaL_checkinteger(L, 4); + DrawMeshInstanced(mesh, material, transforms, instances); + return 0; +} -// Load music stream from file -int lua_LoadMusicStream(lua_State *L) +// Compute mesh bounding box limits +static int rl_GetMeshBoundingBox(lua_State *L) { - const char *fileName = LuaGetArgument_string(L, 1); - Music result = LoadMusicStream(fileName); - LuaPush_Music(L, result); + Mesh mesh = *(Mesh*)RLUA_CHECK_Resource(L, 1, "Mesh"); + BoundingBox result = GetMeshBoundingBox(mesh); + RLUA_PUSH_BoundingBox(L, result); return 1; } -// Unload music stream -int lua_UnloadMusicStream(lua_State *L) +// Compute mesh tangents +static int rl_GenMeshTangents(lua_State *L) { - Music music = LuaGetArgument_Music(L, 1); - UnloadMusicStream(music); + Mesh * mesh = (Mesh *)lua_touserdata(L, 1); + GenMeshTangents(mesh); return 0; } -// Start music playing -int lua_PlayMusicStream(lua_State *L) +// Export mesh data to file, returns true on success +static int rl_ExportMesh(lua_State *L) { - Music music = LuaGetArgument_Music(L, 1); - PlayMusicStream(music); - return 0; + Mesh mesh = *(Mesh*)RLUA_CHECK_Resource(L, 1, "Mesh"); + const char * fileName = luaL_checkstring(L, 2); + bool result = ExportMesh(mesh, fileName); + lua_pushboolean(L, result); + return 1; } -// Updates buffers for music streaming -int lua_UpdateMusicStream(lua_State *L) +// Export mesh as code file (.h) defining multiple arrays of vertex attributes +static int rl_ExportMeshAsCode(lua_State *L) { - Music music = LuaGetArgument_Music(L, 1); - UpdateMusicStream(music); - return 0; + Mesh mesh = *(Mesh*)RLUA_CHECK_Resource(L, 1, "Mesh"); + const char * fileName = luaL_checkstring(L, 2); + bool result = ExportMeshAsCode(mesh, fileName); + lua_pushboolean(L, result); + return 1; } -// Stop music playing -int lua_StopMusicStream(lua_State *L) +// Mesh generation functions +// Generate polygonal mesh +static int rl_GenMeshPoly(lua_State *L) { - Music music = LuaGetArgument_Music(L, 1); - StopMusicStream(music); - return 0; + int sides = (int)luaL_checkinteger(L, 1); + float radius = (float)luaL_checknumber(L, 2); + Mesh result = GenMeshPoly(sides, radius); + RLUA_PUSH_Resource(L, &result, sizeof(Mesh), "Mesh"); + return 1; } -// Pause music playing -int lua_PauseMusicStream(lua_State *L) +// Generate plane mesh (with subdivisions) +static int rl_GenMeshPlane(lua_State *L) { - Music music = LuaGetArgument_Music(L, 1); - PauseMusicStream(music); - return 0; + float width = (float)luaL_checknumber(L, 1); + float length = (float)luaL_checknumber(L, 2); + int resX = (int)luaL_checkinteger(L, 3); + int resZ = (int)luaL_checkinteger(L, 4); + Mesh result = GenMeshPlane(width, length, resX, resZ); + RLUA_PUSH_Resource(L, &result, sizeof(Mesh), "Mesh"); + return 1; } -// Resume playing paused music -int lua_ResumeMusicStream(lua_State *L) +// Generate cuboid mesh +static int rl_GenMeshCube(lua_State *L) { - Music music = LuaGetArgument_Music(L, 1); - ResumeMusicStream(music); - return 0; + float width = (float)luaL_checknumber(L, 1); + float height = (float)luaL_checknumber(L, 2); + float length = (float)luaL_checknumber(L, 3); + Mesh result = GenMeshCube(width, height, length); + RLUA_PUSH_Resource(L, &result, sizeof(Mesh), "Mesh"); + return 1; } -// Check if music is playing -int lua_IsMusicPlaying(lua_State *L) +// Generate sphere mesh (standard sphere) +static int rl_GenMeshSphere(lua_State *L) { - Music music = LuaGetArgument_Music(L, 1); - bool result = IsMusicPlaying(music); - LuaPush_bool(L, result); + float radius = (float)luaL_checknumber(L, 1); + int rings = (int)luaL_checkinteger(L, 2); + int slices = (int)luaL_checkinteger(L, 3); + Mesh result = GenMeshSphere(radius, rings, slices); + RLUA_PUSH_Resource(L, &result, sizeof(Mesh), "Mesh"); return 1; } -// Set volume for music (1.0 is max level) -int lua_SetMusicVolume(lua_State *L) +// Generate half-sphere mesh (no bottom cap) +static int rl_GenMeshHemiSphere(lua_State *L) { - Music music = LuaGetArgument_Music(L, 1); - float volume = LuaGetArgument_float(L, 2); - SetMusicVolume(music, volume); - return 0; + float radius = (float)luaL_checknumber(L, 1); + int rings = (int)luaL_checkinteger(L, 2); + int slices = (int)luaL_checkinteger(L, 3); + Mesh result = GenMeshHemiSphere(radius, rings, slices); + RLUA_PUSH_Resource(L, &result, sizeof(Mesh), "Mesh"); + return 1; } -// Set pitch for a music (1.0 is base level) -int lua_SetMusicPitch(lua_State *L) +// Generate cylinder mesh +static int rl_GenMeshCylinder(lua_State *L) { - Music music = LuaGetArgument_Music(L, 1); - float pitch = LuaGetArgument_float(L, 2); - SetMusicPitch(music, pitch); - return 0; + float radius = (float)luaL_checknumber(L, 1); + float height = (float)luaL_checknumber(L, 2); + int slices = (int)luaL_checkinteger(L, 3); + Mesh result = GenMeshCylinder(radius, height, slices); + RLUA_PUSH_Resource(L, &result, sizeof(Mesh), "Mesh"); + return 1; } -// Set music loop count (loop repeats) -int lua_SetMusicLoopCount(lua_State *L) +// Generate cone/pyramid mesh +static int rl_GenMeshCone(lua_State *L) { - Music music = LuaGetArgument_Music(L, 1); - int count = LuaGetArgument_int(L, 2); - SetMusicLoopCount(music, count); - return 0; + float radius = (float)luaL_checknumber(L, 1); + float height = (float)luaL_checknumber(L, 2); + int slices = (int)luaL_checkinteger(L, 3); + Mesh result = GenMeshCone(radius, height, slices); + RLUA_PUSH_Resource(L, &result, sizeof(Mesh), "Mesh"); + return 1; } -// Get music time length (in seconds) -int lua_GetMusicTimeLength(lua_State *L) +// Generate torus mesh +static int rl_GenMeshTorus(lua_State *L) { - Music music = LuaGetArgument_Music(L, 1); - float result = GetMusicTimeLength(music); - LuaPush_float(L, result); + float radius = (float)luaL_checknumber(L, 1); + float size = (float)luaL_checknumber(L, 2); + int radSeg = (int)luaL_checkinteger(L, 3); + int sides = (int)luaL_checkinteger(L, 4); + Mesh result = GenMeshTorus(radius, size, radSeg, sides); + RLUA_PUSH_Resource(L, &result, sizeof(Mesh), "Mesh"); return 1; } -// Get current music time played (in seconds) -int lua_GetMusicTimePlayed(lua_State *L) +// Generate trefoil knot mesh +static int rl_GenMeshKnot(lua_State *L) { - Music music = LuaGetArgument_Music(L, 1); - float result = GetMusicTimePlayed(music); - LuaPush_float(L, result); + float radius = (float)luaL_checknumber(L, 1); + float size = (float)luaL_checknumber(L, 2); + int radSeg = (int)luaL_checkinteger(L, 3); + int sides = (int)luaL_checkinteger(L, 4); + Mesh result = GenMeshKnot(radius, size, radSeg, sides); + RLUA_PUSH_Resource(L, &result, sizeof(Mesh), "Mesh"); return 1; } -// AudioStream management functions -// Init audio stream (to stream raw audio pcm data) -int lua_InitAudioStream(lua_State *L) +// Generate heightmap mesh from image data +static int rl_GenMeshHeightmap(lua_State *L) +{ + Image heightmap = *(Image*)RLUA_CHECK_Resource(L, 1, "Image"); + Vector3 size = RLUA_CHECK_Vector3(L, 2); + Mesh result = GenMeshHeightmap(heightmap, size); + RLUA_PUSH_Resource(L, &result, sizeof(Mesh), "Mesh"); + return 1; +} + +// Generate cubes-based map mesh from image data +static int rl_GenMeshCubicmap(lua_State *L) { - unsigned int sampleRate = LuaGetArgument_unsigned(L, 1); - unsigned int sampleSize = LuaGetArgument_unsigned(L, 2); - unsigned int channels = LuaGetArgument_unsigned(L, 3); - AudioStream result = InitAudioStream(sampleRate, sampleSize, channels); - LuaPush_AudioStream(L, result); + Image cubicmap = *(Image*)RLUA_CHECK_Resource(L, 1, "Image"); + Vector3 cubeSize = RLUA_CHECK_Vector3(L, 2); + Mesh result = GenMeshCubicmap(cubicmap, cubeSize); + RLUA_PUSH_Resource(L, &result, sizeof(Mesh), "Mesh"); return 1; } -// WARNING: Update audio stream buffers with data -int lua_UpdateAudioStream(lua_State* L) +// Material loading/unloading functions +// Load materials from model file +static int rl_LoadMaterials(lua_State *L) { - // TODO: arg2 parameter is a void pointer... - - AudioStream arg1 = LuaGetArgument_AudioStream(L, 1); - void *arg2 = LuaGetArgument_ptr(L, 2); - int arg3 = LuaGetArgument_int(L, 3); - UpdateAudioStream(arg1, arg2, arg3); - return 0; + const char * fileName = luaL_checkstring(L, 1); + int materialCount = 0; + Material * result = LoadMaterials(fileName, &materialCount); + RLUA_PUSH_View(L, result, materialCount, "Material", true); + return 1; } -// Close audio stream and free memory -int lua_CloseAudioStream(lua_State *L) +// Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) +static int rl_LoadMaterialDefault(lua_State *L) { - AudioStream stream = LuaGetArgument_AudioStream(L, 1); - CloseAudioStream(stream); - return 0; + Material result = LoadMaterialDefault(); + RLUA_PUSH_Resource(L, &result, sizeof(Material), "Material"); + return 1; } -// Check if any audio stream buffers requires refill -int lua_IsAudioBufferProcessed(lua_State *L) +// Check if a material is valid (shader assigned, map textures loaded in GPU) +static int rl_IsMaterialValid(lua_State *L) { - AudioStream stream = LuaGetArgument_AudioStream(L, 1); - bool result = IsAudioBufferProcessed(stream); - LuaPush_bool(L, result); + Material material = *(Material*)RLUA_CHECK_Resource(L, 1, "Material"); + bool result = IsMaterialValid(material); + lua_pushboolean(L, result); return 1; } -// Play audio stream -int lua_PlayAudioStream(lua_State *L) +// Unload material from GPU memory (VRAM) +static int rl_UnloadMaterial(lua_State *L) { - AudioStream stream = LuaGetArgument_AudioStream(L, 1); - PlayAudioStream(stream); + Material material = *(Material*)RLUA_CHECK_Resource(L, 1, "Material"); + UnloadMaterial(material); return 0; } -// Pause audio stream -int lua_PauseAudioStream(lua_State *L) +// Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...) +static int rl_SetMaterialTexture(lua_State *L) { - AudioStream stream = LuaGetArgument_AudioStream(L, 1); - PauseAudioStream(stream); + Material * material = (Material *)lua_touserdata(L, 1); + int mapType = (int)luaL_checkinteger(L, 2); + Texture2D texture = *(Texture2D*)RLUA_CHECK_Resource(L, 3, "Texture2D"); + SetMaterialTexture(material, mapType, texture); return 0; } -// Resume audio stream -int lua_ResumeAudioStream(lua_State *L) +// Set material for a mesh +static int rl_SetModelMeshMaterial(lua_State *L) { - AudioStream stream = LuaGetArgument_AudioStream(L, 1); - ResumeAudioStream(stream); + Model * model = (Model *)lua_touserdata(L, 1); + int meshId = (int)luaL_checkinteger(L, 2); + int materialId = (int)luaL_checkinteger(L, 3); + SetModelMeshMaterial(model, meshId, materialId); return 0; } -// Check if audio stream is playing -int lua_IsAudioStreamPlaying(lua_State *L) +// Model animations loading/unloading functions +// Load model animations from file +static int rl_LoadModelAnimations(lua_State *L) { - AudioStream stream = LuaGetArgument_AudioStream(L, 1); - bool result = IsAudioStreamPlaying(stream); - LuaPush_bool(L, result); + const char * fileName = luaL_checkstring(L, 1); + int animCount = 0; + ModelAnimation * result = LoadModelAnimations(fileName, &animCount); + RLUA_PUSH_View(L, result, animCount, "ModelAnimation", true); return 1; } -// Stop audio stream -int lua_StopAudioStream(lua_State *L) +// Update model animation pose (vertex buffers and bone matrices) +static int rl_UpdateModelAnimation(lua_State *L) { - AudioStream stream = LuaGetArgument_AudioStream(L, 1); - StopAudioStream(stream); + Model model = *(Model*)RLUA_CHECK_Resource(L, 1, "Model"); + ModelAnimation anim = *(ModelAnimation*)RLUA_CHECK_Resource(L, 2, "ModelAnimation"); + float frame = (float)luaL_checknumber(L, 3); + UpdateModelAnimation(model, anim, frame); return 0; } -// Set volume for audio stream (1.0 is max level) -int lua_SetAudioStreamVolume(lua_State *L) +// Update model animation pose, blending two animations +static int rl_UpdateModelAnimationEx(lua_State *L) { - AudioStream stream = LuaGetArgument_AudioStream(L, 1); - float volume = LuaGetArgument_float(L, 2); - SetAudioStreamVolume(stream, volume); + Model model = *(Model*)RLUA_CHECK_Resource(L, 1, "Model"); + ModelAnimation animA = *(ModelAnimation*)RLUA_CHECK_Resource(L, 2, "ModelAnimation"); + float frameA = (float)luaL_checknumber(L, 3); + ModelAnimation animB = *(ModelAnimation*)RLUA_CHECK_Resource(L, 4, "ModelAnimation"); + float frameB = (float)luaL_checknumber(L, 5); + float blend = (float)luaL_checknumber(L, 6); + UpdateModelAnimationEx(model, animA, frameA, animB, frameB, blend); return 0; } -// Set pitch for audio stream (1.0 is base level) -int lua_SetAudioStreamPitch(lua_State *L) +// Unload animation array data +static int rl_UnloadModelAnimations(lua_State *L) { - AudioStream stream = LuaGetArgument_AudioStream(L, 1); - float pitch = LuaGetArgument_float(L, 2); - SetAudioStreamPitch(stream, pitch); + ModelAnimation * animations = (ModelAnimation *)lua_touserdata(L, 1); + int animCount = (int)luaL_checkinteger(L, 2); + UnloadModelAnimations(animations, animCount); return 0; } -// TODO: FROM HERE DOWN! - -//---------------------------------------------------------------------------------- -// Module Functions Definition - Utils math -//---------------------------------------------------------------------------------- -int lua_Clamp(lua_State* L) +// Check model animation skeleton match +static int rl_IsModelAnimationValid(lua_State *L) { - float arg1 = LuaGetArgument_float(L, 1); - float arg2 = LuaGetArgument_float(L, 2); - float arg3 = LuaGetArgument_float(L, 3); - float result = Clamp(arg1, arg2, arg3); - LuaPush_float(L, result); + Model model = *(Model*)RLUA_CHECK_Resource(L, 1, "Model"); + ModelAnimation anim = *(ModelAnimation*)RLUA_CHECK_Resource(L, 2, "ModelAnimation"); + bool result = IsModelAnimationValid(model, anim); + lua_pushboolean(L, result); return 1; } -//---------------------------------------------------------------------------------- -// Module Functions Definition - Vector2 math -//---------------------------------------------------------------------------------- -int lua_Vector2Zero(lua_State* L) +// Collision detection functions +// Check collision between two spheres +static int rl_CheckCollisionSpheres(lua_State *L) { - Vector2 result = Vector2Zero(); - LuaPush_Vector2(L, result); + Vector3 center1 = RLUA_CHECK_Vector3(L, 1); + float radius1 = (float)luaL_checknumber(L, 2); + Vector3 center2 = RLUA_CHECK_Vector3(L, 3); + float radius2 = (float)luaL_checknumber(L, 4); + bool result = CheckCollisionSpheres(center1, radius1, center2, radius2); + lua_pushboolean(L, result); return 1; } -int lua_Vector2One(lua_State* L) +// Check collision between two bounding boxes +static int rl_CheckCollisionBoxes(lua_State *L) { - Vector2 result = Vector2One(); - LuaPush_Vector2(L, result); + BoundingBox box1 = RLUA_CHECK_BoundingBox(L, 1); + BoundingBox box2 = RLUA_CHECK_BoundingBox(L, 2); + bool result = CheckCollisionBoxes(box1, box2); + lua_pushboolean(L, result); return 1; } -int lua_Vector2Add(lua_State* L) +// Check collision between box and sphere +static int rl_CheckCollisionBoxSphere(lua_State *L) { - Vector2 arg1 = LuaGetArgument_Vector2(L, 1); - Vector2 arg2 = LuaGetArgument_Vector2(L, 2); - Vector2 result = Vector2Add(arg1, arg2); - LuaPush_Vector2(L, result); + BoundingBox box = RLUA_CHECK_BoundingBox(L, 1); + Vector3 center = RLUA_CHECK_Vector3(L, 2); + float radius = (float)luaL_checknumber(L, 3); + bool result = CheckCollisionBoxSphere(box, center, radius); + lua_pushboolean(L, result); return 1; } -int lua_Vector2Subtract(lua_State* L) +// Get collision info between ray and sphere +static int rl_GetRayCollisionSphere(lua_State *L) { - Vector2 arg1 = LuaGetArgument_Vector2(L, 1); - Vector2 arg2 = LuaGetArgument_Vector2(L, 2); - Vector2 result = Vector2Subtract(arg1, arg2); - LuaPush_Vector2(L, result); + Ray ray = RLUA_CHECK_Ray(L, 1); + Vector3 center = RLUA_CHECK_Vector3(L, 2); + float radius = (float)luaL_checknumber(L, 3); + RayCollision result = GetRayCollisionSphere(ray, center, radius); + RLUA_PUSH_RayCollision(L, result); return 1; } -int lua_Vector2Lenght(lua_State* L) +// Get collision info between ray and box +static int rl_GetRayCollisionBox(lua_State *L) { - Vector2 arg1 = LuaGetArgument_Vector2(L, 1); - float result = Vector2Lenght(arg1); - LuaPush_float(L, result); + Ray ray = RLUA_CHECK_Ray(L, 1); + BoundingBox box = RLUA_CHECK_BoundingBox(L, 2); + RayCollision result = GetRayCollisionBox(ray, box); + RLUA_PUSH_RayCollision(L, result); return 1; } -int lua_Vector2DotProduct(lua_State* L) +// Get collision info between ray and mesh +static int rl_GetRayCollisionMesh(lua_State *L) { - Vector2 arg1 = LuaGetArgument_Vector2(L, 1); - Vector2 arg2 = LuaGetArgument_Vector2(L, 2); - float result = Vector2DotProduct(arg1, arg2); - LuaPush_float(L, result); + Ray ray = RLUA_CHECK_Ray(L, 1); + Mesh mesh = *(Mesh*)RLUA_CHECK_Resource(L, 2, "Mesh"); + Matrix transform = RLUA_CHECK_Matrix(L, 3); + RayCollision result = GetRayCollisionMesh(ray, mesh, transform); + RLUA_PUSH_RayCollision(L, result); return 1; } -int lua_Vector2Distance(lua_State* L) +// Get collision info between ray and triangle +static int rl_GetRayCollisionTriangle(lua_State *L) { - Vector2 arg1 = LuaGetArgument_Vector2(L, 1); - Vector2 arg2 = LuaGetArgument_Vector2(L, 2); - float result = Vector2Distance(arg1, arg2); - LuaPush_float(L, result); + Ray ray = RLUA_CHECK_Ray(L, 1); + Vector3 p1 = RLUA_CHECK_Vector3(L, 2); + Vector3 p2 = RLUA_CHECK_Vector3(L, 3); + Vector3 p3 = RLUA_CHECK_Vector3(L, 4); + RayCollision result = GetRayCollisionTriangle(ray, p1, p2, p3); + RLUA_PUSH_RayCollision(L, result); return 1; } -int lua_Vector2Angle(lua_State* L) +// Get collision info between ray and quad +static int rl_GetRayCollisionQuad(lua_State *L) { - Vector2 arg1 = LuaGetArgument_Vector2(L, 1); - Vector2 arg2 = LuaGetArgument_Vector2(L, 2); - float result = Vector2Angle(arg1, arg2); - LuaPush_float(L, result); + Ray ray = RLUA_CHECK_Ray(L, 1); + Vector3 p1 = RLUA_CHECK_Vector3(L, 2); + Vector3 p2 = RLUA_CHECK_Vector3(L, 3); + Vector3 p3 = RLUA_CHECK_Vector3(L, 4); + Vector3 p4 = RLUA_CHECK_Vector3(L, 5); + RayCollision result = GetRayCollisionQuad(ray, p1, p2, p3, p4); + RLUA_PUSH_RayCollision(L, result); return 1; } -int lua_Vector2Scale(lua_State* L) -{ - Vector2 arg1 = LuaGetArgument_Vector2(L, 1); - float arg2 = LuaGetArgument_float(L, 2); - Vector2Scale(&arg1, arg2); - LuaPush_Vector2(L, arg1); - return 1; -} +// ------------------------------------------------------------------------------------ +// Audio Loading and Playing Functions (Module: audio) +// ------------------------------------------------------------------------------------ -int lua_Vector2Negate(lua_State* L) +// Audio device management functions +// Initialize audio device and context +static int rl_InitAudioDevice(lua_State *L) { - Vector2 arg1 = LuaGetArgument_Vector2(L, 1); - Vector2Negate(&arg1); - LuaPush_Vector2(L, arg1); - return 1; + InitAudioDevice(); + return 0; } -int lua_Vector2Divide(lua_State* L) +// Close the audio device and context +static int rl_CloseAudioDevice(lua_State *L) { - Vector2 arg1 = LuaGetArgument_Vector2(L, 1); - float arg2 = LuaGetArgument_float(L, 2); - Vector2Divide(&arg1, arg2); - LuaPush_Vector2(L, arg1); - return 1; + CloseAudioDevice(); + return 0; } -int lua_Vector2Normalize(lua_State* L) +// Check if audio device has been initialized successfully +static int rl_IsAudioDeviceReady(lua_State *L) { - Vector2 arg1 = LuaGetArgument_Vector2(L, 1); - Vector2Normalize(&arg1); - LuaPush_Vector2(L, arg1); + bool result = IsAudioDeviceReady(); + lua_pushboolean(L, result); return 1; } -//---------------------------------------------------------------------------------- -// raylib [raymath] module functions - Vector3 math -//---------------------------------------------------------------------------------- -int lua_VectorZero(lua_State* L) +// Set master volume (listener) +static int rl_SetMasterVolume(lua_State *L) { - Vector3 result = VectorZero(); - LuaPush_Vector3(L, result); - return 1; + float volume = (float)luaL_checknumber(L, 1); + SetMasterVolume(volume); + return 0; } -int lua_VectorOne(lua_State* L) +// Get master volume (listener) +static int rl_GetMasterVolume(lua_State *L) { - Vector3 result = VectorOne(); - LuaPush_Vector3(L, result); + float result = GetMasterVolume(); + lua_pushnumber(L, result); return 1; } -int lua_VectorAdd(lua_State* L) +// Wave/Sound loading/unloading functions +// Load wave data from file +static int rl_LoadWave(lua_State *L) { - Vector3 arg1 = LuaGetArgument_Vector3(L, 1); - Vector3 arg2 = LuaGetArgument_Vector3(L, 2); - Vector3 result = VectorAdd(arg1, arg2); - LuaPush_Vector3(L, result); + const char * fileName = luaL_checkstring(L, 1); + Wave result = LoadWave(fileName); + RLUA_PUSH_Resource(L, &result, sizeof(Wave), "Wave"); return 1; } -int lua_VectorSubtract(lua_State* L) +// Load wave from memory buffer, fileType refers to extension: i.e. '.wav' +static int rl_LoadWaveFromMemory(lua_State *L) { - Vector3 arg1 = LuaGetArgument_Vector3(L, 1); - Vector3 arg2 = LuaGetArgument_Vector3(L, 2); - Vector3 result = VectorSubtract(arg1, arg2); - LuaPush_Vector3(L, result); + const char * fileType = luaL_checkstring(L, 1); + const unsigned char * fileData = (const unsigned char *)lua_touserdata(L, 2); + int dataSize = (int)luaL_checkinteger(L, 3); + Wave result = LoadWaveFromMemory(fileType, fileData, dataSize); + RLUA_PUSH_Resource(L, &result, sizeof(Wave), "Wave"); return 1; } -int lua_VectorCrossProduct(lua_State* L) +// Checks if wave data is valid (data loaded and parameters) +static int rl_IsWaveValid(lua_State *L) { - Vector3 arg1 = LuaGetArgument_Vector3(L, 1); - Vector3 arg2 = LuaGetArgument_Vector3(L, 2); - Vector3 result = VectorCrossProduct(arg1, arg2); - LuaPush_Vector3(L, result); + Wave wave = *(Wave*)RLUA_CHECK_Resource(L, 1, "Wave"); + bool result = IsWaveValid(wave); + lua_pushboolean(L, result); return 1; } -int lua_VectorPerpendicular(lua_State* L) +// Load sound from file +static int rl_LoadSound(lua_State *L) { - Vector3 arg1 = LuaGetArgument_Vector3(L, 1); - Vector3 result = VectorPerpendicular(arg1); - LuaPush_Vector3(L, result); + const char * fileName = luaL_checkstring(L, 1); + Sound result = LoadSound(fileName); + RLUA_PUSH_Resource(L, &result, sizeof(Sound), "Sound"); return 1; } -int lua_VectorDotProduct(lua_State* L) +// Load sound from wave data +static int rl_LoadSoundFromWave(lua_State *L) { - Vector3 arg1 = LuaGetArgument_Vector3(L, 1); - Vector3 arg2 = LuaGetArgument_Vector3(L, 2); - float result = VectorDotProduct(arg1, arg2); - LuaPush_float(L, result); + Wave wave = *(Wave*)RLUA_CHECK_Resource(L, 1, "Wave"); + Sound result = LoadSoundFromWave(wave); + RLUA_PUSH_Resource(L, &result, sizeof(Sound), "Sound"); return 1; } -int lua_VectorLength(lua_State* L) +// Create a new sound that shares the same sample data as the source sound, does not own the sound data +static int rl_LoadSoundAlias(lua_State *L) { - const Vector3 arg1 = LuaGetArgument_Vector3(L, 1); - float result = VectorLength(arg1); - LuaPush_float(L, result); + Sound source = *(Sound*)RLUA_CHECK_Resource(L, 1, "Sound"); + Sound result = LoadSoundAlias(source); + RLUA_PUSH_Resource(L, &result, sizeof(Sound), "Sound"); return 1; } -int lua_VectorScale(lua_State* L) +// Checks if a sound is valid (data loaded and buffers initialized) +static int rl_IsSoundValid(lua_State *L) { - Vector3 arg1 = LuaGetArgument_Vector3(L, 1); - float arg2 = LuaGetArgument_float(L, 2); - VectorScale(&arg1, arg2); - LuaPush_Vector3(L, arg1); + Sound sound = *(Sound*)RLUA_CHECK_Resource(L, 1, "Sound"); + bool result = IsSoundValid(sound); + lua_pushboolean(L, result); return 1; } -int lua_VectorNegate(lua_State* L) +// Update sound buffer with new data (default data format: 32 bit float, stereo) +static int rl_UpdateSound(lua_State *L) { - Vector3 arg1 = LuaGetArgument_Vector3(L, 1); - VectorNegate(&arg1); - LuaPush_Vector3(L, arg1); - return 1; + Sound sound = *(Sound*)RLUA_CHECK_Resource(L, 1, "Sound"); + const void * data = (const void *)lua_touserdata(L, 2); + int sampleCount = (int)luaL_checkinteger(L, 3); + UpdateSound(sound, data, sampleCount); + return 0; } -int lua_VectorNormalize(lua_State* L) +// Unload wave data +static int rl_UnloadWave(lua_State *L) { - Vector3 arg1 = LuaGetArgument_Vector3(L, 1); - VectorNormalize(&arg1); - LuaPush_Vector3(L, arg1); - return 1; + Wave wave = *(Wave*)RLUA_CHECK_Resource(L, 1, "Wave"); + UnloadWave(wave); + return 0; } -int lua_VectorDistance(lua_State* L) +// Unload sound +static int rl_UnloadSound(lua_State *L) { - Vector3 arg1 = LuaGetArgument_Vector3(L, 1); - Vector3 arg2 = LuaGetArgument_Vector3(L, 2); - float result = VectorDistance(arg1, arg2); - LuaPush_float(L, result); - return 1; + Sound sound = *(Sound*)RLUA_CHECK_Resource(L, 1, "Sound"); + UnloadSound(sound); + return 0; } -int lua_VectorLerp(lua_State* L) +// Unload a sound alias (does not deallocate sample data) +static int rl_UnloadSoundAlias(lua_State *L) { - Vector3 arg1 = LuaGetArgument_Vector3(L, 1); - Vector3 arg2 = LuaGetArgument_Vector3(L, 2); - float arg3 = LuaGetArgument_float(L, 3); - Vector3 result = VectorLerp(arg1, arg2, arg3); - LuaPush_Vector3(L, result); - return 1; + Sound alias = *(Sound*)RLUA_CHECK_Resource(L, 1, "Sound"); + UnloadSoundAlias(alias); + return 0; } -int lua_VectorReflect(lua_State* L) +// Export wave data to file, returns true on success +static int rl_ExportWave(lua_State *L) { - Vector3 arg1 = LuaGetArgument_Vector3(L, 1); - Vector3 arg2 = LuaGetArgument_Vector3(L, 2); - Vector3 result = VectorReflect(arg1, arg2); - LuaPush_Vector3(L, result); + Wave wave = *(Wave*)RLUA_CHECK_Resource(L, 1, "Wave"); + const char * fileName = luaL_checkstring(L, 2); + bool result = ExportWave(wave, fileName); + lua_pushboolean(L, result); return 1; } -int lua_VectorTransform(lua_State* L) +// Export wave sample data to code (.h), returns true on success +static int rl_ExportWaveAsCode(lua_State *L) { - Vector3 arg1 = LuaGetArgument_Vector3(L, 1); - Matrix arg2 = LuaGetArgument_Matrix(L, 2); - VectorTransform(&arg1, arg2); - LuaPush_Vector3(L, arg1); + Wave wave = *(Wave*)RLUA_CHECK_Resource(L, 1, "Wave"); + const char * fileName = luaL_checkstring(L, 2); + bool result = ExportWaveAsCode(wave, fileName); + lua_pushboolean(L, result); return 1; } -//---------------------------------------------------------------------------------- -// raylib [raymath] module functions - Matrix math -//---------------------------------------------------------------------------------- -int lua_MatrixDeterminant(lua_State* L) +// Wave/Sound management functions +// Play a sound +static int rl_PlaySound(lua_State *L) { - Matrix arg1 = LuaGetArgument_Matrix(L, 1); - float result = MatrixDeterminant(arg1); - LuaPush_float(L, result); - return 1; + Sound sound = *(Sound*)RLUA_CHECK_Resource(L, 1, "Sound"); + PlaySound(sound); + return 0; } -int lua_MatrixTrace(lua_State* L) +// Stop playing a sound +static int rl_StopSound(lua_State *L) { - Matrix arg1 = LuaGetArgument_Matrix(L, 1); - float result = MatrixTrace(arg1); - LuaPush_float(L, result); - return 1; + Sound sound = *(Sound*)RLUA_CHECK_Resource(L, 1, "Sound"); + StopSound(sound); + return 0; } -int lua_MatrixTranspose(lua_State* L) +// Pause a sound +static int rl_PauseSound(lua_State *L) { - Matrix arg1 = LuaGetArgument_Matrix(L, 1); - MatrixTranspose(&arg1); - LuaPush_Matrix(L, &arg1); - return 1; + Sound sound = *(Sound*)RLUA_CHECK_Resource(L, 1, "Sound"); + PauseSound(sound); + return 0; } -int lua_MatrixInvert(lua_State* L) +// Resume a paused sound +static int rl_ResumeSound(lua_State *L) { - Matrix arg1 = LuaGetArgument_Matrix(L, 1); - MatrixInvert(&arg1); - LuaPush_Matrix(L, &arg1); - return 1; + Sound sound = *(Sound*)RLUA_CHECK_Resource(L, 1, "Sound"); + ResumeSound(sound); + return 0; } -int lua_MatrixNormalize(lua_State* L) +// Check if a sound is currently playing +static int rl_IsSoundPlaying(lua_State *L) { - Matrix arg1 = LuaGetArgument_Matrix(L, 1); - MatrixNormalize(&arg1); - LuaPush_Matrix(L, &arg1); + Sound sound = *(Sound*)RLUA_CHECK_Resource(L, 1, "Sound"); + bool result = IsSoundPlaying(sound); + lua_pushboolean(L, result); return 1; } -int lua_MatrixIdentity(lua_State* L) +// Set volume for a sound (1.0 is max level) +static int rl_SetSoundVolume(lua_State *L) { - Matrix result = MatrixIdentity(); - LuaPush_Matrix(L, &result); - return 1; + Sound sound = *(Sound*)RLUA_CHECK_Resource(L, 1, "Sound"); + float volume = (float)luaL_checknumber(L, 2); + SetSoundVolume(sound, volume); + return 0; } -int lua_MatrixAdd(lua_State* L) +// Set pitch for a sound (1.0 is base level) +static int rl_SetSoundPitch(lua_State *L) { - Matrix arg1 = LuaGetArgument_Matrix(L, 1); - Matrix arg2 = LuaGetArgument_Matrix(L, 2); - Matrix result = MatrixAdd(arg1, arg2); - LuaPush_Matrix(L, &result); - return 1; + Sound sound = *(Sound*)RLUA_CHECK_Resource(L, 1, "Sound"); + float pitch = (float)luaL_checknumber(L, 2); + SetSoundPitch(sound, pitch); + return 0; } -int lua_MatrixSubstract(lua_State* L) +// Set pan for a sound (-1.0 left, 0.0 center, 1.0 right) +static int rl_SetSoundPan(lua_State *L) { - Matrix arg1 = LuaGetArgument_Matrix(L, 1); - Matrix arg2 = LuaGetArgument_Matrix(L, 2); - Matrix result = MatrixSubstract(arg1, arg2); - LuaPush_Matrix(L, &result); - return 1; + Sound sound = *(Sound*)RLUA_CHECK_Resource(L, 1, "Sound"); + float pan = (float)luaL_checknumber(L, 2); + SetSoundPan(sound, pan); + return 0; } -int lua_MatrixTranslate(lua_State* L) +// Copy a wave to a new wave +static int rl_WaveCopy(lua_State *L) { - float arg1 = LuaGetArgument_float(L, 1); - float arg2 = LuaGetArgument_float(L, 2); - float arg3 = LuaGetArgument_float(L, 3); - Matrix result = MatrixTranslate(arg1, arg2, arg3); - LuaPush_Matrix(L, &result); + Wave wave = *(Wave*)RLUA_CHECK_Resource(L, 1, "Wave"); + Wave result = WaveCopy(wave); + RLUA_PUSH_Resource(L, &result, sizeof(Wave), "Wave"); return 1; } -int lua_MatrixRotate(lua_State* L) +// Crop a wave to defined frames range +static int rl_WaveCrop(lua_State *L) { - Vector3 arg1 = LuaGetArgument_Vector3(L, 1); - float arg2 = LuaGetArgument_float(L, 2); - Matrix result = MatrixRotate(arg1, arg2); - LuaPush_Matrix(L, &result); - return 1; + Wave * wave = (Wave *)lua_touserdata(L, 1); + int initFrame = (int)luaL_checkinteger(L, 2); + int finalFrame = (int)luaL_checkinteger(L, 3); + WaveCrop(wave, initFrame, finalFrame); + return 0; } -int lua_MatrixRotateX(lua_State* L) +// Convert wave data to desired format +static int rl_WaveFormat(lua_State *L) { - float arg1 = LuaGetArgument_float(L, 1); - Matrix result = MatrixRotateX(arg1); - LuaPush_Matrix(L, &result); - return 1; + Wave * wave = (Wave *)lua_touserdata(L, 1); + int sampleRate = (int)luaL_checkinteger(L, 2); + int sampleSize = (int)luaL_checkinteger(L, 3); + int channels = (int)luaL_checkinteger(L, 4); + WaveFormat(wave, sampleRate, sampleSize, channels); + return 0; } -int lua_MatrixRotateY(lua_State* L) +// Load samples data from wave as a 32bit float data array +static int rl_LoadWaveSamples(lua_State *L) { - float arg1 = LuaGetArgument_float(L, 1); - Matrix result = MatrixRotateY(arg1); - LuaPush_Matrix(L, &result); + Wave wave = *(Wave*)RLUA_CHECK_Resource(L, 1, "Wave"); + float * result = LoadWaveSamples(wave); + lua_pushlightuserdata(L, result); return 1; } -int lua_MatrixRotateZ(lua_State* L) +// Unload samples data loaded with LoadWaveSamples() +static int rl_UnloadWaveSamples(lua_State *L) { - float arg1 = LuaGetArgument_float(L, 1); - Matrix result = MatrixRotateZ(arg1); - LuaPush_Matrix(L, &result); - return 1; + float * samples = (float *)lua_touserdata(L, 1); + UnloadWaveSamples(samples); + return 0; } -int lua_MatrixScale(lua_State* L) +// Music management functions +// Load music stream from file +static int rl_LoadMusicStream(lua_State *L) { - float arg1 = LuaGetArgument_float(L, 1); - float arg2 = LuaGetArgument_float(L, 2); - float arg3 = LuaGetArgument_float(L, 3); - Matrix result = MatrixScale(arg1, arg2, arg3); - LuaPush_Matrix(L, &result); + const char * fileName = luaL_checkstring(L, 1); + Music result = LoadMusicStream(fileName); + RLUA_PUSH_Resource(L, &result, sizeof(Music), "Music"); return 1; } -int lua_MatrixMultiply(lua_State* L) +// Load music stream from data +static int rl_LoadMusicStreamFromMemory(lua_State *L) { - Matrix arg1 = LuaGetArgument_Matrix(L, 1); - Matrix arg2 = LuaGetArgument_Matrix(L, 2); - Matrix result = MatrixMultiply(arg1, arg2); - LuaPush_Matrix(L, &result); + const char * fileType = luaL_checkstring(L, 1); + const unsigned char * data = (const unsigned char *)lua_touserdata(L, 2); + int dataSize = (int)luaL_checkinteger(L, 3); + Music result = LoadMusicStreamFromMemory(fileType, data, dataSize); + RLUA_PUSH_Resource(L, &result, sizeof(Music), "Music"); return 1; } -int lua_MatrixFrustum(lua_State* L) +// Checks if a music stream is valid (context and buffers initialized) +static int rl_IsMusicValid(lua_State *L) { - double arg1 = LuaGetArgument_double(L, 1); - double arg2 = LuaGetArgument_double(L, 2); - double arg3 = LuaGetArgument_double(L, 3); - double arg4 = LuaGetArgument_double(L, 4); - double arg5 = LuaGetArgument_double(L, 5); - double arg6 = LuaGetArgument_double(L, 6); - Matrix result = MatrixFrustum(arg1, arg2, arg3, arg4, arg5, arg6); - LuaPush_Matrix(L, &result); + Music music = *(Music*)RLUA_CHECK_Resource(L, 1, "Music"); + bool result = IsMusicValid(music); + lua_pushboolean(L, result); return 1; } -int lua_MatrixPerspective(lua_State* L) +// Unload music stream +static int rl_UnloadMusicStream(lua_State *L) { - double arg1 = LuaGetArgument_double(L, 1); - double arg2 = LuaGetArgument_double(L, 2); - double arg3 = LuaGetArgument_double(L, 3); - double arg4 = LuaGetArgument_double(L, 4); - Matrix result = MatrixPerspective(arg1, arg2, arg3, arg4); - LuaPush_Matrix(L, &result); - return 1; + Music music = *(Music*)RLUA_CHECK_Resource(L, 1, "Music"); + UnloadMusicStream(music); + return 0; } -int lua_MatrixOrtho(lua_State* L) +// Start music playing +static int rl_PlayMusicStream(lua_State *L) { - double arg1 = LuaGetArgument_double(L, 1); - double arg2 = LuaGetArgument_double(L, 2); - double arg3 = LuaGetArgument_double(L, 3); - double arg4 = LuaGetArgument_double(L, 4); - double arg5 = LuaGetArgument_double(L, 5); - double arg6 = LuaGetArgument_double(L, 6); - Matrix result = MatrixOrtho(arg1, arg2, arg3, arg4, arg5, arg6); - LuaPush_Matrix(L, &result); - return 1; + Music music = *(Music*)RLUA_CHECK_Resource(L, 1, "Music"); + PlayMusicStream(music); + return 0; } -int lua_MatrixLookAt(lua_State* L) +// Check if music is playing +static int rl_IsMusicStreamPlaying(lua_State *L) { - Vector3 arg1 = LuaGetArgument_Vector3(L, 1); - Vector3 arg2 = LuaGetArgument_Vector3(L, 2); - Vector3 arg3 = LuaGetArgument_Vector3(L, 3); - Matrix result = MatrixLookAt(arg1, arg2, arg3); - LuaPush_Matrix(L, &result); + Music music = *(Music*)RLUA_CHECK_Resource(L, 1, "Music"); + bool result = IsMusicStreamPlaying(music); + lua_pushboolean(L, result); return 1; } -//---------------------------------------------------------------------------------- -// raylib [raymath] module functions - Quaternion math -//---------------------------------------------------------------------------------- -int lua_QuaternionLength(lua_State* L) +// Updates buffers for music streaming +static int rl_UpdateMusicStream(lua_State *L) { - Quaternion arg1 = LuaGetArgument_Quaternion(L, 1); - float result = QuaternionLength(arg1); - LuaPush_float(L, result); - return 1; + Music music = *(Music*)RLUA_CHECK_Resource(L, 1, "Music"); + UpdateMusicStream(music); + return 0; } -int lua_QuaternionNormalize(lua_State* L) +// Stop music playing +static int rl_StopMusicStream(lua_State *L) { - Quaternion arg1 = LuaGetArgument_Quaternion(L, 1); - QuaternionNormalize(&arg1); - LuaPush_Quaternion(L, arg1); - return 1; + Music music = *(Music*)RLUA_CHECK_Resource(L, 1, "Music"); + StopMusicStream(music); + return 0; } -int lua_QuaternionMultiply(lua_State* L) +// Pause music playing +static int rl_PauseMusicStream(lua_State *L) { - Quaternion arg1 = LuaGetArgument_Quaternion(L, 1); - Quaternion arg2 = LuaGetArgument_Quaternion(L, 2); - Quaternion result = QuaternionMultiply(arg1, arg2); - LuaPush_Quaternion(L, result); - return 1; + Music music = *(Music*)RLUA_CHECK_Resource(L, 1, "Music"); + PauseMusicStream(music); + return 0; } -int lua_QuaternionSlerp(lua_State* L) +// Resume playing paused music +static int rl_ResumeMusicStream(lua_State *L) { - Quaternion arg1 = LuaGetArgument_Quaternion(L, 1); - Quaternion arg2 = LuaGetArgument_Quaternion(L, 2); - float arg3 = LuaGetArgument_float(L, 3); - Quaternion result = QuaternionSlerp(arg1, arg2, arg3); - LuaPush_Quaternion(L, result); - return 1; + Music music = *(Music*)RLUA_CHECK_Resource(L, 1, "Music"); + ResumeMusicStream(music); + return 0; } -int lua_QuaternionFromMatrix(lua_State* L) +// Seek music to a position (in seconds) +static int rl_SeekMusicStream(lua_State *L) { - Matrix arg1 = LuaGetArgument_Matrix(L, 1); - Quaternion result = QuaternionFromMatrix(arg1); - LuaPush_Quaternion(L, result); - return 1; + Music music = *(Music*)RLUA_CHECK_Resource(L, 1, "Music"); + float position = (float)luaL_checknumber(L, 2); + SeekMusicStream(music, position); + return 0; } -int lua_QuaternionToMatrix(lua_State* L) +// Set volume for music (1.0 is max level) +static int rl_SetMusicVolume(lua_State *L) { - Quaternion arg1 = LuaGetArgument_Quaternion(L, 1); - Matrix result = QuaternionToMatrix(arg1); - LuaPush_Matrix(L, &result); - return 1; + Music music = *(Music*)RLUA_CHECK_Resource(L, 1, "Music"); + float volume = (float)luaL_checknumber(L, 2); + SetMusicVolume(music, volume); + return 0; } -int lua_QuaternionFromAxisAngle(lua_State* L) +// Set pitch for a music (1.0 is base level) +static int rl_SetMusicPitch(lua_State *L) { - Vector3 arg1 = LuaGetArgument_Vector3(L, 1); - float arg2 = LuaGetArgument_float(L, 2); - Quaternion result = QuaternionFromAxisAngle(arg1, arg2); - LuaPush_Quaternion(L, result); - return 1; + Music music = *(Music*)RLUA_CHECK_Resource(L, 1, "Music"); + float pitch = (float)luaL_checknumber(L, 2); + SetMusicPitch(music, pitch); + return 0; } -int lua_QuaternionToAxisAngle(lua_State* L) +// Set pan for a music (-1.0 left, 0.0 center, 1.0 right) +static int rl_SetMusicPan(lua_State *L) { - Quaternion arg1 = LuaGetArgument_Quaternion(L, 1); - Vector3 arg2; - float arg3 = 0; - QuaternionToAxisAngle(arg1, &arg2, &arg3); - LuaPush_Vector3(L, arg2); - LuaPush_float(L, arg3); - return 2; + Music music = *(Music*)RLUA_CHECK_Resource(L, 1, "Music"); + float pan = (float)luaL_checknumber(L, 2); + SetMusicPan(music, pan); + return 0; } -int lua_QuaternionFromEuler(lua_State* L) +// Get music time length (in seconds) +static int rl_GetMusicTimeLength(lua_State *L) { - float arg1 = LuaGetArgument_float(L, 1); - float arg2 = LuaGetArgument_float(L, 2); - float arg3 = LuaGetArgument_float(L, 3); - Quaternion result = QuaternionFromEuler(arg1, arg2, arg3); - LuaPush_Quaternion(L, result); + Music music = *(Music*)RLUA_CHECK_Resource(L, 1, "Music"); + float result = GetMusicTimeLength(music); + lua_pushnumber(L, result); return 1; } -int lua_QuaternionToEuler(lua_State* L) +// Get current music time played (in seconds) +static int rl_GetMusicTimePlayed(lua_State *L) { - Quaternion arg1 = LuaGetArgument_Quaternion(L, 1); - Vector3 result = QuaternionToEuler(arg1); - LuaPush_Vector3(L, result); + Music music = *(Music*)RLUA_CHECK_Resource(L, 1, "Music"); + float result = GetMusicTimePlayed(music); + lua_pushnumber(L, result); return 1; } -int lua_QuaternionTransform(lua_State* L) +// AudioStream management functions +// Load audio stream (to stream raw audio pcm data) +static int rl_LoadAudioStream(lua_State *L) { - Quaternion arg1 = LuaGetArgument_Quaternion(L, 1); - Matrix arg2 = LuaGetArgument_Matrix(L, 2); - QuaternionTransform(&arg1, arg2); - LuaPush_Quaternion(L, arg1); + unsigned int sampleRate = (unsigned int)luaL_checkinteger(L, 1); + unsigned int sampleSize = (unsigned int)luaL_checkinteger(L, 2); + unsigned int channels = (unsigned int)luaL_checkinteger(L, 3); + AudioStream result = LoadAudioStream(sampleRate, sampleSize, channels); + RLUA_PUSH_Resource(L, &result, sizeof(AudioStream), "AudioStream"); return 1; } -//---------------------------------------------------------------------------------- -// physics [physac] module functions -//---------------------------------------------------------------------------------- - -// Initializes physics values, pointers and creates physics loop thread -int lua_InitPhysics(lua_State* L) +// Checks if an audio stream is valid (buffers initialized) +static int rl_IsAudioStreamValid(lua_State *L) { - InitPhysics(); - return 0; + AudioStream stream = *(AudioStream*)RLUA_CHECK_Resource(L, 1, "AudioStream"); + bool result = IsAudioStreamValid(stream); + lua_pushboolean(L, result); + return 1; } -// Returns true if physics thread is currently enabled -int lua_IsPhysicsEnabled(lua_State* L) +// Unload audio stream and free memory +static int rl_UnloadAudioStream(lua_State *L) { - bool result = IsPhysicsEnabled(); - LuaPush_bool(L, result); - return 1; + AudioStream stream = *(AudioStream*)RLUA_CHECK_Resource(L, 1, "AudioStream"); + UnloadAudioStream(stream); + return 0; } -// Sets physics global gravity force -int lua_SetPhysicsGravity(lua_State* L) +// Update audio stream buffers with data +static int rl_UpdateAudioStream(lua_State *L) { - float arg1 = LuaGetArgument_float(L, 1); - float arg2 = LuaGetArgument_float(L, 2); - SetPhysicsGravity(arg1, arg2); + AudioStream stream = *(AudioStream*)RLUA_CHECK_Resource(L, 1, "AudioStream"); + const void * data = (const void *)lua_touserdata(L, 2); + int frameCount = (int)luaL_checkinteger(L, 3); + UpdateAudioStream(stream, data, frameCount); return 0; } -// Creates a new circle physics body with generic parameters -int lua_CreatePhysicsBodyCircle(lua_State* L) +// Check if any audio stream buffers requires refill +static int rl_IsAudioStreamProcessed(lua_State *L) { - Vector2 arg1 = LuaGetArgument_Vector2(L, 1); - float arg2 = LuaGetArgument_float(L, 2); - float arg3 = LuaGetArgument_float(L, 3); - PhysicsBody result = CreatePhysicsBodyCircle(arg1, arg2, arg3); - LuaPush_PhysicsBody(L, result); + AudioStream stream = *(AudioStream*)RLUA_CHECK_Resource(L, 1, "AudioStream"); + bool result = IsAudioStreamProcessed(stream); + lua_pushboolean(L, result); return 1; } -// Creates a new rectangle physics body with generic parameters -int lua_CreatePhysicsBodyRectangle(lua_State* L) +// Play audio stream +static int rl_PlayAudioStream(lua_State *L) { - Vector2 arg1 = LuaGetArgument_Vector2(L, 1); - float arg2 = LuaGetArgument_float(L, 2); - float arg3 = LuaGetArgument_float(L, 3); - float arg4 = LuaGetArgument_float(L, 4); - PhysicsBody result = CreatePhysicsBodyRectangle(arg1, arg2, arg3, arg4); - LuaPush_PhysicsBody(L, result); - return 1; + AudioStream stream = *(AudioStream*)RLUA_CHECK_Resource(L, 1, "AudioStream"); + PlayAudioStream(stream); + return 0; } -// Creates a new polygon physics body with generic parameters -int lua_CreatePhysicsBodyPolygon(lua_State* L) +// Pause audio stream +static int rl_PauseAudioStream(lua_State *L) { - Vector2 arg1 = LuaGetArgument_Vector2(L, 1); - float arg2 = LuaGetArgument_float(L, 2); - int arg3 = LuaGetArgument_int(L, 3); - float arg4 = LuaGetArgument_float(L, 4); - PhysicsBody result = CreatePhysicsBodyPolygon(arg1, arg2, arg3, arg4); - LuaPush_PhysicsBody(L, result); - return 1; + AudioStream stream = *(AudioStream*)RLUA_CHECK_Resource(L, 1, "AudioStream"); + PauseAudioStream(stream); + return 0; } -// Adds a force to a physics body -int lua_PhysicsAddForce(lua_State* L) +// Resume audio stream +static int rl_ResumeAudioStream(lua_State *L) { - PhysicsBody arg1 = LuaGetArgument_PhysicsBody(L, 1); - Vector2 arg2 = LuaGetArgument_Vector2(L, 2); - PhysicsAddForce(arg1, arg2); + AudioStream stream = *(AudioStream*)RLUA_CHECK_Resource(L, 1, "AudioStream"); + ResumeAudioStream(stream); return 0; } -// Adds an angular force to a physics body -int lua_PhysicsAddTorque(lua_State* L) +// Check if audio stream is playing +static int rl_IsAudioStreamPlaying(lua_State *L) { - PhysicsBody arg1 = LuaGetArgument_PhysicsBody(L, 1); - float arg2 = LuaGetArgument_float(L, 2); - PhysicsAddTorque(arg1, arg2); - return 0; + AudioStream stream = *(AudioStream*)RLUA_CHECK_Resource(L, 1, "AudioStream"); + bool result = IsAudioStreamPlaying(stream); + lua_pushboolean(L, result); + return 1; } -// Shatters a polygon shape physics body to little physics bodies with explosion force -int lua_PhysicsShatter(lua_State* L) +// Stop audio stream +static int rl_StopAudioStream(lua_State *L) { - PhysicsBody arg1 = LuaGetArgument_PhysicsBody(L, 1); - Vector2 arg2 = LuaGetArgument_Vector2(L, 2); - float arg3 = LuaGetArgument_float(L, 3); - PhysicsShatter(arg1, arg2, arg3); + AudioStream stream = *(AudioStream*)RLUA_CHECK_Resource(L, 1, "AudioStream"); + StopAudioStream(stream); return 0; } -// Returns the current amount of created physics bodies -int lua_GetPhysicsBodiesCount(lua_State* L) +// Set volume for audio stream (1.0 is max level) +static int rl_SetAudioStreamVolume(lua_State *L) { - int result = GetPhysicsBodiesCount(); - LuaPush_int(L, result); - return 1; + AudioStream stream = *(AudioStream*)RLUA_CHECK_Resource(L, 1, "AudioStream"); + float volume = (float)luaL_checknumber(L, 2); + SetAudioStreamVolume(stream, volume); + return 0; } -// Returns a physics body of the bodies pool at a specific index -int lua_GetPhysicsBody(lua_State* L) +// Set pitch for audio stream (1.0 is base level) +static int rl_SetAudioStreamPitch(lua_State *L) { - int arg1 = LuaGetArgument_int(L, 1); - PhysicsBody result = GetPhysicsBody(arg1); - LuaPush_PhysicsBody(L, result); - return 1; + AudioStream stream = *(AudioStream*)RLUA_CHECK_Resource(L, 1, "AudioStream"); + float pitch = (float)luaL_checknumber(L, 2); + SetAudioStreamPitch(stream, pitch); + return 0; } -// Returns the physics body shape type (PHYSICS_CIRCLE or PHYSICS_POLYGON) -int lua_GetPhysicsShapeType(lua_State* L) +// Set pan for audio stream (-1.0 to 1.0 range, 0.0 is centered) +static int rl_SetAudioStreamPan(lua_State *L) { - int arg1 = LuaGetArgument_int(L, 1); - int result = GetPhysicsShapeType(arg1); - LuaPush_int(L, result); - return 1; + AudioStream stream = *(AudioStream*)RLUA_CHECK_Resource(L, 1, "AudioStream"); + float pan = (float)luaL_checknumber(L, 2); + SetAudioStreamPan(stream, pan); + return 0; } -// Returns the amount of vertices of a physics body shape -int lua_GetPhysicsShapeVerticesCount(lua_State* L) +// Default size for new audio streams +static int rl_SetAudioStreamBufferSizeDefault(lua_State *L) { - int arg1 = LuaGetArgument_int(L, 1); - int result = GetPhysicsShapeVerticesCount(arg1); - LuaPush_int(L, result); - return 1; + int size = (int)luaL_checkinteger(L, 1); + SetAudioStreamBufferSizeDefault(size); + return 0; } -// Returns transformed position of a body shape (body position + vertex transformed position) -int lua_GetPhysicsShapeVertex(lua_State* L) +// Audio thread callback to request new data +static int rl_SetAudioStreamCallback(lua_State *L) { - PhysicsBody arg1 = LuaGetArgument_PhysicsBody(L, 1); - int arg2 = LuaGetArgument_int(L, 2); - Vector2 result = GetPhysicsShapeVertex(arg1, arg2); - LuaPush_Vector2(L, result); - return 1; + AudioStream stream = *(AudioStream*)RLUA_CHECK_Resource(L, 1, "AudioStream"); + AudioCallback callback = (AudioCallback)lua_touserdata(L, 2); + SetAudioStreamCallback(stream, callback); + return 0; } -// Sets physics body shape transform based on radians parameter -int lua_SetPhysicsBodyRotation(lua_State* L) +// Attach audio stream processor to stream, receives frames x 2 samples as 'float' (stereo) +static int rl_AttachAudioStreamProcessor(lua_State *L) { - PhysicsBody arg1 = LuaGetArgument_PhysicsBody(L, 1); - float arg2 = LuaGetArgument_float(L, 2); - SetPhysicsBodyRotation(arg1, arg2); + AudioStream stream = *(AudioStream*)RLUA_CHECK_Resource(L, 1, "AudioStream"); + AudioCallback processor = (AudioCallback)lua_touserdata(L, 2); + AttachAudioStreamProcessor(stream, processor); return 0; } -// Unitializes and destroy a physics body -int lua_DestroyPhysicsBody(lua_State* L) +// Detach audio stream processor from stream +static int rl_DetachAudioStreamProcessor(lua_State *L) { - PhysicsBody arg1 = LuaGetArgument_PhysicsBody(L, 1); - DestroyPhysicsBody(arg1); + AudioStream stream = *(AudioStream*)RLUA_CHECK_Resource(L, 1, "AudioStream"); + AudioCallback processor = (AudioCallback)lua_touserdata(L, 2); + DetachAudioStreamProcessor(stream, processor); return 0; } -// Destroys created physics bodies and manifolds and resets global values -int lua_ResetPhysics(lua_State* L) +// Attach audio stream processor to the entire audio pipeline, receives frames x 2 samples as 'float' (stereo) +static int rl_AttachAudioMixedProcessor(lua_State *L) { - ResetPhysics(); + AudioCallback processor = (AudioCallback)lua_touserdata(L, 1); + AttachAudioMixedProcessor(processor); return 0; } -// Unitializes physics pointers and closes physics loop thread -int lua_ClosePhysics(lua_State* L) +// Detach audio stream processor from the entire audio pipeline +static int rl_DetachAudioMixedProcessor(lua_State *L) { - ClosePhysics(); + AudioCallback processor = (AudioCallback)lua_touserdata(L, 1); + DetachAudioMixedProcessor(processor); return 0; } -//---------------------------------------------------------------------------------- -// Functions Registering -//---------------------------------------------------------------------------------- -#define REG(name) { #name, lua_##name }, - -static luaL_Reg raylib_functions[] = { - - // Register non-opaque data types - REG(Color) - REG(Vector2) - REG(Vector3) - REG(Vector4) - //REG(Matrix) - REG(Quaternion) - REG(Rectangle) - REG(Ray) - REG(RayHitInfo) - REG(Camera) - REG(Camera2D) - REG(BoundingBox) - //REG(Material) - - // Register functions - //-------------------- - REG(InitWindow) - REG(CloseWindow) - REG(IsWindowReady) - REG(WindowShouldClose) - REG(IsWindowMinimized) - REG(ToggleFullscreen) - REG(SetWindowIcon) - REG(SetWindowTitle) - REG(SetWindowPosition) - REG(SetWindowMonitor) - REG(SetWindowMinSize) - REG(SetWindowSize) - REG(GetScreenWidth) - REG(GetScreenHeight) - REG(ShowCursor) - REG(HideCursor) - REG(IsCursorHidden) - REG(EnableCursor) - REG(DisableCursor) - REG(ClearBackground) - REG(BeginDrawing) - REG(EndDrawing) - REG(BeginMode2D) - REG(EndMode2D) - REG(BeginMode3D) - REG(EndMode3D) - REG(BeginTextureMode) - REG(EndTextureMode) - REG(GetMouseRay) - REG(GetWorldToScreen) - REG(GetCameraMatrix) - REG(SetTargetFPS) - REG(GetFPS) - REG(GetFrameTime) - REG(GetTime) - REG(ColorToInt) - REG(ColorNormalize) - REG(ColorToHSV) - REG(GetColor) - REG(Fade) - REG(ShowLogo) - REG(SetConfigFlags) - REG(SetTraceLog) - REG(TraceLog) - REG(TakeScreenshot) - REG(GetRandomValue) - REG(IsFileExtension) - REG(GetExtension) - REG(GetFileName) - REG(GetDirectoryPath) - REG(GetWorkingDirectory) - REG(ChangeDirectory) - REG(IsFileDropped) - REG(GetDroppedFiles) - REG(ClearDroppedFiles) - REG(StorageSaveValue) - REG(StorageLoadValue) - REG(IsKeyPressed) - REG(IsKeyDown) - REG(IsKeyReleased) - REG(IsKeyUp) - REG(GetKeyPressed) - REG(SetExitKey) - REG(IsGamepadAvailable) - REG(IsGamepadName) - REG(GetGamepadName) - REG(IsGamepadButtonPressed) - REG(IsGamepadButtonDown) - REG(IsGamepadButtonReleased) - REG(IsGamepadButtonUp) - REG(GetGamepadButtonPressed) - REG(GetGamepadAxisCount) - REG(GetGamepadAxisMovement) - REG(IsMouseButtonPressed) - REG(IsMouseButtonDown) - REG(IsMouseButtonReleased) - REG(IsMouseButtonUp) - REG(GetMouseX) - REG(GetMouseY) - REG(GetMousePosition) - REG(SetMousePosition) - REG(SetMouseScale) - REG(GetMouseWheelMove) - REG(GetTouchX) - REG(GetTouchY) - REG(GetTouchPosition) - REG(SetGesturesEnabled) - REG(IsGestureDetected) - REG(GetGestureDetected) - REG(GetTouchPointsCount) - REG(GetGestureHoldDuration) - REG(GetGestureDragVector) - REG(GetGestureDragAngle) - REG(GetGesturePinchVector) - REG(GetGesturePinchAngle) - REG(SetCameraMode) - REG(UpdateCamera) - REG(SetCameraPanControl) - REG(SetCameraAltControl) - REG(SetCameraSmoothZoomControl) - REG(SetCameraMoveControls) - REG(DrawPixel) - REG(DrawPixelV) - REG(DrawLine) - REG(DrawLineV) - REG(DrawLineEx) - REG(DrawLineBezier) - REG(DrawCircle) - REG(DrawCircleGradient) - REG(DrawCircleV) - REG(DrawCircleLines) - REG(DrawRectangle) - REG(DrawRectangleV) - REG(DrawRectangleRec) - REG(DrawRectanglePro) - REG(DrawRectangleGradientV) - REG(DrawRectangleGradientH) - REG(DrawRectangleGradientEx) - REG(DrawRectangleLines) - REG(DrawRectangleLinesEx) - REG(DrawTriangle) - REG(DrawTriangleLines) - REG(DrawPoly) - REG(DrawPolyEx) - REG(DrawPolyExLines) - REG(CheckCollisionRecs) - REG(CheckCollisionCircles) - REG(CheckCollisionCircleRec) - REG(GetCollisionRec) - REG(CheckCollisionPointRec) - REG(CheckCollisionPointCircle) - REG(CheckCollisionPointTriangle) - REG(LoadImage) - REG(LoadImageEx) - REG(LoadImagePro) - REG(LoadImageRaw) - REG(ExportImage) - REG(LoadTexture) - REG(LoadTextureFromImage) - REG(LoadRenderTexture) - REG(UnloadImage) - REG(UnloadTexture) - REG(UnloadRenderTexture) - REG(GetImageData) - REG(GetImageDataNormalized) - REG(GetPixelDataSize) - REG(GetTextureData) - REG(UpdateTexture) - REG(ImageCopy) - REG(ImageToPOT) - REG(ImageFormat) - REG(ImageAlphaMask) - REG(ImageAlphaClear) - REG(ImageAlphaCrop) - REG(ImageAlphaPremultiply) - REG(ImageCrop) - REG(ImageResize) - REG(ImageResizeNN) - REG(ImageResizeCanvas) - REG(ImageMipmaps) - REG(ImageDither) - REG(ImageText) - REG(ImageTextEx) - REG(ImageDraw) - REG(ImageDrawRectangle) - REG(ImageDrawText) - REG(ImageDrawTextEx) - REG(ImageFlipVertical) - REG(ImageFlipHorizontal) - REG(ImageRotateCW) - REG(ImageRotateCCW) - REG(ImageColorTint) - REG(ImageColorInvert) - REG(ImageColorGrayscale) - REG(ImageColorContrast) - REG(ImageColorBrightness) - REG(ImageColorReplace) - REG(GenImageColor) - REG(GenImageGradientV) - REG(GenImageGradientH) - REG(GenImageGradientRadial) - REG(GenImageChecked) - REG(GenImageWhiteNoise) - REG(GenImagePerlinNoise) - REG(GenImageCellular) - REG(GenTextureMipmaps) - REG(SetTextureFilter) - REG(SetTextureWrap) - REG(DrawTexture) - REG(DrawTextureV) - REG(DrawTextureEx) - REG(DrawTextureRec) - REG(DrawTexturePro) - REG(GetFontDefault) - REG(LoadFont) - REG(LoadFontEx) - REG(LoadFontData) - REG(GenImageFontAtlas) - REG(UnloadFont) - REG(DrawFPS) - REG(DrawText) - REG(DrawTextEx) - REG(MeasureText) - REG(MeasureTextEx) - REG(FormatText) - REG(SubText) - REG(GetGlyphIndex) - REG(DrawLine3D) - REG(DrawCircle3D) - REG(DrawCube) - REG(DrawCubeV) - REG(DrawCubeWires) - REG(DrawCubeTexture) - REG(DrawSphere) - REG(DrawSphereEx) - REG(DrawSphereWires) - REG(DrawCylinder) - REG(DrawCylinderWires) - REG(DrawPlane) - REG(DrawRay) - REG(DrawGrid) - REG(DrawGizmo) - REG(LoadModel) - REG(LoadModelFromMesh) - REG(UnloadModel) - REG(LoadMesh) - REG(UnloadMesh) - REG(ExportMesh) - REG(MeshBoundingBox) - REG(MeshTangents) - REG(MeshBinormals) - REG(GenMeshPlane) - REG(GenMeshCube) - REG(GenMeshSphere) - REG(GenMeshHemiSphere) - REG(GenMeshCylinder) - REG(GenMeshTorus) - REG(GenMeshKnot) - REG(GenMeshHeightmap) - REG(GenMeshCubicmap) - REG(LoadMaterial) - REG(LoadMaterialDefault) - REG(UnloadMaterial) - REG(DrawModel) - REG(DrawModelEx) - REG(DrawModelWires) - REG(DrawModelWiresEx) - REG(DrawBoundingBox) - REG(DrawBillboard) - REG(DrawBillboardRec) - REG(CheckCollisionSpheres) - REG(CheckCollisionBoxes) - REG(CheckCollisionBoxSphere) - REG(CheckCollisionRaySphere) - REG(CheckCollisionRaySphereEx) - REG(CheckCollisionRayBox) - REG(GetCollisionRayModel) - REG(GetCollisionRayTriangle) - REG(GetCollisionRayGround) - REG(LoadText) - REG(LoadShader) - REG(LoadShaderCode) - REG(UnloadShader) - REG(GetShaderDefault) - REG(GetTextureDefault) - REG(GetShaderLocation) - REG(SetShaderValue) - REG(SetShaderValuei) - REG(SetShaderValueMatrix) - REG(SetMatrixProjection) - REG(SetMatrixModelview) - REG(GetMatrixModelview) - REG(GenTextureCubemap) - REG(GenTextureIrradiance) - REG(GenTexturePrefilter) - REG(GenTextureBRDF) - REG(BeginShaderMode) - REG(EndShaderMode) - REG(BeginBlendMode) - REG(EndBlendMode) - REG(GetVrDeviceInfo) - REG(InitVrSimulator) - REG(CloseVrSimulator) - REG(IsVrSimulatorReady) - REG(SetVrDistortionShader) - REG(UpdateVrTracking) - REG(ToggleVrMode) - REG(BeginVrDrawing) - REG(EndVrDrawing) - REG(InitAudioDevice) - REG(CloseAudioDevice) - REG(IsAudioDeviceReady) - REG(SetMasterVolume) - REG(LoadWave) - REG(LoadWaveEx) - REG(LoadSound) - REG(LoadSoundFromWave) - REG(UpdateSound) - REG(UnloadWave) - REG(UnloadSound) - REG(PlaySound) - REG(PauseSound) - REG(ResumeSound) - REG(StopSound) - REG(IsSoundPlaying) - REG(SetSoundVolume) - REG(SetSoundPitch) - REG(WaveFormat) - REG(WaveCopy) - REG(WaveCrop) - REG(GetWaveData) - REG(LoadMusicStream) - REG(UnloadMusicStream) - REG(PlayMusicStream) - REG(UpdateMusicStream) - REG(StopMusicStream) - REG(PauseMusicStream) - REG(ResumeMusicStream) - REG(IsMusicPlaying) - REG(SetMusicVolume) - REG(SetMusicPitch) - REG(SetMusicLoopCount) - REG(GetMusicTimeLength) - REG(GetMusicTimePlayed) - REG(InitAudioStream) - REG(UpdateAudioStream) - REG(CloseAudioStream) - REG(IsAudioBufferProcessed) - REG(PlayAudioStream) - REG(PauseAudioStream) - REG(ResumeAudioStream) - REG(IsAudioStreamPlaying) - REG(StopAudioStream) - REG(SetAudioStreamVolume) - REG(SetAudioStreamPitch) - - - // [raymath] module functions - general - REG(Clamp) - - // [raymath] module functions - Vector2 - REG(Vector2Zero) - REG(Vector2One) - REG(Vector2Add) - REG(Vector2Subtract) - REG(Vector2Lenght) - REG(Vector2DotProduct) - REG(Vector2Distance) - REG(Vector2Angle) - REG(Vector2Scale) - REG(Vector2Negate) - REG(Vector2Divide) - REG(Vector2Normalize) - - // [raymath] module functions - Vector3 - REG(VectorZero) - REG(VectorOne) - REG(VectorAdd) - REG(VectorSubtract) - REG(VectorCrossProduct) - REG(VectorPerpendicular) - REG(VectorLength) - REG(VectorDotProduct) - REG(VectorDistance) - REG(VectorScale) - REG(VectorNegate) - REG(VectorNormalize) - REG(VectorTransform) - REG(VectorLerp) - REG(VectorReflect) - - // [raymath] module functions - Matrix - REG(MatrixDeterminant) - REG(MatrixTrace) - REG(MatrixTranspose) - REG(MatrixInvert) - REG(MatrixNormalize) - REG(MatrixIdentity) - REG(MatrixAdd) - REG(MatrixSubstract) - REG(MatrixTranslate) - REG(MatrixRotate) - REG(MatrixRotateX) - REG(MatrixRotateY) - REG(MatrixRotateZ) - REG(MatrixScale) - REG(MatrixMultiply) - REG(MatrixFrustum) - REG(MatrixPerspective) - REG(MatrixOrtho) - REG(MatrixLookAt) - - // [raymath] module functions - Quaternion - REG(QuaternionLength) - REG(QuaternionNormalize) - REG(QuaternionMultiply) - REG(QuaternionSlerp) - REG(QuaternionFromMatrix) - REG(QuaternionToMatrix) - REG(QuaternionFromAxisAngle) - REG(QuaternionToAxisAngle) - REG(QuaternionFromEuler) - REG(QuaternionToEuler) - REG(QuaternionTransform) - - // [physac] module functions - REG(InitPhysics) - REG(IsPhysicsEnabled) - REG(SetPhysicsGravity) - REG(CreatePhysicsBodyCircle) - REG(CreatePhysicsBodyRectangle) - REG(CreatePhysicsBodyPolygon) - REG(PhysicsAddForce) - REG(PhysicsAddTorque) - REG(PhysicsShatter) - REG(GetPhysicsBodiesCount) - REG(GetPhysicsBody) - REG(GetPhysicsShapeType) - REG(GetPhysicsShapeVerticesCount) - REG(GetPhysicsShapeVertex) - REG(SetPhysicsBodyRotation) - REG(DestroyPhysicsBody) - REG(ResetPhysics) - REG(ClosePhysics) - - { NULL, NULL } // sentinel: end signal -}; +// --- Registries --- -// Register raylib Lua functionality -static void rLuaRegisterFunctions(const char *opt_table) +static void rLuaRegisterMetatables(lua_State *L) { - if (opt_table) lua_createtable(L, 0, sizeof(raylib_functions)/sizeof(raylib_functions[0])); - else lua_pushglobaltable(L); + luaL_newmetatable(L, "AudioStream"); + lua_pushcfunction(L, rl_AudioStream_index); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, rl_AudioStream_gc); + lua_setfield(L, -2, "__gc"); + lua_pop(L, 1); - luaL_setfuncs(L, raylib_functions, 0); -} + luaL_newmetatable(L, "Font"); + lua_pushcfunction(L, rl_Font_index); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, rl_Font_gc); + lua_setfield(L, -2, "__gc"); + lua_pop(L, 1); -//---------------------------------------------------------------------------------- -// raylib Lua API -//---------------------------------------------------------------------------------- - -// Initialize Lua system -RLUADEF void rLuaInitDevice(void) -{ - mainLuaState = luaL_newstate(); - L = mainLuaState; - - LuaStartEnum(); - LuaSetEnum("SHOW_LOGO", 1); - LuaSetEnum("FULLSCREEN_MODE", 2); - LuaSetEnum("WINDOW_RESIZABLE", 4); - LuaSetEnum("WINDOW_DECORATED", 8); - LuaSetEnum("WINDOW_TRANSPARENT", 16); - LuaSetEnum("MSAA_4X_HINT", 32); - LuaSetEnum("VSYNC_HINT", 64); - LuaEndEnum("FLAG"); - - LuaStartEnum(); - LuaSetEnum("SPACE", 32); - LuaSetEnum("ESCAPE", 256); - LuaSetEnum("ENTER", 257); - LuaSetEnum("BACKSPACE", 259); - LuaSetEnum("RIGHT", 262); - LuaSetEnum("LEFT", 263); - LuaSetEnum("DOWN", 264); - LuaSetEnum("UP", 265); - LuaSetEnum("F1", 290); - LuaSetEnum("F2", 291); - LuaSetEnum("F3", 292); - LuaSetEnum("F4", 293); - LuaSetEnum("F5", 294); - LuaSetEnum("F6", 295); - LuaSetEnum("F7", 296); - LuaSetEnum("F8", 297); - LuaSetEnum("F9", 298); - LuaSetEnum("F10", 299); - LuaSetEnum("LEFT_SHIFT", 340); - LuaSetEnum("LEFT_CONTROL", 341); - LuaSetEnum("LEFT_ALT", 342); - LuaSetEnum("RIGHT_SHIFT", 344); - LuaSetEnum("RIGHT_CONTROL", 345); - LuaSetEnum("RIGHT_ALT", 346); - LuaSetEnum("ZERO", 48); - LuaSetEnum("ONE", 49); - LuaSetEnum("TWO", 50); - LuaSetEnum("THREE", 51); - LuaSetEnum("FOUR", 52); - LuaSetEnum("FIVE", 53); - LuaSetEnum("SIX", 54); - LuaSetEnum("SEVEN", 55); - LuaSetEnum("EIGHT", 56); - LuaSetEnum("NINE", 57); - LuaSetEnum("A", 65); - LuaSetEnum("B", 66); - LuaSetEnum("C", 67); - LuaSetEnum("D", 68); - LuaSetEnum("E", 69); - LuaSetEnum("F", 70); - LuaSetEnum("G", 71); - LuaSetEnum("H", 72); - LuaSetEnum("I", 73); - LuaSetEnum("J", 74); - LuaSetEnum("K", 75); - LuaSetEnum("L", 76); - LuaSetEnum("M", 77); - LuaSetEnum("N", 78); - LuaSetEnum("O", 79); - LuaSetEnum("P", 80); - LuaSetEnum("Q", 81); - LuaSetEnum("R", 82); - LuaSetEnum("S", 83); - LuaSetEnum("T", 84); - LuaSetEnum("U", 85); - LuaSetEnum("V", 86); - LuaSetEnum("W", 87); - LuaSetEnum("X", 88); - LuaSetEnum("Y", 89); - LuaSetEnum("Z", 90); - LuaEndEnum("KEY"); - - LuaStartEnum(); - LuaSetEnum("LEFT_BUTTON", 0); - LuaSetEnum("RIGHT_BUTTON", 1); - LuaSetEnum("MIDDLE_BUTTON", 2); - LuaEndEnum("MOUSE"); - - LuaStartEnum(); - LuaSetEnum("PLAYER1", 0); - LuaSetEnum("PLAYER2", 1); - LuaSetEnum("PLAYER3", 2); - LuaSetEnum("PLAYER4", 3); - - LuaSetEnum("PS3_BUTTON_TRIANGLE", 0); - LuaSetEnum("PS3_BUTTON_CIRCLE", 1); - LuaSetEnum("PS3_BUTTON_CROSS", 2); - LuaSetEnum("PS3_BUTTON_SQUARE", 3); - LuaSetEnum("PS3_BUTTON_L1", 6); - LuaSetEnum("PS3_BUTTON_R1", 7); - LuaSetEnum("PS3_BUTTON_L2", 4); - LuaSetEnum("PS3_BUTTON_R2", 5); - LuaSetEnum("PS3_BUTTON_START", 8); - LuaSetEnum("PS3_BUTTON_SELECT", 9); - LuaSetEnum("PS3_BUTTON_UP", 24); - LuaSetEnum("PS3_BUTTON_RIGHT", 25); - LuaSetEnum("PS3_BUTTON_DOWN", 26); - LuaSetEnum("PS3_BUTTON_LEFT", 27); - LuaSetEnum("PS3_BUTTON_PS", 12); - LuaSetEnum("PS3_AXIS_LEFT_X", 0); - LuaSetEnum("PS3_AXIS_LEFT_Y", 1); - LuaSetEnum("PS3_AXIS_RIGHT_X", 2); - LuaSetEnum("PS3_AXIS_RIGHT_Y", 5); - LuaSetEnum("PS3_AXIS_L2", 3); // [1..-1] (pressure-level) - LuaSetEnum("PS3_AXIS_R2", 4); // [1..-1] (pressure-level) - -// Xbox360 USB Controller Buttons - LuaSetEnum("XBOX_BUTTON_A", 0); - LuaSetEnum("XBOX_BUTTON_B", 1); - LuaSetEnum("XBOX_BUTTON_X", 2); - LuaSetEnum("XBOX_BUTTON_Y", 3); - LuaSetEnum("XBOX_BUTTON_LB", 4); - LuaSetEnum("XBOX_BUTTON_RB", 5); - LuaSetEnum("XBOX_BUTTON_SELECT", 6); - LuaSetEnum("XBOX_BUTTON_START", 7); - LuaSetEnum("XBOX_BUTTON_UP", 10); - LuaSetEnum("XBOX_BUTTON_RIGHT", 11); - LuaSetEnum("XBOX_BUTTON_DOWN", 12); - LuaSetEnum("XBOX_BUTTON_LEFT", 13); - LuaSetEnum("XBOX_BUTTON_HOME", 8); -#if defined(PLATFORM_RPI) - LuaSetEnum("XBOX_AXIS_LEFT_X", 0); // [-1..1] (left->right) - LuaSetEnum("XBOX_AXIS_LEFT_Y", 1); // [-1..1] (up->down) - LuaSetEnum("XBOX_AXIS_RIGHT_X", 3); // [-1..1] (left->right) - LuaSetEnum("XBOX_AXIS_RIGHT_Y", 4); // [-1..1] (up->down) - LuaSetEnum("XBOX_AXIS_LT", 2); // [-1..1] (pressure-level) - LuaSetEnum("XBOX_AXIS_RT", 5); // [-1..1] (pressure-level) -#else - LuaSetEnum("XBOX_AXIS_LEFT_X", 0); // [-1..1] (left->right) - LuaSetEnum("XBOX_AXIS_LEFT_Y", 1); // [1..-1] (up->down) - LuaSetEnum("XBOX_AXIS_RIGHT_X", 2); // [-1..1] (left->right) - LuaSetEnum("XBOX_AXIS_RIGHT_Y", 3); // [1..-1] (up->down) - LuaSetEnum("XBOX_AXIS_LT", 4); // [-1..1] (pressure-level) - LuaSetEnum("XBOX_AXIS_RT", 5); // [-1..1] (pressure-level) -#endif - LuaEndEnum("GAMEPAD"); + luaL_newmetatable(L, "Image"); + lua_pushcfunction(L, rl_Image_index); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, rl_Image_gc); + lua_setfield(L, -2, "__gc"); + lua_pop(L, 1); - lua_pushglobaltable(L); - LuaSetEnumColor("LIGHTGRAY", LIGHTGRAY); - LuaSetEnumColor("GRAY", GRAY); - LuaSetEnumColor("DARKGRAY", DARKGRAY); - LuaSetEnumColor("YELLOW", YELLOW); - LuaSetEnumColor("GOLD", GOLD); - LuaSetEnumColor("ORANGE", ORANGE); - LuaSetEnumColor("PINK", PINK); - LuaSetEnumColor("RED", RED); - LuaSetEnumColor("MAROON", MAROON); - LuaSetEnumColor("GREEN", GREEN); - LuaSetEnumColor("LIME", LIME); - LuaSetEnumColor("DARKGREEN", DARKGREEN); - LuaSetEnumColor("SKYBLUE", SKYBLUE); - LuaSetEnumColor("BLUE", BLUE); - LuaSetEnumColor("DARKBLUE", DARKBLUE); - LuaSetEnumColor("PURPLE", PURPLE); - LuaSetEnumColor("VIOLET", VIOLET); - LuaSetEnumColor("DARKPURPLE", DARKPURPLE); - LuaSetEnumColor("BEIGE", BEIGE); - LuaSetEnumColor("BROWN", BROWN); - LuaSetEnumColor("DARKBROWN", DARKBROWN); - LuaSetEnumColor("WHITE", WHITE); - LuaSetEnumColor("BLACK", BLACK); - LuaSetEnumColor("BLANK", BLANK); - LuaSetEnumColor("MAGENTA", MAGENTA); - LuaSetEnumColor("RAYWHITE", RAYWHITE); + luaL_newmetatable(L, "Material"); + lua_pushcfunction(L, rl_Material_index); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, rl_Material_gc); + lua_setfield(L, -2, "__gc"); lua_pop(L, 1); - LuaStartEnum(); - LuaSetEnum("UNCOMPRESSED_GRAYSCALE", UNCOMPRESSED_GRAYSCALE); - LuaSetEnum("UNCOMPRESSED_GRAY_ALPHA", UNCOMPRESSED_GRAY_ALPHA); - LuaSetEnum("UNCOMPRESSED_R5G6B5", UNCOMPRESSED_R5G6B5); - LuaSetEnum("UNCOMPRESSED_R8G8B8", UNCOMPRESSED_R8G8B8); - LuaSetEnum("UNCOMPRESSED_R5G5B5A1", UNCOMPRESSED_R5G5B5A1); - LuaSetEnum("UNCOMPRESSED_R4G4B4A4", UNCOMPRESSED_R4G4B4A4); - LuaSetEnum("UNCOMPRESSED_R8G8B8A8", UNCOMPRESSED_R8G8B8A8); - LuaSetEnum("COMPRESSED_DXT1_RGB", COMPRESSED_DXT1_RGB); - LuaSetEnum("COMPRESSED_DXT1_RGBA", COMPRESSED_DXT1_RGBA); - LuaSetEnum("COMPRESSED_DXT3_RGBA", COMPRESSED_DXT3_RGBA); - LuaSetEnum("COMPRESSED_DXT5_RGBA", COMPRESSED_DXT5_RGBA); - LuaSetEnum("COMPRESSED_ETC1_RGB", COMPRESSED_ETC1_RGB); - LuaSetEnum("COMPRESSED_ETC2_RGB", COMPRESSED_ETC2_RGB); - LuaSetEnum("COMPRESSED_ETC2_EAC_RGBA", COMPRESSED_ETC2_EAC_RGBA); - LuaSetEnum("COMPRESSED_PVRT_RGB", COMPRESSED_PVRT_RGB); - LuaSetEnum("COMPRESSED_PVRT_RGBA", COMPRESSED_PVRT_RGBA); - LuaSetEnum("COMPRESSED_ASTC_4x4_RGBA", COMPRESSED_ASTC_4x4_RGBA); - LuaSetEnum("COMPRESSED_ASTC_8x8_RGBA", COMPRESSED_ASTC_8x8_RGBA); - LuaEndEnum("TextureFormat"); - - LuaStartEnum(); - LuaSetEnum("ALPHA", BLEND_ALPHA); - LuaSetEnum("ADDITIVE", BLEND_ADDITIVE); - LuaSetEnum("MULTIPLIED", BLEND_MULTIPLIED); - LuaEndEnum("BlendMode"); - - LuaStartEnum(); - LuaSetEnum("POINT", FILTER_POINT); - LuaSetEnum("BILINEAR", FILTER_BILINEAR); - LuaSetEnum("TRILINEAR", FILTER_TRILINEAR); - LuaSetEnum("ANISOTROPIC_4X", FILTER_ANISOTROPIC_4X); - LuaSetEnum("ANISOTROPIC_8X", FILTER_ANISOTROPIC_8X); - LuaSetEnum("ANISOTROPIC_16X", FILTER_ANISOTROPIC_16X); - LuaEndEnum("TextureFilter"); - - LuaStartEnum(); - LuaSetEnum("NONE", GESTURE_NONE); - LuaSetEnum("TAP", GESTURE_TAP); - LuaSetEnum("DOUBLETAP", GESTURE_DOUBLETAP); - LuaSetEnum("HOLD", GESTURE_HOLD); - LuaSetEnum("DRAG", GESTURE_DRAG); - LuaSetEnum("SWIPE_RIGHT", GESTURE_SWIPE_RIGHT); - LuaSetEnum("SWIPE_LEFT", GESTURE_SWIPE_LEFT); - LuaSetEnum("SWIPE_UP", GESTURE_SWIPE_UP); - LuaSetEnum("SWIPE_DOWN", GESTURE_SWIPE_DOWN); - LuaSetEnum("PINCH_IN", GESTURE_PINCH_IN); - LuaSetEnum("PINCH_OUT", GESTURE_PINCH_OUT); - LuaEndEnum("Gestures"); - - LuaStartEnum(); - LuaSetEnum("CUSTOM", CAMERA_CUSTOM); - LuaSetEnum("FREE", CAMERA_FREE); - LuaSetEnum("ORBITAL", CAMERA_ORBITAL); - LuaSetEnum("FIRST_PERSON", CAMERA_FIRST_PERSON); - LuaSetEnum("THIRD_PERSON", CAMERA_THIRD_PERSON); - LuaEndEnum("CameraMode"); - - LuaStartEnum(); - LuaSetEnum("DEFAULT_DEVICE", HMD_DEFAULT_DEVICE); - LuaSetEnum("OCULUS_RIFT_DK2", HMD_OCULUS_RIFT_DK2); - LuaSetEnum("OCULUS_RIFT_CV1", HMD_OCULUS_RIFT_CV1); - LuaSetEnum("VALVE_HTC_VIVE", HMD_VALVE_HTC_VIVE); - LuaSetEnum("SAMSUNG_GEAR_VR", HMD_SAMSUNG_GEAR_VR); - LuaSetEnum("GOOGLE_CARDBOARD", HMD_GOOGLE_CARDBOARD); - LuaSetEnum("SONY_PLAYSTATION_VR", HMD_SONY_PLAYSTATION_VR); - LuaSetEnum("RAZER_OSVR", HMD_RAZER_OSVR); - LuaSetEnum("FOVE_VR", HMD_FOVE_VR); - LuaEndEnum("VrDevice"); + luaL_newmetatable(L, "Mesh"); + lua_pushcfunction(L, rl_Mesh_index); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, rl_Mesh_gc); + lua_setfield(L, -2, "__gc"); + lua_pop(L, 1); - lua_pushglobaltable(L); - LuaSetEnum("INFO", INFO); - LuaSetEnum("ERROR", ERROR); - LuaSetEnum("WARNING", WARNING); - LuaSetEnum("DEBUG", DEBUG); - LuaSetEnum("OTHER", OTHER); + luaL_newmetatable(L, "Model"); + lua_pushcfunction(L, rl_Model_index); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, rl_Model_gc); + lua_setfield(L, -2, "__gc"); lua_pop(L, 1); - LuaPush_bool(L, true); -#if defined(PLATFORM_DESKTOP) - lua_setglobal(L, "PLATFORM_DESKTOP"); -#elif defined(PLATFORM_ANDROID) - lua_setglobal(L, "PLATFORM_ANDROID"); -#elif defined(PLATFORM_RPI) - lua_setglobal(L, "PLATFORM_RPI"); -#elif defined(PLATFORM_WEB) - lua_setglobal(L, "PLATFORM_WEB"); -#endif + luaL_newmetatable(L, "ModelAnimation"); + lua_pushcfunction(L, rl_ModelAnimation_index); + lua_setfield(L, -2, "__index"); + lua_pop(L, 1); - luaL_openlibs(L); - LuaBuildOpaqueMetatables(); + luaL_newmetatable(L, "Music"); + lua_pushcfunction(L, rl_Music_index); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, rl_Music_gc); + lua_setfield(L, -2, "__gc"); + lua_pop(L, 1); - rLuaRegisterFunctions(0); // Register Lua raylib functions -} + luaL_newmetatable(L, "RenderTexture"); + lua_pushcfunction(L, rl_RenderTexture_index); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, rl_RenderTexture_gc); + lua_setfield(L, -2, "__gc"); + lua_pop(L, 1); -// De-initialize Lua system -RLUADEF void rLuaCloseDevice(void) -{ - if (mainLuaState) - { - lua_close(mainLuaState); - mainLuaState = 0; - L = 0; - } -} + luaL_newmetatable(L, "RenderTexture2D"); + lua_pushcfunction(L, rl_RenderTexture2D_gc); + lua_setfield(L, -2, "__gc"); + lua_pop(L, 1); -// Execute raylib Lua code -RLUADEF void rLuaExecuteCode(const char *code) -{ - if (!mainLuaState) - { - TraceLog(WARNING, "Lua device not initialized"); - return; - } + luaL_newmetatable(L, "Shader"); + lua_pushcfunction(L, rl_Shader_index); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, rl_Shader_gc); + lua_setfield(L, -2, "__gc"); + lua_pop(L, 1); + + luaL_newmetatable(L, "Sound"); + lua_pushcfunction(L, rl_Sound_index); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, rl_Sound_gc); + lua_setfield(L, -2, "__gc"); + lua_pop(L, 1); - int result = luaL_dostring(L, code); + luaL_newmetatable(L, "Texture"); + lua_pushcfunction(L, rl_Texture_index); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, rl_Texture_gc); + lua_setfield(L, -2, "__gc"); + lua_pop(L, 1); + + luaL_newmetatable(L, "Texture2D"); + lua_pushcfunction(L, rl_Texture2D_gc); + lua_setfield(L, -2, "__gc"); + lua_pop(L, 1); + + luaL_newmetatable(L, "TextureCubemap"); + lua_pushcfunction(L, rl_TextureCubemap_gc); + lua_setfield(L, -2, "__gc"); + lua_pop(L, 1); + + luaL_newmetatable(L, "Wave"); + lua_pushcfunction(L, rl_Wave_index); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, rl_Wave_gc); + lua_setfield(L, -2, "__gc"); + lua_pop(L, 1); - switch (result) - { - case LUA_OK: break; - case LUA_ERRRUN: TraceLog(ERROR, "Lua Runtime Error: %s", lua_tostring(L, -1)); break; - case LUA_ERRMEM: TraceLog(ERROR, "Lua Memory Error: %s", lua_tostring(L, -1)); break; - default: TraceLog(ERROR, "Lua Error: %s", lua_tostring(L, -1)); break; - } } +static void rLuaRegisterConstants(lua_State *L) +{ + lua_pushinteger(L, 64); + lua_setfield(L, -2, "FLAG_VSYNC_HINT"); + lua_pushinteger(L, 2); + lua_setfield(L, -2, "FLAG_FULLSCREEN_MODE"); + lua_pushinteger(L, 4); + lua_setfield(L, -2, "FLAG_WINDOW_RESIZABLE"); + lua_pushinteger(L, 8); + lua_setfield(L, -2, "FLAG_WINDOW_UNDECORATED"); + lua_pushinteger(L, 128); + lua_setfield(L, -2, "FLAG_WINDOW_HIDDEN"); + lua_pushinteger(L, 512); + lua_setfield(L, -2, "FLAG_WINDOW_MINIMIZED"); + lua_pushinteger(L, 1024); + lua_setfield(L, -2, "FLAG_WINDOW_MAXIMIZED"); + lua_pushinteger(L, 2048); + lua_setfield(L, -2, "FLAG_WINDOW_UNFOCUSED"); + lua_pushinteger(L, 4096); + lua_setfield(L, -2, "FLAG_WINDOW_TOPMOST"); + lua_pushinteger(L, 256); + lua_setfield(L, -2, "FLAG_WINDOW_ALWAYS_RUN"); + lua_pushinteger(L, 16); + lua_setfield(L, -2, "FLAG_WINDOW_TRANSPARENT"); + lua_pushinteger(L, 8192); + lua_setfield(L, -2, "FLAG_WINDOW_HIGHDPI"); + lua_pushinteger(L, 16384); + lua_setfield(L, -2, "FLAG_WINDOW_MOUSE_PASSTHROUGH"); + lua_pushinteger(L, 32768); + lua_setfield(L, -2, "FLAG_BORDERLESS_WINDOWED_MODE"); + lua_pushinteger(L, 32); + lua_setfield(L, -2, "FLAG_MSAA_4X_HINT"); + lua_pushinteger(L, 65536); + lua_setfield(L, -2, "FLAG_INTERLACED_HINT"); + lua_pushinteger(L, 0); + lua_setfield(L, -2, "LOG_ALL"); + lua_pushinteger(L, 1); + lua_setfield(L, -2, "LOG_TRACE"); + lua_pushinteger(L, 2); + lua_setfield(L, -2, "LOG_DEBUG"); + lua_pushinteger(L, 3); + lua_setfield(L, -2, "LOG_INFO"); + lua_pushinteger(L, 4); + lua_setfield(L, -2, "LOG_WARNING"); + lua_pushinteger(L, 5); + lua_setfield(L, -2, "LOG_ERROR"); + lua_pushinteger(L, 6); + lua_setfield(L, -2, "LOG_FATAL"); + lua_pushinteger(L, 7); + lua_setfield(L, -2, "LOG_NONE"); + lua_pushinteger(L, 0); + lua_setfield(L, -2, "KEY_NULL"); + lua_pushinteger(L, 39); + lua_setfield(L, -2, "KEY_APOSTROPHE"); + lua_pushinteger(L, 44); + lua_setfield(L, -2, "KEY_COMMA"); + lua_pushinteger(L, 45); + lua_setfield(L, -2, "KEY_MINUS"); + lua_pushinteger(L, 46); + lua_setfield(L, -2, "KEY_PERIOD"); + lua_pushinteger(L, 47); + lua_setfield(L, -2, "KEY_SLASH"); + lua_pushinteger(L, 48); + lua_setfield(L, -2, "KEY_ZERO"); + lua_pushinteger(L, 49); + lua_setfield(L, -2, "KEY_ONE"); + lua_pushinteger(L, 50); + lua_setfield(L, -2, "KEY_TWO"); + lua_pushinteger(L, 51); + lua_setfield(L, -2, "KEY_THREE"); + lua_pushinteger(L, 52); + lua_setfield(L, -2, "KEY_FOUR"); + lua_pushinteger(L, 53); + lua_setfield(L, -2, "KEY_FIVE"); + lua_pushinteger(L, 54); + lua_setfield(L, -2, "KEY_SIX"); + lua_pushinteger(L, 55); + lua_setfield(L, -2, "KEY_SEVEN"); + lua_pushinteger(L, 56); + lua_setfield(L, -2, "KEY_EIGHT"); + lua_pushinteger(L, 57); + lua_setfield(L, -2, "KEY_NINE"); + lua_pushinteger(L, 59); + lua_setfield(L, -2, "KEY_SEMICOLON"); + lua_pushinteger(L, 61); + lua_setfield(L, -2, "KEY_EQUAL"); + lua_pushinteger(L, 65); + lua_setfield(L, -2, "KEY_A"); + lua_pushinteger(L, 66); + lua_setfield(L, -2, "KEY_B"); + lua_pushinteger(L, 67); + lua_setfield(L, -2, "KEY_C"); + lua_pushinteger(L, 68); + lua_setfield(L, -2, "KEY_D"); + lua_pushinteger(L, 69); + lua_setfield(L, -2, "KEY_E"); + lua_pushinteger(L, 70); + lua_setfield(L, -2, "KEY_F"); + lua_pushinteger(L, 71); + lua_setfield(L, -2, "KEY_G"); + lua_pushinteger(L, 72); + lua_setfield(L, -2, "KEY_H"); + lua_pushinteger(L, 73); + lua_setfield(L, -2, "KEY_I"); + lua_pushinteger(L, 74); + lua_setfield(L, -2, "KEY_J"); + lua_pushinteger(L, 75); + lua_setfield(L, -2, "KEY_K"); + lua_pushinteger(L, 76); + lua_setfield(L, -2, "KEY_L"); + lua_pushinteger(L, 77); + lua_setfield(L, -2, "KEY_M"); + lua_pushinteger(L, 78); + lua_setfield(L, -2, "KEY_N"); + lua_pushinteger(L, 79); + lua_setfield(L, -2, "KEY_O"); + lua_pushinteger(L, 80); + lua_setfield(L, -2, "KEY_P"); + lua_pushinteger(L, 81); + lua_setfield(L, -2, "KEY_Q"); + lua_pushinteger(L, 82); + lua_setfield(L, -2, "KEY_R"); + lua_pushinteger(L, 83); + lua_setfield(L, -2, "KEY_S"); + lua_pushinteger(L, 84); + lua_setfield(L, -2, "KEY_T"); + lua_pushinteger(L, 85); + lua_setfield(L, -2, "KEY_U"); + lua_pushinteger(L, 86); + lua_setfield(L, -2, "KEY_V"); + lua_pushinteger(L, 87); + lua_setfield(L, -2, "KEY_W"); + lua_pushinteger(L, 88); + lua_setfield(L, -2, "KEY_X"); + lua_pushinteger(L, 89); + lua_setfield(L, -2, "KEY_Y"); + lua_pushinteger(L, 90); + lua_setfield(L, -2, "KEY_Z"); + lua_pushinteger(L, 91); + lua_setfield(L, -2, "KEY_LEFT_BRACKET"); + lua_pushinteger(L, 92); + lua_setfield(L, -2, "KEY_BACKSLASH"); + lua_pushinteger(L, 93); + lua_setfield(L, -2, "KEY_RIGHT_BRACKET"); + lua_pushinteger(L, 96); + lua_setfield(L, -2, "KEY_GRAVE"); + lua_pushinteger(L, 32); + lua_setfield(L, -2, "KEY_SPACE"); + lua_pushinteger(L, 256); + lua_setfield(L, -2, "KEY_ESCAPE"); + lua_pushinteger(L, 257); + lua_setfield(L, -2, "KEY_ENTER"); + lua_pushinteger(L, 258); + lua_setfield(L, -2, "KEY_TAB"); + lua_pushinteger(L, 259); + lua_setfield(L, -2, "KEY_BACKSPACE"); + lua_pushinteger(L, 260); + lua_setfield(L, -2, "KEY_INSERT"); + lua_pushinteger(L, 261); + lua_setfield(L, -2, "KEY_DELETE"); + lua_pushinteger(L, 262); + lua_setfield(L, -2, "KEY_RIGHT"); + lua_pushinteger(L, 263); + lua_setfield(L, -2, "KEY_LEFT"); + lua_pushinteger(L, 264); + lua_setfield(L, -2, "KEY_DOWN"); + lua_pushinteger(L, 265); + lua_setfield(L, -2, "KEY_UP"); + lua_pushinteger(L, 266); + lua_setfield(L, -2, "KEY_PAGE_UP"); + lua_pushinteger(L, 267); + lua_setfield(L, -2, "KEY_PAGE_DOWN"); + lua_pushinteger(L, 268); + lua_setfield(L, -2, "KEY_HOME"); + lua_pushinteger(L, 269); + lua_setfield(L, -2, "KEY_END"); + lua_pushinteger(L, 280); + lua_setfield(L, -2, "KEY_CAPS_LOCK"); + lua_pushinteger(L, 281); + lua_setfield(L, -2, "KEY_SCROLL_LOCK"); + lua_pushinteger(L, 282); + lua_setfield(L, -2, "KEY_NUM_LOCK"); + lua_pushinteger(L, 283); + lua_setfield(L, -2, "KEY_PRINT_SCREEN"); + lua_pushinteger(L, 284); + lua_setfield(L, -2, "KEY_PAUSE"); + lua_pushinteger(L, 290); + lua_setfield(L, -2, "KEY_F1"); + lua_pushinteger(L, 291); + lua_setfield(L, -2, "KEY_F2"); + lua_pushinteger(L, 292); + lua_setfield(L, -2, "KEY_F3"); + lua_pushinteger(L, 293); + lua_setfield(L, -2, "KEY_F4"); + lua_pushinteger(L, 294); + lua_setfield(L, -2, "KEY_F5"); + lua_pushinteger(L, 295); + lua_setfield(L, -2, "KEY_F6"); + lua_pushinteger(L, 296); + lua_setfield(L, -2, "KEY_F7"); + lua_pushinteger(L, 297); + lua_setfield(L, -2, "KEY_F8"); + lua_pushinteger(L, 298); + lua_setfield(L, -2, "KEY_F9"); + lua_pushinteger(L, 299); + lua_setfield(L, -2, "KEY_F10"); + lua_pushinteger(L, 300); + lua_setfield(L, -2, "KEY_F11"); + lua_pushinteger(L, 301); + lua_setfield(L, -2, "KEY_F12"); + lua_pushinteger(L, 340); + lua_setfield(L, -2, "KEY_LEFT_SHIFT"); + lua_pushinteger(L, 341); + lua_setfield(L, -2, "KEY_LEFT_CONTROL"); + lua_pushinteger(L, 342); + lua_setfield(L, -2, "KEY_LEFT_ALT"); + lua_pushinteger(L, 343); + lua_setfield(L, -2, "KEY_LEFT_SUPER"); + lua_pushinteger(L, 344); + lua_setfield(L, -2, "KEY_RIGHT_SHIFT"); + lua_pushinteger(L, 345); + lua_setfield(L, -2, "KEY_RIGHT_CONTROL"); + lua_pushinteger(L, 346); + lua_setfield(L, -2, "KEY_RIGHT_ALT"); + lua_pushinteger(L, 347); + lua_setfield(L, -2, "KEY_RIGHT_SUPER"); + lua_pushinteger(L, 348); + lua_setfield(L, -2, "KEY_KB_MENU"); + lua_pushinteger(L, 320); + lua_setfield(L, -2, "KEY_KP_0"); + lua_pushinteger(L, 321); + lua_setfield(L, -2, "KEY_KP_1"); + lua_pushinteger(L, 322); + lua_setfield(L, -2, "KEY_KP_2"); + lua_pushinteger(L, 323); + lua_setfield(L, -2, "KEY_KP_3"); + lua_pushinteger(L, 324); + lua_setfield(L, -2, "KEY_KP_4"); + lua_pushinteger(L, 325); + lua_setfield(L, -2, "KEY_KP_5"); + lua_pushinteger(L, 326); + lua_setfield(L, -2, "KEY_KP_6"); + lua_pushinteger(L, 327); + lua_setfield(L, -2, "KEY_KP_7"); + lua_pushinteger(L, 328); + lua_setfield(L, -2, "KEY_KP_8"); + lua_pushinteger(L, 329); + lua_setfield(L, -2, "KEY_KP_9"); + lua_pushinteger(L, 330); + lua_setfield(L, -2, "KEY_KP_DECIMAL"); + lua_pushinteger(L, 331); + lua_setfield(L, -2, "KEY_KP_DIVIDE"); + lua_pushinteger(L, 332); + lua_setfield(L, -2, "KEY_KP_MULTIPLY"); + lua_pushinteger(L, 333); + lua_setfield(L, -2, "KEY_KP_SUBTRACT"); + lua_pushinteger(L, 334); + lua_setfield(L, -2, "KEY_KP_ADD"); + lua_pushinteger(L, 335); + lua_setfield(L, -2, "KEY_KP_ENTER"); + lua_pushinteger(L, 336); + lua_setfield(L, -2, "KEY_KP_EQUAL"); + lua_pushinteger(L, 4); + lua_setfield(L, -2, "KEY_BACK"); + lua_pushinteger(L, 5); + lua_setfield(L, -2, "KEY_MENU"); + lua_pushinteger(L, 24); + lua_setfield(L, -2, "KEY_VOLUME_UP"); + lua_pushinteger(L, 25); + lua_setfield(L, -2, "KEY_VOLUME_DOWN"); + lua_pushinteger(L, 0); + lua_setfield(L, -2, "MOUSE_BUTTON_LEFT"); + lua_pushinteger(L, 1); + lua_setfield(L, -2, "MOUSE_BUTTON_RIGHT"); + lua_pushinteger(L, 2); + lua_setfield(L, -2, "MOUSE_BUTTON_MIDDLE"); + lua_pushinteger(L, 3); + lua_setfield(L, -2, "MOUSE_BUTTON_SIDE"); + lua_pushinteger(L, 4); + lua_setfield(L, -2, "MOUSE_BUTTON_EXTRA"); + lua_pushinteger(L, 5); + lua_setfield(L, -2, "MOUSE_BUTTON_FORWARD"); + lua_pushinteger(L, 6); + lua_setfield(L, -2, "MOUSE_BUTTON_BACK"); + lua_pushinteger(L, 0); + lua_setfield(L, -2, "MOUSE_CURSOR_DEFAULT"); + lua_pushinteger(L, 1); + lua_setfield(L, -2, "MOUSE_CURSOR_ARROW"); + lua_pushinteger(L, 2); + lua_setfield(L, -2, "MOUSE_CURSOR_IBEAM"); + lua_pushinteger(L, 3); + lua_setfield(L, -2, "MOUSE_CURSOR_CROSSHAIR"); + lua_pushinteger(L, 4); + lua_setfield(L, -2, "MOUSE_CURSOR_POINTING_HAND"); + lua_pushinteger(L, 5); + lua_setfield(L, -2, "MOUSE_CURSOR_RESIZE_EW"); + lua_pushinteger(L, 6); + lua_setfield(L, -2, "MOUSE_CURSOR_RESIZE_NS"); + lua_pushinteger(L, 7); + lua_setfield(L, -2, "MOUSE_CURSOR_RESIZE_NWSE"); + lua_pushinteger(L, 8); + lua_setfield(L, -2, "MOUSE_CURSOR_RESIZE_NESW"); + lua_pushinteger(L, 9); + lua_setfield(L, -2, "MOUSE_CURSOR_RESIZE_ALL"); + lua_pushinteger(L, 10); + lua_setfield(L, -2, "MOUSE_CURSOR_NOT_ALLOWED"); + lua_pushinteger(L, 0); + lua_setfield(L, -2, "GAMEPAD_BUTTON_UNKNOWN"); + lua_pushinteger(L, 1); + lua_setfield(L, -2, "GAMEPAD_BUTTON_LEFT_FACE_UP"); + lua_pushinteger(L, 2); + lua_setfield(L, -2, "GAMEPAD_BUTTON_LEFT_FACE_RIGHT"); + lua_pushinteger(L, 3); + lua_setfield(L, -2, "GAMEPAD_BUTTON_LEFT_FACE_DOWN"); + lua_pushinteger(L, 4); + lua_setfield(L, -2, "GAMEPAD_BUTTON_LEFT_FACE_LEFT"); + lua_pushinteger(L, 5); + lua_setfield(L, -2, "GAMEPAD_BUTTON_RIGHT_FACE_UP"); + lua_pushinteger(L, 6); + lua_setfield(L, -2, "GAMEPAD_BUTTON_RIGHT_FACE_RIGHT"); + lua_pushinteger(L, 7); + lua_setfield(L, -2, "GAMEPAD_BUTTON_RIGHT_FACE_DOWN"); + lua_pushinteger(L, 8); + lua_setfield(L, -2, "GAMEPAD_BUTTON_RIGHT_FACE_LEFT"); + lua_pushinteger(L, 9); + lua_setfield(L, -2, "GAMEPAD_BUTTON_LEFT_TRIGGER_1"); + lua_pushinteger(L, 10); + lua_setfield(L, -2, "GAMEPAD_BUTTON_LEFT_TRIGGER_2"); + lua_pushinteger(L, 11); + lua_setfield(L, -2, "GAMEPAD_BUTTON_RIGHT_TRIGGER_1"); + lua_pushinteger(L, 12); + lua_setfield(L, -2, "GAMEPAD_BUTTON_RIGHT_TRIGGER_2"); + lua_pushinteger(L, 13); + lua_setfield(L, -2, "GAMEPAD_BUTTON_MIDDLE_LEFT"); + lua_pushinteger(L, 14); + lua_setfield(L, -2, "GAMEPAD_BUTTON_MIDDLE"); + lua_pushinteger(L, 15); + lua_setfield(L, -2, "GAMEPAD_BUTTON_MIDDLE_RIGHT"); + lua_pushinteger(L, 16); + lua_setfield(L, -2, "GAMEPAD_BUTTON_LEFT_THUMB"); + lua_pushinteger(L, 17); + lua_setfield(L, -2, "GAMEPAD_BUTTON_RIGHT_THUMB"); + lua_pushinteger(L, 0); + lua_setfield(L, -2, "GAMEPAD_AXIS_LEFT_X"); + lua_pushinteger(L, 1); + lua_setfield(L, -2, "GAMEPAD_AXIS_LEFT_Y"); + lua_pushinteger(L, 2); + lua_setfield(L, -2, "GAMEPAD_AXIS_RIGHT_X"); + lua_pushinteger(L, 3); + lua_setfield(L, -2, "GAMEPAD_AXIS_RIGHT_Y"); + lua_pushinteger(L, 4); + lua_setfield(L, -2, "GAMEPAD_AXIS_LEFT_TRIGGER"); + lua_pushinteger(L, 5); + lua_setfield(L, -2, "GAMEPAD_AXIS_RIGHT_TRIGGER"); + lua_pushinteger(L, 0); + lua_setfield(L, -2, "MATERIAL_MAP_ALBEDO"); + lua_pushinteger(L, 1); + lua_setfield(L, -2, "MATERIAL_MAP_METALNESS"); + lua_pushinteger(L, 2); + lua_setfield(L, -2, "MATERIAL_MAP_NORMAL"); + lua_pushinteger(L, 3); + lua_setfield(L, -2, "MATERIAL_MAP_ROUGHNESS"); + lua_pushinteger(L, 4); + lua_setfield(L, -2, "MATERIAL_MAP_OCCLUSION"); + lua_pushinteger(L, 5); + lua_setfield(L, -2, "MATERIAL_MAP_EMISSION"); + lua_pushinteger(L, 6); + lua_setfield(L, -2, "MATERIAL_MAP_HEIGHT"); + lua_pushinteger(L, 7); + lua_setfield(L, -2, "MATERIAL_MAP_CUBEMAP"); + lua_pushinteger(L, 8); + lua_setfield(L, -2, "MATERIAL_MAP_IRRADIANCE"); + lua_pushinteger(L, 9); + lua_setfield(L, -2, "MATERIAL_MAP_PREFILTER"); + lua_pushinteger(L, 10); + lua_setfield(L, -2, "MATERIAL_MAP_BRDF"); + lua_pushinteger(L, 0); + lua_setfield(L, -2, "SHADER_LOC_VERTEX_POSITION"); + lua_pushinteger(L, 1); + lua_setfield(L, -2, "SHADER_LOC_VERTEX_TEXCOORD01"); + lua_pushinteger(L, 2); + lua_setfield(L, -2, "SHADER_LOC_VERTEX_TEXCOORD02"); + lua_pushinteger(L, 3); + lua_setfield(L, -2, "SHADER_LOC_VERTEX_NORMAL"); + lua_pushinteger(L, 4); + lua_setfield(L, -2, "SHADER_LOC_VERTEX_TANGENT"); + lua_pushinteger(L, 5); + lua_setfield(L, -2, "SHADER_LOC_VERTEX_COLOR"); + lua_pushinteger(L, 6); + lua_setfield(L, -2, "SHADER_LOC_MATRIX_MVP"); + lua_pushinteger(L, 7); + lua_setfield(L, -2, "SHADER_LOC_MATRIX_VIEW"); + lua_pushinteger(L, 8); + lua_setfield(L, -2, "SHADER_LOC_MATRIX_PROJECTION"); + lua_pushinteger(L, 9); + lua_setfield(L, -2, "SHADER_LOC_MATRIX_MODEL"); + lua_pushinteger(L, 10); + lua_setfield(L, -2, "SHADER_LOC_MATRIX_NORMAL"); + lua_pushinteger(L, 11); + lua_setfield(L, -2, "SHADER_LOC_VECTOR_VIEW"); + lua_pushinteger(L, 12); + lua_setfield(L, -2, "SHADER_LOC_COLOR_DIFFUSE"); + lua_pushinteger(L, 13); + lua_setfield(L, -2, "SHADER_LOC_COLOR_SPECULAR"); + lua_pushinteger(L, 14); + lua_setfield(L, -2, "SHADER_LOC_COLOR_AMBIENT"); + lua_pushinteger(L, 15); + lua_setfield(L, -2, "SHADER_LOC_MAP_ALBEDO"); + lua_pushinteger(L, 16); + lua_setfield(L, -2, "SHADER_LOC_MAP_METALNESS"); + lua_pushinteger(L, 17); + lua_setfield(L, -2, "SHADER_LOC_MAP_NORMAL"); + lua_pushinteger(L, 18); + lua_setfield(L, -2, "SHADER_LOC_MAP_ROUGHNESS"); + lua_pushinteger(L, 19); + lua_setfield(L, -2, "SHADER_LOC_MAP_OCCLUSION"); + lua_pushinteger(L, 20); + lua_setfield(L, -2, "SHADER_LOC_MAP_EMISSION"); + lua_pushinteger(L, 21); + lua_setfield(L, -2, "SHADER_LOC_MAP_HEIGHT"); + lua_pushinteger(L, 22); + lua_setfield(L, -2, "SHADER_LOC_MAP_CUBEMAP"); + lua_pushinteger(L, 23); + lua_setfield(L, -2, "SHADER_LOC_MAP_IRRADIANCE"); + lua_pushinteger(L, 24); + lua_setfield(L, -2, "SHADER_LOC_MAP_PREFILTER"); + lua_pushinteger(L, 25); + lua_setfield(L, -2, "SHADER_LOC_MAP_BRDF"); + lua_pushinteger(L, 26); + lua_setfield(L, -2, "SHADER_LOC_VERTEX_BONEIDS"); + lua_pushinteger(L, 27); + lua_setfield(L, -2, "SHADER_LOC_VERTEX_BONEWEIGHTS"); + lua_pushinteger(L, 28); + lua_setfield(L, -2, "SHADER_LOC_MATRIX_BONETRANSFORMS"); + lua_pushinteger(L, 29); + lua_setfield(L, -2, "SHADER_LOC_VERTEX_INSTANCETRANSFORM"); + lua_pushinteger(L, 0); + lua_setfield(L, -2, "SHADER_UNIFORM_FLOAT"); + lua_pushinteger(L, 1); + lua_setfield(L, -2, "SHADER_UNIFORM_VEC2"); + lua_pushinteger(L, 2); + lua_setfield(L, -2, "SHADER_UNIFORM_VEC3"); + lua_pushinteger(L, 3); + lua_setfield(L, -2, "SHADER_UNIFORM_VEC4"); + lua_pushinteger(L, 4); + lua_setfield(L, -2, "SHADER_UNIFORM_INT"); + lua_pushinteger(L, 5); + lua_setfield(L, -2, "SHADER_UNIFORM_IVEC2"); + lua_pushinteger(L, 6); + lua_setfield(L, -2, "SHADER_UNIFORM_IVEC3"); + lua_pushinteger(L, 7); + lua_setfield(L, -2, "SHADER_UNIFORM_IVEC4"); + lua_pushinteger(L, 8); + lua_setfield(L, -2, "SHADER_UNIFORM_UINT"); + lua_pushinteger(L, 9); + lua_setfield(L, -2, "SHADER_UNIFORM_UIVEC2"); + lua_pushinteger(L, 10); + lua_setfield(L, -2, "SHADER_UNIFORM_UIVEC3"); + lua_pushinteger(L, 11); + lua_setfield(L, -2, "SHADER_UNIFORM_UIVEC4"); + lua_pushinteger(L, 12); + lua_setfield(L, -2, "SHADER_UNIFORM_SAMPLER2D"); + lua_pushinteger(L, 0); + lua_setfield(L, -2, "SHADER_ATTRIB_FLOAT"); + lua_pushinteger(L, 1); + lua_setfield(L, -2, "SHADER_ATTRIB_VEC2"); + lua_pushinteger(L, 2); + lua_setfield(L, -2, "SHADER_ATTRIB_VEC3"); + lua_pushinteger(L, 3); + lua_setfield(L, -2, "SHADER_ATTRIB_VEC4"); + lua_pushinteger(L, 1); + lua_setfield(L, -2, "PIXELFORMAT_UNCOMPRESSED_GRAYSCALE"); + lua_pushinteger(L, 2); + lua_setfield(L, -2, "PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA"); + lua_pushinteger(L, 3); + lua_setfield(L, -2, "PIXELFORMAT_UNCOMPRESSED_R5G6B5"); + lua_pushinteger(L, 4); + lua_setfield(L, -2, "PIXELFORMAT_UNCOMPRESSED_R8G8B8"); + lua_pushinteger(L, 5); + lua_setfield(L, -2, "PIXELFORMAT_UNCOMPRESSED_R5G5B5A1"); + lua_pushinteger(L, 6); + lua_setfield(L, -2, "PIXELFORMAT_UNCOMPRESSED_R4G4B4A4"); + lua_pushinteger(L, 7); + lua_setfield(L, -2, "PIXELFORMAT_UNCOMPRESSED_R8G8B8A8"); + lua_pushinteger(L, 8); + lua_setfield(L, -2, "PIXELFORMAT_UNCOMPRESSED_R32"); + lua_pushinteger(L, 9); + lua_setfield(L, -2, "PIXELFORMAT_UNCOMPRESSED_R32G32B32"); + lua_pushinteger(L, 10); + lua_setfield(L, -2, "PIXELFORMAT_UNCOMPRESSED_R32G32B32A32"); + lua_pushinteger(L, 11); + lua_setfield(L, -2, "PIXELFORMAT_UNCOMPRESSED_R16"); + lua_pushinteger(L, 12); + lua_setfield(L, -2, "PIXELFORMAT_UNCOMPRESSED_R16G16B16"); + lua_pushinteger(L, 13); + lua_setfield(L, -2, "PIXELFORMAT_UNCOMPRESSED_R16G16B16A16"); + lua_pushinteger(L, 14); + lua_setfield(L, -2, "PIXELFORMAT_COMPRESSED_DXT1_RGB"); + lua_pushinteger(L, 15); + lua_setfield(L, -2, "PIXELFORMAT_COMPRESSED_DXT1_RGBA"); + lua_pushinteger(L, 16); + lua_setfield(L, -2, "PIXELFORMAT_COMPRESSED_DXT3_RGBA"); + lua_pushinteger(L, 17); + lua_setfield(L, -2, "PIXELFORMAT_COMPRESSED_DXT5_RGBA"); + lua_pushinteger(L, 18); + lua_setfield(L, -2, "PIXELFORMAT_COMPRESSED_ETC1_RGB"); + lua_pushinteger(L, 19); + lua_setfield(L, -2, "PIXELFORMAT_COMPRESSED_ETC2_RGB"); + lua_pushinteger(L, 20); + lua_setfield(L, -2, "PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA"); + lua_pushinteger(L, 21); + lua_setfield(L, -2, "PIXELFORMAT_COMPRESSED_PVRT_RGB"); + lua_pushinteger(L, 22); + lua_setfield(L, -2, "PIXELFORMAT_COMPRESSED_PVRT_RGBA"); + lua_pushinteger(L, 23); + lua_setfield(L, -2, "PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA"); + lua_pushinteger(L, 24); + lua_setfield(L, -2, "PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA"); + lua_pushinteger(L, 0); + lua_setfield(L, -2, "TEXTURE_FILTER_POINT"); + lua_pushinteger(L, 1); + lua_setfield(L, -2, "TEXTURE_FILTER_BILINEAR"); + lua_pushinteger(L, 2); + lua_setfield(L, -2, "TEXTURE_FILTER_TRILINEAR"); + lua_pushinteger(L, 3); + lua_setfield(L, -2, "TEXTURE_FILTER_ANISOTROPIC_4X"); + lua_pushinteger(L, 4); + lua_setfield(L, -2, "TEXTURE_FILTER_ANISOTROPIC_8X"); + lua_pushinteger(L, 5); + lua_setfield(L, -2, "TEXTURE_FILTER_ANISOTROPIC_16X"); + lua_pushinteger(L, 0); + lua_setfield(L, -2, "TEXTURE_WRAP_REPEAT"); + lua_pushinteger(L, 1); + lua_setfield(L, -2, "TEXTURE_WRAP_CLAMP"); + lua_pushinteger(L, 2); + lua_setfield(L, -2, "TEXTURE_WRAP_MIRROR_REPEAT"); + lua_pushinteger(L, 3); + lua_setfield(L, -2, "TEXTURE_WRAP_MIRROR_CLAMP"); + lua_pushinteger(L, 0); + lua_setfield(L, -2, "CUBEMAP_LAYOUT_AUTO_DETECT"); + lua_pushinteger(L, 1); + lua_setfield(L, -2, "CUBEMAP_LAYOUT_LINE_VERTICAL"); + lua_pushinteger(L, 2); + lua_setfield(L, -2, "CUBEMAP_LAYOUT_LINE_HORIZONTAL"); + lua_pushinteger(L, 3); + lua_setfield(L, -2, "CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR"); + lua_pushinteger(L, 4); + lua_setfield(L, -2, "CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE"); + lua_pushinteger(L, 0); + lua_setfield(L, -2, "FONT_DEFAULT"); + lua_pushinteger(L, 1); + lua_setfield(L, -2, "FONT_BITMAP"); + lua_pushinteger(L, 2); + lua_setfield(L, -2, "FONT_SDF"); + lua_pushinteger(L, 0); + lua_setfield(L, -2, "BLEND_ALPHA"); + lua_pushinteger(L, 1); + lua_setfield(L, -2, "BLEND_ADDITIVE"); + lua_pushinteger(L, 2); + lua_setfield(L, -2, "BLEND_MULTIPLIED"); + lua_pushinteger(L, 3); + lua_setfield(L, -2, "BLEND_ADD_COLORS"); + lua_pushinteger(L, 4); + lua_setfield(L, -2, "BLEND_SUBTRACT_COLORS"); + lua_pushinteger(L, 5); + lua_setfield(L, -2, "BLEND_ALPHA_PREMULTIPLY"); + lua_pushinteger(L, 6); + lua_setfield(L, -2, "BLEND_CUSTOM"); + lua_pushinteger(L, 7); + lua_setfield(L, -2, "BLEND_CUSTOM_SEPARATE"); + lua_pushinteger(L, 0); + lua_setfield(L, -2, "GESTURE_NONE"); + lua_pushinteger(L, 1); + lua_setfield(L, -2, "GESTURE_TAP"); + lua_pushinteger(L, 2); + lua_setfield(L, -2, "GESTURE_DOUBLETAP"); + lua_pushinteger(L, 4); + lua_setfield(L, -2, "GESTURE_HOLD"); + lua_pushinteger(L, 8); + lua_setfield(L, -2, "GESTURE_DRAG"); + lua_pushinteger(L, 16); + lua_setfield(L, -2, "GESTURE_SWIPE_RIGHT"); + lua_pushinteger(L, 32); + lua_setfield(L, -2, "GESTURE_SWIPE_LEFT"); + lua_pushinteger(L, 64); + lua_setfield(L, -2, "GESTURE_SWIPE_UP"); + lua_pushinteger(L, 128); + lua_setfield(L, -2, "GESTURE_SWIPE_DOWN"); + lua_pushinteger(L, 256); + lua_setfield(L, -2, "GESTURE_PINCH_IN"); + lua_pushinteger(L, 512); + lua_setfield(L, -2, "GESTURE_PINCH_OUT"); + lua_pushinteger(L, 0); + lua_setfield(L, -2, "CAMERA_CUSTOM"); + lua_pushinteger(L, 1); + lua_setfield(L, -2, "CAMERA_FREE"); + lua_pushinteger(L, 2); + lua_setfield(L, -2, "CAMERA_ORBITAL"); + lua_pushinteger(L, 3); + lua_setfield(L, -2, "CAMERA_FIRST_PERSON"); + lua_pushinteger(L, 4); + lua_setfield(L, -2, "CAMERA_THIRD_PERSON"); + lua_pushinteger(L, 0); + lua_setfield(L, -2, "CAMERA_PERSPECTIVE"); + lua_pushinteger(L, 1); + lua_setfield(L, -2, "CAMERA_ORTHOGRAPHIC"); + lua_pushinteger(L, 0); + lua_setfield(L, -2, "NPATCH_NINE_PATCH"); + lua_pushinteger(L, 1); + lua_setfield(L, -2, "NPATCH_THREE_PATCH_VERTICAL"); + lua_pushinteger(L, 2); + lua_setfield(L, -2, "NPATCH_THREE_PATCH_HORIZONTAL"); + lua_pushnumber(L, 3.14159265358979323846f); + lua_setfield(L, -2, "PI"); + lua_pushnumber(L, (PI/180.0f)); + lua_setfield(L, -2, "DEG2RAD"); + lua_pushnumber(L, (180.0f/PI)); + lua_setfield(L, -2, "RAD2DEG"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 200, 200, 200, 255 }); + lua_setfield(L, -2, "LIGHTGRAY"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 130, 130, 130, 255 }); + lua_setfield(L, -2, "GRAY"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 80, 80, 80, 255 }); + lua_setfield(L, -2, "DARKGRAY"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 253, 249, 0, 255 }); + lua_setfield(L, -2, "YELLOW"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 255, 203, 0, 255 }); + lua_setfield(L, -2, "GOLD"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 255, 161, 0, 255 }); + lua_setfield(L, -2, "ORANGE"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 255, 109, 194, 255 }); + lua_setfield(L, -2, "PINK"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 230, 41, 55, 255 }); + lua_setfield(L, -2, "RED"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 190, 33, 55, 255 }); + lua_setfield(L, -2, "MAROON"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 0, 228, 48, 255 }); + lua_setfield(L, -2, "GREEN"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 0, 158, 47, 255 }); + lua_setfield(L, -2, "LIME"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 0, 117, 44, 255 }); + lua_setfield(L, -2, "DARKGREEN"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 102, 191, 255, 255 }); + lua_setfield(L, -2, "SKYBLUE"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 0, 121, 241, 255 }); + lua_setfield(L, -2, "BLUE"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 0, 82, 172, 255 }); + lua_setfield(L, -2, "DARKBLUE"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 200, 122, 255, 255 }); + lua_setfield(L, -2, "PURPLE"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 135, 60, 190, 255 }); + lua_setfield(L, -2, "VIOLET"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 112, 31, 126, 255 }); + lua_setfield(L, -2, "DARKPURPLE"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 211, 176, 131, 255 }); + lua_setfield(L, -2, "BEIGE"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 127, 106, 79, 255 }); + lua_setfield(L, -2, "BROWN"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 76, 63, 47, 255 }); + lua_setfield(L, -2, "DARKBROWN"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 255, 255, 255, 255 }); + lua_setfield(L, -2, "WHITE"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 0, 0, 0, 255 }); + lua_setfield(L, -2, "BLACK"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 0, 0, 0, 0 }); + lua_setfield(L, -2, "BLANK"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 255, 0, 255, 255 }); + lua_setfield(L, -2, "MAGENTA"); + RLUA_PUSH_Color(L, CLITERAL(Color){ 245, 245, 245, 255 }); + lua_setfield(L, -2, "RAYWHITE"); + lua_pushinteger(L, MOUSE_BUTTON_LEFT); + lua_setfield(L, -2, "MOUSE_LEFT_BUTTON"); + lua_pushinteger(L, MOUSE_BUTTON_RIGHT); + lua_setfield(L, -2, "MOUSE_RIGHT_BUTTON"); + lua_pushinteger(L, MOUSE_BUTTON_MIDDLE); + lua_setfield(L, -2, "MOUSE_MIDDLE_BUTTON"); + lua_pushinteger(L, MATERIAL_MAP_ALBEDO); + lua_setfield(L, -2, "MATERIAL_MAP_DIFFUSE"); + lua_pushinteger(L, MATERIAL_MAP_METALNESS); + lua_setfield(L, -2, "MATERIAL_MAP_SPECULAR"); + lua_pushinteger(L, SHADER_LOC_MAP_ALBEDO); + lua_setfield(L, -2, "SHADER_LOC_MAP_DIFFUSE"); + lua_pushinteger(L, SHADER_LOC_MAP_METALNESS); + lua_setfield(L, -2, "SHADER_LOC_MAP_SPECULAR"); +} + +// raylib functions list +static const struct luaL_Reg raylib_functions[] = { + {"InitWindow", rl_InitWindow}, + {"CloseWindow", rl_CloseWindow}, + {"WindowShouldClose", rl_WindowShouldClose}, + {"IsWindowReady", rl_IsWindowReady}, + {"IsWindowFullscreen", rl_IsWindowFullscreen}, + {"IsWindowHidden", rl_IsWindowHidden}, + {"IsWindowMinimized", rl_IsWindowMinimized}, + {"IsWindowMaximized", rl_IsWindowMaximized}, + {"IsWindowFocused", rl_IsWindowFocused}, + {"IsWindowResized", rl_IsWindowResized}, + {"IsWindowState", rl_IsWindowState}, + {"SetWindowState", rl_SetWindowState}, + {"ClearWindowState", rl_ClearWindowState}, + {"ToggleFullscreen", rl_ToggleFullscreen}, + {"ToggleBorderlessWindowed", rl_ToggleBorderlessWindowed}, + {"MaximizeWindow", rl_MaximizeWindow}, + {"MinimizeWindow", rl_MinimizeWindow}, + {"RestoreWindow", rl_RestoreWindow}, + {"SetWindowIcon", rl_SetWindowIcon}, + {"SetWindowIcons", rl_SetWindowIcons}, + {"SetWindowTitle", rl_SetWindowTitle}, + {"SetWindowPosition", rl_SetWindowPosition}, + {"SetWindowMonitor", rl_SetWindowMonitor}, + {"SetWindowMinSize", rl_SetWindowMinSize}, + {"SetWindowMaxSize", rl_SetWindowMaxSize}, + {"SetWindowSize", rl_SetWindowSize}, + {"SetWindowOpacity", rl_SetWindowOpacity}, + {"SetWindowFocused", rl_SetWindowFocused}, + {"GetWindowHandle", rl_GetWindowHandle}, + {"GetScreenWidth", rl_GetScreenWidth}, + {"GetScreenHeight", rl_GetScreenHeight}, + {"GetRenderWidth", rl_GetRenderWidth}, + {"GetRenderHeight", rl_GetRenderHeight}, + {"GetMonitorCount", rl_GetMonitorCount}, + {"GetCurrentMonitor", rl_GetCurrentMonitor}, + {"GetMonitorPosition", rl_GetMonitorPosition}, + {"GetMonitorWidth", rl_GetMonitorWidth}, + {"GetMonitorHeight", rl_GetMonitorHeight}, + {"GetMonitorPhysicalWidth", rl_GetMonitorPhysicalWidth}, + {"GetMonitorPhysicalHeight", rl_GetMonitorPhysicalHeight}, + {"GetMonitorRefreshRate", rl_GetMonitorRefreshRate}, + {"GetWindowPosition", rl_GetWindowPosition}, + {"GetWindowScaleDPI", rl_GetWindowScaleDPI}, + {"GetMonitorName", rl_GetMonitorName}, + {"SetClipboardText", rl_SetClipboardText}, + {"GetClipboardText", rl_GetClipboardText}, + {"GetClipboardImage", rl_GetClipboardImage}, + {"EnableEventWaiting", rl_EnableEventWaiting}, + {"DisableEventWaiting", rl_DisableEventWaiting}, + {"ShowCursor", rl_ShowCursor}, + {"HideCursor", rl_HideCursor}, + {"IsCursorHidden", rl_IsCursorHidden}, + {"EnableCursor", rl_EnableCursor}, + {"DisableCursor", rl_DisableCursor}, + {"IsCursorOnScreen", rl_IsCursorOnScreen}, + {"ClearBackground", rl_ClearBackground}, + {"BeginDrawing", rl_BeginDrawing}, + {"EndDrawing", rl_EndDrawing}, + {"BeginMode2D", rl_BeginMode2D}, + {"EndMode2D", rl_EndMode2D}, + {"BeginMode3D", rl_BeginMode3D}, + {"EndMode3D", rl_EndMode3D}, + {"BeginTextureMode", rl_BeginTextureMode}, + {"EndTextureMode", rl_EndTextureMode}, + {"BeginShaderMode", rl_BeginShaderMode}, + {"EndShaderMode", rl_EndShaderMode}, + {"BeginBlendMode", rl_BeginBlendMode}, + {"EndBlendMode", rl_EndBlendMode}, + {"BeginScissorMode", rl_BeginScissorMode}, + {"EndScissorMode", rl_EndScissorMode}, + {"BeginVrStereoMode", rl_BeginVrStereoMode}, + {"EndVrStereoMode", rl_EndVrStereoMode}, + {"LoadVrStereoConfig", rl_LoadVrStereoConfig}, + {"UnloadVrStereoConfig", rl_UnloadVrStereoConfig}, + {"LoadShader", rl_LoadShader}, + {"LoadShaderFromMemory", rl_LoadShaderFromMemory}, + {"IsShaderValid", rl_IsShaderValid}, + {"GetShaderLocation", rl_GetShaderLocation}, + {"GetShaderLocationAttrib", rl_GetShaderLocationAttrib}, + {"SetShaderValue", rl_SetShaderValue}, + {"SetShaderValueV", rl_SetShaderValueV}, + {"SetShaderValueMatrix", rl_SetShaderValueMatrix}, + {"SetShaderValueTexture", rl_SetShaderValueTexture}, + {"UnloadShader", rl_UnloadShader}, + {"GetScreenToWorldRay", rl_GetScreenToWorldRay}, + {"GetScreenToWorldRayEx", rl_GetScreenToWorldRayEx}, + {"GetWorldToScreen", rl_GetWorldToScreen}, + {"GetWorldToScreenEx", rl_GetWorldToScreenEx}, + {"GetWorldToScreen2D", rl_GetWorldToScreen2D}, + {"GetScreenToWorld2D", rl_GetScreenToWorld2D}, + {"GetCameraMatrix", rl_GetCameraMatrix}, + {"GetCameraMatrix2D", rl_GetCameraMatrix2D}, + {"SetTargetFPS", rl_SetTargetFPS}, + {"GetFrameTime", rl_GetFrameTime}, + {"GetTime", rl_GetTime}, + {"GetFPS", rl_GetFPS}, + {"SwapScreenBuffer", rl_SwapScreenBuffer}, + {"PollInputEvents", rl_PollInputEvents}, + {"WaitTime", rl_WaitTime}, + {"SetRandomSeed", rl_SetRandomSeed}, + {"GetRandomValue", rl_GetRandomValue}, + {"LoadRandomSequence", rl_LoadRandomSequence}, + {"UnloadRandomSequence", rl_UnloadRandomSequence}, + {"TakeScreenshot", rl_TakeScreenshot}, + {"SetConfigFlags", rl_SetConfigFlags}, + {"OpenURL", rl_OpenURL}, + {"SetTraceLogLevel", rl_SetTraceLogLevel}, + {"TraceLog", rl_TraceLog}, + {"SetTraceLogCallback", rl_SetTraceLogCallback}, + {"MemAlloc", rl_MemAlloc}, + {"MemRealloc", rl_MemRealloc}, + {"MemFree", rl_MemFree}, + {"LoadFileData", rl_LoadFileData}, + {"UnloadFileData", rl_UnloadFileData}, + {"SaveFileData", rl_SaveFileData}, + {"ExportDataAsCode", rl_ExportDataAsCode}, + {"LoadFileText", rl_LoadFileText}, + {"UnloadFileText", rl_UnloadFileText}, + {"SaveFileText", rl_SaveFileText}, + {"SetLoadFileDataCallback", rl_SetLoadFileDataCallback}, + {"SetSaveFileDataCallback", rl_SetSaveFileDataCallback}, + {"SetLoadFileTextCallback", rl_SetLoadFileTextCallback}, + {"SetSaveFileTextCallback", rl_SetSaveFileTextCallback}, + {"FileRename", rl_FileRename}, + {"FileRemove", rl_FileRemove}, + {"FileCopy", rl_FileCopy}, + {"FileMove", rl_FileMove}, + {"FileTextReplace", rl_FileTextReplace}, + {"FileTextFindIndex", rl_FileTextFindIndex}, + {"FileExists", rl_FileExists}, + {"DirectoryExists", rl_DirectoryExists}, + {"IsFileExtension", rl_IsFileExtension}, + {"GetFileLength", rl_GetFileLength}, + {"GetFileModTime", rl_GetFileModTime}, + {"GetFileExtension", rl_GetFileExtension}, + {"GetFileName", rl_GetFileName}, + {"GetFileNameWithoutExt", rl_GetFileNameWithoutExt}, + {"GetDirectoryPath", rl_GetDirectoryPath}, + {"GetPrevDirectoryPath", rl_GetPrevDirectoryPath}, + {"GetWorkingDirectory", rl_GetWorkingDirectory}, + {"GetApplicationDirectory", rl_GetApplicationDirectory}, + {"MakeDirectory", rl_MakeDirectory}, + {"ChangeDirectory", rl_ChangeDirectory}, + {"IsPathFile", rl_IsPathFile}, + {"IsFileNameValid", rl_IsFileNameValid}, + {"LoadDirectoryFiles", rl_LoadDirectoryFiles}, + {"LoadDirectoryFilesEx", rl_LoadDirectoryFilesEx}, + {"UnloadDirectoryFiles", rl_UnloadDirectoryFiles}, + {"IsFileDropped", rl_IsFileDropped}, + {"LoadDroppedFiles", rl_LoadDroppedFiles}, + {"UnloadDroppedFiles", rl_UnloadDroppedFiles}, + {"GetDirectoryFileCount", rl_GetDirectoryFileCount}, + {"GetDirectoryFileCountEx", rl_GetDirectoryFileCountEx}, + {"CompressData", rl_CompressData}, + {"DecompressData", rl_DecompressData}, + {"EncodeDataBase64", rl_EncodeDataBase64}, + {"DecodeDataBase64", rl_DecodeDataBase64}, + {"ComputeCRC32", rl_ComputeCRC32}, + {"ComputeMD5", rl_ComputeMD5}, + {"ComputeSHA1", rl_ComputeSHA1}, + {"ComputeSHA256", rl_ComputeSHA256}, + {"LoadAutomationEventList", rl_LoadAutomationEventList}, + {"UnloadAutomationEventList", rl_UnloadAutomationEventList}, + {"ExportAutomationEventList", rl_ExportAutomationEventList}, + {"SetAutomationEventList", rl_SetAutomationEventList}, + {"SetAutomationEventBaseFrame", rl_SetAutomationEventBaseFrame}, + {"StartAutomationEventRecording", rl_StartAutomationEventRecording}, + {"StopAutomationEventRecording", rl_StopAutomationEventRecording}, + {"PlayAutomationEvent", rl_PlayAutomationEvent}, + {"IsKeyPressed", rl_IsKeyPressed}, + {"IsKeyPressedRepeat", rl_IsKeyPressedRepeat}, + {"IsKeyDown", rl_IsKeyDown}, + {"IsKeyReleased", rl_IsKeyReleased}, + {"IsKeyUp", rl_IsKeyUp}, + {"GetKeyPressed", rl_GetKeyPressed}, + {"GetCharPressed", rl_GetCharPressed}, + {"GetKeyName", rl_GetKeyName}, + {"SetExitKey", rl_SetExitKey}, + {"IsGamepadAvailable", rl_IsGamepadAvailable}, + {"GetGamepadName", rl_GetGamepadName}, + {"IsGamepadButtonPressed", rl_IsGamepadButtonPressed}, + {"IsGamepadButtonDown", rl_IsGamepadButtonDown}, + {"IsGamepadButtonReleased", rl_IsGamepadButtonReleased}, + {"IsGamepadButtonUp", rl_IsGamepadButtonUp}, + {"GetGamepadButtonPressed", rl_GetGamepadButtonPressed}, + {"GetGamepadAxisCount", rl_GetGamepadAxisCount}, + {"GetGamepadAxisMovement", rl_GetGamepadAxisMovement}, + {"SetGamepadMappings", rl_SetGamepadMappings}, + {"SetGamepadVibration", rl_SetGamepadVibration}, + {"IsMouseButtonPressed", rl_IsMouseButtonPressed}, + {"IsMouseButtonDown", rl_IsMouseButtonDown}, + {"IsMouseButtonReleased", rl_IsMouseButtonReleased}, + {"IsMouseButtonUp", rl_IsMouseButtonUp}, + {"GetMouseX", rl_GetMouseX}, + {"GetMouseY", rl_GetMouseY}, + {"GetMousePosition", rl_GetMousePosition}, + {"GetMouseDelta", rl_GetMouseDelta}, + {"SetMousePosition", rl_SetMousePosition}, + {"SetMouseOffset", rl_SetMouseOffset}, + {"SetMouseScale", rl_SetMouseScale}, + {"GetMouseWheelMove", rl_GetMouseWheelMove}, + {"GetMouseWheelMoveV", rl_GetMouseWheelMoveV}, + {"SetMouseCursor", rl_SetMouseCursor}, + {"GetTouchX", rl_GetTouchX}, + {"GetTouchY", rl_GetTouchY}, + {"GetTouchPosition", rl_GetTouchPosition}, + {"GetTouchPointId", rl_GetTouchPointId}, + {"GetTouchPointCount", rl_GetTouchPointCount}, + {"SetGesturesEnabled", rl_SetGesturesEnabled}, + {"IsGestureDetected", rl_IsGestureDetected}, + {"GetGestureDetected", rl_GetGestureDetected}, + {"GetGestureHoldDuration", rl_GetGestureHoldDuration}, + {"GetGestureDragVector", rl_GetGestureDragVector}, + {"GetGestureDragAngle", rl_GetGestureDragAngle}, + {"GetGesturePinchVector", rl_GetGesturePinchVector}, + {"GetGesturePinchAngle", rl_GetGesturePinchAngle}, + {"UpdateCamera", rl_UpdateCamera}, + {"UpdateCameraPro", rl_UpdateCameraPro}, + {"SetShapesTexture", rl_SetShapesTexture}, + {"GetShapesTexture", rl_GetShapesTexture}, + {"GetShapesTextureRectangle", rl_GetShapesTextureRectangle}, + {"DrawPixel", rl_DrawPixel}, + {"DrawPixelV", rl_DrawPixelV}, + {"DrawLine", rl_DrawLine}, + {"DrawLineV", rl_DrawLineV}, + {"DrawLineEx", rl_DrawLineEx}, + {"DrawLineStrip", rl_DrawLineStrip}, + {"DrawLineBezier", rl_DrawLineBezier}, + {"DrawLineDashed", rl_DrawLineDashed}, + {"DrawCircle", rl_DrawCircle}, + {"DrawCircleV", rl_DrawCircleV}, + {"DrawCircleGradient", rl_DrawCircleGradient}, + {"DrawCircleSector", rl_DrawCircleSector}, + {"DrawCircleSectorLines", rl_DrawCircleSectorLines}, + {"DrawCircleLines", rl_DrawCircleLines}, + {"DrawCircleLinesV", rl_DrawCircleLinesV}, + {"DrawEllipse", rl_DrawEllipse}, + {"DrawEllipseV", rl_DrawEllipseV}, + {"DrawEllipseLines", rl_DrawEllipseLines}, + {"DrawEllipseLinesV", rl_DrawEllipseLinesV}, + {"DrawRing", rl_DrawRing}, + {"DrawRingLines", rl_DrawRingLines}, + {"DrawRectangle", rl_DrawRectangle}, + {"DrawRectangleV", rl_DrawRectangleV}, + {"DrawRectangleRec", rl_DrawRectangleRec}, + {"DrawRectanglePro", rl_DrawRectanglePro}, + {"DrawRectangleGradientV", rl_DrawRectangleGradientV}, + {"DrawRectangleGradientH", rl_DrawRectangleGradientH}, + {"DrawRectangleGradientEx", rl_DrawRectangleGradientEx}, + {"DrawRectangleLines", rl_DrawRectangleLines}, + {"DrawRectangleLinesEx", rl_DrawRectangleLinesEx}, + {"DrawRectangleRounded", rl_DrawRectangleRounded}, + {"DrawRectangleRoundedLines", rl_DrawRectangleRoundedLines}, + {"DrawRectangleRoundedLinesEx", rl_DrawRectangleRoundedLinesEx}, + {"DrawTriangle", rl_DrawTriangle}, + {"DrawTriangleLines", rl_DrawTriangleLines}, + {"DrawTriangleFan", rl_DrawTriangleFan}, + {"DrawTriangleStrip", rl_DrawTriangleStrip}, + {"DrawPoly", rl_DrawPoly}, + {"DrawPolyLines", rl_DrawPolyLines}, + {"DrawPolyLinesEx", rl_DrawPolyLinesEx}, + {"DrawSplineLinear", rl_DrawSplineLinear}, + {"DrawSplineBasis", rl_DrawSplineBasis}, + {"DrawSplineCatmullRom", rl_DrawSplineCatmullRom}, + {"DrawSplineBezierQuadratic", rl_DrawSplineBezierQuadratic}, + {"DrawSplineBezierCubic", rl_DrawSplineBezierCubic}, + {"DrawSplineSegmentLinear", rl_DrawSplineSegmentLinear}, + {"DrawSplineSegmentBasis", rl_DrawSplineSegmentBasis}, + {"DrawSplineSegmentCatmullRom", rl_DrawSplineSegmentCatmullRom}, + {"DrawSplineSegmentBezierQuadratic", rl_DrawSplineSegmentBezierQuadratic}, + {"DrawSplineSegmentBezierCubic", rl_DrawSplineSegmentBezierCubic}, + {"GetSplinePointLinear", rl_GetSplinePointLinear}, + {"GetSplinePointBasis", rl_GetSplinePointBasis}, + {"GetSplinePointCatmullRom", rl_GetSplinePointCatmullRom}, + {"GetSplinePointBezierQuad", rl_GetSplinePointBezierQuad}, + {"GetSplinePointBezierCubic", rl_GetSplinePointBezierCubic}, + {"CheckCollisionRecs", rl_CheckCollisionRecs}, + {"CheckCollisionCircles", rl_CheckCollisionCircles}, + {"CheckCollisionCircleRec", rl_CheckCollisionCircleRec}, + {"CheckCollisionCircleLine", rl_CheckCollisionCircleLine}, + {"CheckCollisionPointRec", rl_CheckCollisionPointRec}, + {"CheckCollisionPointCircle", rl_CheckCollisionPointCircle}, + {"CheckCollisionPointTriangle", rl_CheckCollisionPointTriangle}, + {"CheckCollisionPointLine", rl_CheckCollisionPointLine}, + {"CheckCollisionPointPoly", rl_CheckCollisionPointPoly}, + {"CheckCollisionLines", rl_CheckCollisionLines}, + {"GetCollisionRec", rl_GetCollisionRec}, + {"LoadImage", rl_LoadImage}, + {"LoadImageRaw", rl_LoadImageRaw}, + {"LoadImageAnim", rl_LoadImageAnim}, + {"LoadImageAnimFromMemory", rl_LoadImageAnimFromMemory}, + {"LoadImageFromMemory", rl_LoadImageFromMemory}, + {"LoadImageFromTexture", rl_LoadImageFromTexture}, + {"LoadImageFromScreen", rl_LoadImageFromScreen}, + {"IsImageValid", rl_IsImageValid}, + {"UnloadImage", rl_UnloadImage}, + {"ExportImage", rl_ExportImage}, + {"ExportImageToMemory", rl_ExportImageToMemory}, + {"ExportImageAsCode", rl_ExportImageAsCode}, + {"GenImageColor", rl_GenImageColor}, + {"GenImageGradientLinear", rl_GenImageGradientLinear}, + {"GenImageGradientRadial", rl_GenImageGradientRadial}, + {"GenImageGradientSquare", rl_GenImageGradientSquare}, + {"GenImageChecked", rl_GenImageChecked}, + {"GenImageWhiteNoise", rl_GenImageWhiteNoise}, + {"GenImagePerlinNoise", rl_GenImagePerlinNoise}, + {"GenImageCellular", rl_GenImageCellular}, + {"GenImageText", rl_GenImageText}, + {"ImageCopy", rl_ImageCopy}, + {"ImageFromImage", rl_ImageFromImage}, + {"ImageFromChannel", rl_ImageFromChannel}, + {"ImageText", rl_ImageText}, + {"ImageTextEx", rl_ImageTextEx}, + {"ImageFormat", rl_ImageFormat}, + {"ImageToPOT", rl_ImageToPOT}, + {"ImageCrop", rl_ImageCrop}, + {"ImageAlphaCrop", rl_ImageAlphaCrop}, + {"ImageAlphaClear", rl_ImageAlphaClear}, + {"ImageAlphaMask", rl_ImageAlphaMask}, + {"ImageAlphaPremultiply", rl_ImageAlphaPremultiply}, + {"ImageBlurGaussian", rl_ImageBlurGaussian}, + {"ImageKernelConvolution", rl_ImageKernelConvolution}, + {"ImageResize", rl_ImageResize}, + {"ImageResizeNN", rl_ImageResizeNN}, + {"ImageResizeCanvas", rl_ImageResizeCanvas}, + {"ImageMipmaps", rl_ImageMipmaps}, + {"ImageDither", rl_ImageDither}, + {"ImageFlipVertical", rl_ImageFlipVertical}, + {"ImageFlipHorizontal", rl_ImageFlipHorizontal}, + {"ImageRotate", rl_ImageRotate}, + {"ImageRotateCW", rl_ImageRotateCW}, + {"ImageRotateCCW", rl_ImageRotateCCW}, + {"ImageColorTint", rl_ImageColorTint}, + {"ImageColorInvert", rl_ImageColorInvert}, + {"ImageColorGrayscale", rl_ImageColorGrayscale}, + {"ImageColorContrast", rl_ImageColorContrast}, + {"ImageColorBrightness", rl_ImageColorBrightness}, + {"ImageColorReplace", rl_ImageColorReplace}, + {"LoadImageColors", rl_LoadImageColors}, + {"LoadImagePalette", rl_LoadImagePalette}, + {"UnloadImageColors", rl_UnloadImageColors}, + {"UnloadImagePalette", rl_UnloadImagePalette}, + {"GetImageAlphaBorder", rl_GetImageAlphaBorder}, + {"GetImageColor", rl_GetImageColor}, + {"ImageClearBackground", rl_ImageClearBackground}, + {"ImageDrawPixel", rl_ImageDrawPixel}, + {"ImageDrawPixelV", rl_ImageDrawPixelV}, + {"ImageDrawLine", rl_ImageDrawLine}, + {"ImageDrawLineV", rl_ImageDrawLineV}, + {"ImageDrawLineEx", rl_ImageDrawLineEx}, + {"ImageDrawCircle", rl_ImageDrawCircle}, + {"ImageDrawCircleV", rl_ImageDrawCircleV}, + {"ImageDrawCircleLines", rl_ImageDrawCircleLines}, + {"ImageDrawCircleLinesV", rl_ImageDrawCircleLinesV}, + {"ImageDrawRectangle", rl_ImageDrawRectangle}, + {"ImageDrawRectangleV", rl_ImageDrawRectangleV}, + {"ImageDrawRectangleRec", rl_ImageDrawRectangleRec}, + {"ImageDrawRectangleLines", rl_ImageDrawRectangleLines}, + {"ImageDrawTriangle", rl_ImageDrawTriangle}, + {"ImageDrawTriangleEx", rl_ImageDrawTriangleEx}, + {"ImageDrawTriangleLines", rl_ImageDrawTriangleLines}, + {"ImageDrawTriangleFan", rl_ImageDrawTriangleFan}, + {"ImageDrawTriangleStrip", rl_ImageDrawTriangleStrip}, + {"ImageDraw", rl_ImageDraw}, + {"ImageDrawText", rl_ImageDrawText}, + {"ImageDrawTextEx", rl_ImageDrawTextEx}, + {"LoadTexture", rl_LoadTexture}, + {"LoadTextureFromImage", rl_LoadTextureFromImage}, + {"LoadTextureCubemap", rl_LoadTextureCubemap}, + {"LoadRenderTexture", rl_LoadRenderTexture}, + {"IsTextureValid", rl_IsTextureValid}, + {"UnloadTexture", rl_UnloadTexture}, + {"IsRenderTextureValid", rl_IsRenderTextureValid}, + {"UnloadRenderTexture", rl_UnloadRenderTexture}, + {"UpdateTexture", rl_UpdateTexture}, + {"UpdateTextureRec", rl_UpdateTextureRec}, + {"GenTextureMipmaps", rl_GenTextureMipmaps}, + {"SetTextureFilter", rl_SetTextureFilter}, + {"SetTextureWrap", rl_SetTextureWrap}, + {"DrawTexture", rl_DrawTexture}, + {"DrawTextureV", rl_DrawTextureV}, + {"DrawTextureEx", rl_DrawTextureEx}, + {"DrawTextureRec", rl_DrawTextureRec}, + {"DrawTexturePro", rl_DrawTexturePro}, + {"DrawTextureNPatch", rl_DrawTextureNPatch}, + {"ColorIsEqual", rl_ColorIsEqual}, + {"Fade", rl_Fade}, + {"ColorToInt", rl_ColorToInt}, + {"ColorNormalize", rl_ColorNormalize}, + {"ColorFromNormalized", rl_ColorFromNormalized}, + {"ColorToHSV", rl_ColorToHSV}, + {"ColorFromHSV", rl_ColorFromHSV}, + {"ColorTint", rl_ColorTint}, + {"ColorBrightness", rl_ColorBrightness}, + {"ColorContrast", rl_ColorContrast}, + {"ColorAlpha", rl_ColorAlpha}, + {"ColorAlphaBlend", rl_ColorAlphaBlend}, + {"ColorLerp", rl_ColorLerp}, + {"GetColor", rl_GetColor}, + {"GetPixelColor", rl_GetPixelColor}, + {"SetPixelColor", rl_SetPixelColor}, + {"GetPixelDataSize", rl_GetPixelDataSize}, + {"GetFontDefault", rl_GetFontDefault}, + {"LoadFont", rl_LoadFont}, + {"LoadFontEx", rl_LoadFontEx}, + {"LoadFontFromImage", rl_LoadFontFromImage}, + {"LoadFontFromMemory", rl_LoadFontFromMemory}, + {"IsFontValid", rl_IsFontValid}, + {"LoadFontData", rl_LoadFontData}, + {"GenImageFontAtlas", rl_GenImageFontAtlas}, + {"UnloadFontData", rl_UnloadFontData}, + {"UnloadFont", rl_UnloadFont}, + {"ExportFontAsCode", rl_ExportFontAsCode}, + {"DrawFPS", rl_DrawFPS}, + {"DrawText", rl_DrawText}, + {"DrawTextEx", rl_DrawTextEx}, + {"DrawTextPro", rl_DrawTextPro}, + {"DrawTextCodepoint", rl_DrawTextCodepoint}, + {"DrawTextCodepoints", rl_DrawTextCodepoints}, + {"SetTextLineSpacing", rl_SetTextLineSpacing}, + {"MeasureText", rl_MeasureText}, + {"MeasureTextEx", rl_MeasureTextEx}, + {"MeasureTextCodepoints", rl_MeasureTextCodepoints}, + {"GetGlyphIndex", rl_GetGlyphIndex}, + {"GetGlyphInfo", rl_GetGlyphInfo}, + {"GetGlyphAtlasRec", rl_GetGlyphAtlasRec}, + {"LoadUTF8", rl_LoadUTF8}, + {"UnloadUTF8", rl_UnloadUTF8}, + {"LoadCodepoints", rl_LoadCodepoints}, + {"UnloadCodepoints", rl_UnloadCodepoints}, + {"GetCodepointCount", rl_GetCodepointCount}, + {"GetCodepoint", rl_GetCodepoint}, + {"GetCodepointNext", rl_GetCodepointNext}, + {"GetCodepointPrevious", rl_GetCodepointPrevious}, + {"CodepointToUTF8", rl_CodepointToUTF8}, + {"LoadTextLines", rl_LoadTextLines}, + {"UnloadTextLines", rl_UnloadTextLines}, + {"TextCopy", rl_TextCopy}, + {"TextIsEqual", rl_TextIsEqual}, + {"TextLength", rl_TextLength}, + {"TextFormat", rl_TextFormat}, + {"TextSubtext", rl_TextSubtext}, + {"TextRemoveSpaces", rl_TextRemoveSpaces}, + {"GetTextBetween", rl_GetTextBetween}, + {"TextReplace", rl_TextReplace}, + {"TextReplaceAlloc", rl_TextReplaceAlloc}, + {"TextReplaceBetween", rl_TextReplaceBetween}, + {"TextReplaceBetweenAlloc", rl_TextReplaceBetweenAlloc}, + {"TextInsert", rl_TextInsert}, + {"TextInsertAlloc", rl_TextInsertAlloc}, + {"TextJoin", rl_TextJoin}, + {"TextSplit", rl_TextSplit}, + {"TextAppend", rl_TextAppend}, + {"TextFindIndex", rl_TextFindIndex}, + {"TextToUpper", rl_TextToUpper}, + {"TextToLower", rl_TextToLower}, + {"TextToPascal", rl_TextToPascal}, + {"TextToSnake", rl_TextToSnake}, + {"TextToCamel", rl_TextToCamel}, + {"TextToInteger", rl_TextToInteger}, + {"TextToFloat", rl_TextToFloat}, + {"DrawLine3D", rl_DrawLine3D}, + {"DrawPoint3D", rl_DrawPoint3D}, + {"DrawCircle3D", rl_DrawCircle3D}, + {"DrawTriangle3D", rl_DrawTriangle3D}, + {"DrawTriangleStrip3D", rl_DrawTriangleStrip3D}, + {"DrawCube", rl_DrawCube}, + {"DrawCubeV", rl_DrawCubeV}, + {"DrawCubeWires", rl_DrawCubeWires}, + {"DrawCubeWiresV", rl_DrawCubeWiresV}, + {"DrawSphere", rl_DrawSphere}, + {"DrawSphereEx", rl_DrawSphereEx}, + {"DrawSphereWires", rl_DrawSphereWires}, + {"DrawCylinder", rl_DrawCylinder}, + {"DrawCylinderEx", rl_DrawCylinderEx}, + {"DrawCylinderWires", rl_DrawCylinderWires}, + {"DrawCylinderWiresEx", rl_DrawCylinderWiresEx}, + {"DrawCapsule", rl_DrawCapsule}, + {"DrawCapsuleWires", rl_DrawCapsuleWires}, + {"DrawPlane", rl_DrawPlane}, + {"DrawRay", rl_DrawRay}, + {"DrawGrid", rl_DrawGrid}, + {"LoadModel", rl_LoadModel}, + {"LoadModelFromMesh", rl_LoadModelFromMesh}, + {"IsModelValid", rl_IsModelValid}, + {"UnloadModel", rl_UnloadModel}, + {"GetModelBoundingBox", rl_GetModelBoundingBox}, + {"DrawModel", rl_DrawModel}, + {"DrawModelEx", rl_DrawModelEx}, + {"DrawModelWires", rl_DrawModelWires}, + {"DrawModelWiresEx", rl_DrawModelWiresEx}, + {"DrawBoundingBox", rl_DrawBoundingBox}, + {"DrawBillboard", rl_DrawBillboard}, + {"DrawBillboardRec", rl_DrawBillboardRec}, + {"DrawBillboardPro", rl_DrawBillboardPro}, + {"UploadMesh", rl_UploadMesh}, + {"UpdateMeshBuffer", rl_UpdateMeshBuffer}, + {"UnloadMesh", rl_UnloadMesh}, + {"DrawMesh", rl_DrawMesh}, + {"DrawMeshInstanced", rl_DrawMeshInstanced}, + {"GetMeshBoundingBox", rl_GetMeshBoundingBox}, + {"GenMeshTangents", rl_GenMeshTangents}, + {"ExportMesh", rl_ExportMesh}, + {"ExportMeshAsCode", rl_ExportMeshAsCode}, + {"GenMeshPoly", rl_GenMeshPoly}, + {"GenMeshPlane", rl_GenMeshPlane}, + {"GenMeshCube", rl_GenMeshCube}, + {"GenMeshSphere", rl_GenMeshSphere}, + {"GenMeshHemiSphere", rl_GenMeshHemiSphere}, + {"GenMeshCylinder", rl_GenMeshCylinder}, + {"GenMeshCone", rl_GenMeshCone}, + {"GenMeshTorus", rl_GenMeshTorus}, + {"GenMeshKnot", rl_GenMeshKnot}, + {"GenMeshHeightmap", rl_GenMeshHeightmap}, + {"GenMeshCubicmap", rl_GenMeshCubicmap}, + {"LoadMaterials", rl_LoadMaterials}, + {"LoadMaterialDefault", rl_LoadMaterialDefault}, + {"IsMaterialValid", rl_IsMaterialValid}, + {"UnloadMaterial", rl_UnloadMaterial}, + {"SetMaterialTexture", rl_SetMaterialTexture}, + {"SetModelMeshMaterial", rl_SetModelMeshMaterial}, + {"LoadModelAnimations", rl_LoadModelAnimations}, + {"UpdateModelAnimation", rl_UpdateModelAnimation}, + {"UpdateModelAnimationEx", rl_UpdateModelAnimationEx}, + {"UnloadModelAnimations", rl_UnloadModelAnimations}, + {"IsModelAnimationValid", rl_IsModelAnimationValid}, + {"CheckCollisionSpheres", rl_CheckCollisionSpheres}, + {"CheckCollisionBoxes", rl_CheckCollisionBoxes}, + {"CheckCollisionBoxSphere", rl_CheckCollisionBoxSphere}, + {"GetRayCollisionSphere", rl_GetRayCollisionSphere}, + {"GetRayCollisionBox", rl_GetRayCollisionBox}, + {"GetRayCollisionMesh", rl_GetRayCollisionMesh}, + {"GetRayCollisionTriangle", rl_GetRayCollisionTriangle}, + {"GetRayCollisionQuad", rl_GetRayCollisionQuad}, + {"InitAudioDevice", rl_InitAudioDevice}, + {"CloseAudioDevice", rl_CloseAudioDevice}, + {"IsAudioDeviceReady", rl_IsAudioDeviceReady}, + {"SetMasterVolume", rl_SetMasterVolume}, + {"GetMasterVolume", rl_GetMasterVolume}, + {"LoadWave", rl_LoadWave}, + {"LoadWaveFromMemory", rl_LoadWaveFromMemory}, + {"IsWaveValid", rl_IsWaveValid}, + {"LoadSound", rl_LoadSound}, + {"LoadSoundFromWave", rl_LoadSoundFromWave}, + {"LoadSoundAlias", rl_LoadSoundAlias}, + {"IsSoundValid", rl_IsSoundValid}, + {"UpdateSound", rl_UpdateSound}, + {"UnloadWave", rl_UnloadWave}, + {"UnloadSound", rl_UnloadSound}, + {"UnloadSoundAlias", rl_UnloadSoundAlias}, + {"ExportWave", rl_ExportWave}, + {"ExportWaveAsCode", rl_ExportWaveAsCode}, + {"PlaySound", rl_PlaySound}, + {"StopSound", rl_StopSound}, + {"PauseSound", rl_PauseSound}, + {"ResumeSound", rl_ResumeSound}, + {"IsSoundPlaying", rl_IsSoundPlaying}, + {"SetSoundVolume", rl_SetSoundVolume}, + {"SetSoundPitch", rl_SetSoundPitch}, + {"SetSoundPan", rl_SetSoundPan}, + {"WaveCopy", rl_WaveCopy}, + {"WaveCrop", rl_WaveCrop}, + {"WaveFormat", rl_WaveFormat}, + {"LoadWaveSamples", rl_LoadWaveSamples}, + {"UnloadWaveSamples", rl_UnloadWaveSamples}, + {"LoadMusicStream", rl_LoadMusicStream}, + {"LoadMusicStreamFromMemory", rl_LoadMusicStreamFromMemory}, + {"IsMusicValid", rl_IsMusicValid}, + {"UnloadMusicStream", rl_UnloadMusicStream}, + {"PlayMusicStream", rl_PlayMusicStream}, + {"IsMusicStreamPlaying", rl_IsMusicStreamPlaying}, + {"UpdateMusicStream", rl_UpdateMusicStream}, + {"StopMusicStream", rl_StopMusicStream}, + {"PauseMusicStream", rl_PauseMusicStream}, + {"ResumeMusicStream", rl_ResumeMusicStream}, + {"SeekMusicStream", rl_SeekMusicStream}, + {"SetMusicVolume", rl_SetMusicVolume}, + {"SetMusicPitch", rl_SetMusicPitch}, + {"SetMusicPan", rl_SetMusicPan}, + {"GetMusicTimeLength", rl_GetMusicTimeLength}, + {"GetMusicTimePlayed", rl_GetMusicTimePlayed}, + {"LoadAudioStream", rl_LoadAudioStream}, + {"IsAudioStreamValid", rl_IsAudioStreamValid}, + {"UnloadAudioStream", rl_UnloadAudioStream}, + {"UpdateAudioStream", rl_UpdateAudioStream}, + {"IsAudioStreamProcessed", rl_IsAudioStreamProcessed}, + {"PlayAudioStream", rl_PlayAudioStream}, + {"PauseAudioStream", rl_PauseAudioStream}, + {"ResumeAudioStream", rl_ResumeAudioStream}, + {"IsAudioStreamPlaying", rl_IsAudioStreamPlaying}, + {"StopAudioStream", rl_StopAudioStream}, + {"SetAudioStreamVolume", rl_SetAudioStreamVolume}, + {"SetAudioStreamPitch", rl_SetAudioStreamPitch}, + {"SetAudioStreamPan", rl_SetAudioStreamPan}, + {"SetAudioStreamBufferSizeDefault", rl_SetAudioStreamBufferSizeDefault}, + {"SetAudioStreamCallback", rl_SetAudioStreamCallback}, + {"AttachAudioStreamProcessor", rl_AttachAudioStreamProcessor}, + {"DetachAudioStreamProcessor", rl_DetachAudioStreamProcessor}, + {"AttachAudioMixedProcessor", rl_AttachAudioMixedProcessor}, + {"DetachAudioMixedProcessor", rl_DetachAudioMixedProcessor}, + {"GetMouseRay", rl_GetScreenToWorldRay}, + + { NULL, NULL } // sentinel +}; -// Execute raylib Lua script -RLUADEF void rLuaExecuteFile(const char *filename) -{ - if (!mainLuaState) - { - TraceLog(WARNING, "Lua device not initialized"); - return; - } +RLUADEF lua_State *rlua_open(void) { + lua_State *L = luaL_newstate(); + luaL_openlibs(L); + + RLUA_State = L; + rLuaRegisterMetatables(L); + +#ifdef RAYLIB_STRIP_PREFIX + // Register functions as globals + lua_pushglobaltable(L); + luaL_setfuncs(L, raylib_functions, 0); + lua_pop(L, 1); + + // Register constants as globals + lua_pushglobaltable(L); + rLuaRegisterConstants(L); + lua_pop(L, 1); + + // rl table mirrors globals via __index = _G + lua_newtable(L); + lua_newtable(L); + lua_pushglobaltable(L); + lua_setfield(L, -2, "__index"); + lua_setmetatable(L, -2); + lua_setglobal(L, "rl"); +#else + lua_newtable(L); + rLuaRegisterConstants(L); + luaL_setfuncs(L, raylib_functions, 0); + lua_setglobal(L, "rl"); +#endif - int result = luaL_dofile(L, filename); + return L; +} - switch (result) - { - case LUA_OK: break; - case LUA_ERRRUN: TraceLog(ERROR, "Lua Runtime Error: %s", lua_tostring(L, -1)); - case LUA_ERRMEM: TraceLog(ERROR, "Lua Memory Error: %s", lua_tostring(L, -1)); - default: TraceLog(ERROR, "Lua Error: %s", lua_tostring(L, -1)); +RLUADEF void rlua_close(lua_State *L) { + if (RLUA_LogRef != LUA_REFNIL) { + luaL_unref(L, LUA_REGISTRYINDEX, RLUA_LogRef); + RLUA_LogRef = LUA_REFNIL; } + RLUA_State = NULL; + lua_close(L); } -#endif // RLUA_IMPLEMENTATION + +#endif diff --git a/tools/rLuaLauncher/rlualauncher.c b/tools/rLuaLauncher/rlualauncher.c index 1a8d776..bb73798 100644 --- a/tools/rLuaLauncher/rlualauncher.c +++ b/tools/rLuaLauncher/rlualauncher.c @@ -1,26 +1,30 @@ /******************************************************************************************* * -* rLuaLauncher v1.1 - raylib Lua Launcher +* rlualauncher v2.0 - raylib Lua Launcher * * DEPENDENCIES: * -* raylib 2.0 - This program uses latest raylib version (www.raylib.com) -* Lua 5.3.3 - http://luabinaries.sourceforge.net/download.html +* raylib 6.0 - This program uses latest raylib version (www.raylib.com) +* Lua 5.5 - https://luabinaries.sourceforge.net/download.html * -* COMPILATION (GCC): +* COMPILATION: * -* gcc -o rlualauncher.exe rlualauncher.c -s rlualauncher.rc.o -I. -Iexternal/lua/include \ -* -Lexternal/lua/lib -lraylib -lopengl32 -lgdi32 -llua53 -std=c99 -Wall -Wl,--subsystem,windows +* ./build.lua # X11 (default) +* CFLAGS="-D_GLFW_WAYLAND" ./build.lua # Wayland * * USAGE: * -* Just launch your raylib .lua file from command line: rll.exe core_basic_window.lua -* or drag&drop your .lua file over rll.exe +* Just launch your raylib .lua file from the command line: * +* ./build/rLuaLauncher core_basic_window.lua +* +* NOTE: Windows is not currently supported. +* TODO: The original had drag-and-drop support. * * LICENSE: zlib/libpng * * Copyright (c) 2016-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2026 yilisharcs * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -49,106 +53,27 @@ //------------------------------------------------------------------------------------ int main(int argc, char *argv[]) { - if (argc > 1) + const char *entryLua = (argc > 1) ? argv[1] : "main.lua"; + + if (argc > 2) { - // TODO: Support additional arguments for lua file execution - - if (IsFileExtension(argv[1], ".lua")) - { - rLuaInitDevice(); // Initialize lua device - rLuaExecuteFile(argv[1]); // Execute lua program (argument file) - rLuaCloseDevice(); // Close Lua device and free resources - } + TraceLog(LOG_WARNING, "Too many arguments provided"); + TraceLog(LOG_INFO, "Usage: %s [script.lua] (defaults to main.lua)", argv[0]); + return 1; } - else - { - bool launcherShouldClose = false; - - while (!launcherShouldClose) - { - // Initialization - //-------------------------------------------------------------------------------------- - int screenWidth = 800; - int screenHeight = 450; - InitWindow(screenWidth, screenHeight, "rLL - raylib Lua Launcher"); - - // NOTE: Drag and drop support only available for desktop platforms: Windows, Linux, OSX - int count = 0; - char **droppedFiles; - char luaFileToLoad[256]; - - bool runLuaFile = false; - - SetTargetFPS(60); - //-------------------------------------------------------------------------------------- - - while (!WindowShouldClose() && !runLuaFile) - { - // Update - //---------------------------------------------------------------------------------- + lua_State *L = rlua_open(); + if (L == NULL) { + TraceLog(LOG_ERROR, "LUA: Failed to initialize Lua state"); + return 1; + } - // Load a dropped Lua file dynamically - if (IsFileDropped()) - { - droppedFiles = GetDroppedFiles(&count); - - if (count == 1) // Only support one Lua file dropped - { - if (IsFileExtension(droppedFiles[0], ".lua")) - { - runLuaFile = true; - strcpy(luaFileToLoad, droppedFiles[0]); - } - else TraceLog(WARNING, "[%s] Fileformat not supported", droppedFiles[0]); - } - - ClearDroppedFiles(); - } - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - BeginDrawing(); - - ClearBackground(RAYWHITE); - - DrawText("rLL - raylib Lua launcher", 10, 10, 20, LIGHTGRAY); - DrawText("rLL v1.1", 10, 430, 10, GRAY); - DrawText("< drag & drop raylib Lua file here >", 230, 180, 20, GRAY); - - EndDrawing(); - //---------------------------------------------------------------------------------- - } - - // De-Initialization - //-------------------------------------------------------------------------------------- - ClearDroppedFiles(); // Clear internal buffers - - CloseWindow(); // Close window and OpenGL context - //-------------------------------------------------------------------------------------- - - launcherShouldClose = true; // Close launcher if no Lua file loaded - - if (runLuaFile) - { - TraceLog(INFO, "------------------------------------"); - TraceLog(INFO, "Loading Lua file: %s", luaFileToLoad); - TraceLog(INFO, "------------------------------------"); - - rLuaInitDevice(); // Initialize lua device - ChangeDirectory(GetDirectoryPath(luaFileToLoad)); - rLuaExecuteFile(luaFileToLoad); - rLuaCloseDevice(); // Close Lua device and free resources - - launcherShouldClose = false; // Return to launcher to load another Lua file - - TraceLog(INFO, "------------------------------------"); - TraceLog(INFO, "Closing Lua file..."); - TraceLog(INFO, "------------------------------------"); - } - } + if (luaL_dofile(L, entryLua) != LUA_OK) { + TraceLog(LOG_ERROR, "LUA: %s", lua_tostring(L, -1)); + rlua_close(L); + return 1; } + rlua_close(L); return 0; } diff --git a/tools/rLuaParser/rluaparser.c b/tools/rLuaParser/rluaparser.c index 1521fa8..e69de29 100644 --- a/tools/rLuaParser/rluaparser.c +++ b/tools/rLuaParser/rluaparser.c @@ -1,287 +0,0 @@ -/********************************************************************************************** - - rluaparser - raylib header parser to generate automatic Lua binding - - This parser scans raylib.h for functions that start with RLAPI and - generates raylib-lua function binding. - - Converts: - RLAPI Color Fade(Color color, float alpha); // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f - - To: - // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f - int lua_Fade(lua_State* L) - { - Color arg1 = LuaGetArgument_Color(L, 1); - float arg2 = LuaGetArgument_float(L, 2); - Color result = Fade(arg1, arg2); - LuaPush_Color(L, result); - return 1; - } - - Requirements to create binding raylib -> raylib-lua - NOTE: "Type" refers to raylib defined structs (Vector2, Texture2D...) - [ ] 1. Review LuaPush_Type defines/functions - [ ] 2. Review LuaGetArgument_Type defines/functions - [ ] 3. Review LuaIndexType functions (some raylib structs have changed) - [ ] 4. Review lua_Type functions (raylib Lua structure constructors) - [x] 5. Review function bindings (90% of raylib-lua.h code) --> DONE by this PARSER! - NOTE: Some functions could require specific reviews - [ ] 6. Review registered raylib lua functions --> REG() - [ ] 7. Review enumerators setup on InitLuaDevice() - - LICENSE: zlib/libpng - - Copyright (c) 2018 Ramon Santamaria (@raysan5) - -**********************************************************************************************/ - -#include -#include -#include -#include - -int main() -{ - #define MAX_BUFFER_SIZE 512 - - FILE *rFile = fopen("raylib_test.h", "rt"); - FILE *rluaFile = fopen("raylib-lua_test.h", "wt"); - - if ((rFile == NULL) || (rluaFile == NULL)) - { - printf("File could not be opened.\n"); - return 0; - } - - char *buffer = (char *)calloc(MAX_BUFFER_SIZE, 1); - - char *luaPushFuncs = (char *)calloc(1024*512, 1); // 512 KB - char *luaPushPtr = luaPushFuncs; - - char *luaREG = (char *)calloc(1024*256, 1); // 256 KB - char *luaREGPtr = luaREG; - - int funcsCount = 0; - - while (!feof(rFile)) - { - // Read one full line - fgets(buffer, MAX_BUFFER_SIZE, rFile); - - if (buffer[0] == '/') fprintf(rluaFile, "%s", buffer); // Direct copy of code comments - else if (strncmp(buffer, "RLAPI", 5) == 0) // raylib function declaration - { - char funcType[64]; - char funcTypeAux[64]; - char funcName[64]; - char funcDesc[256]; - - char params[128]; - char paramType[8][16]; - char paramName[8][32]; - - sscanf(buffer, "RLAPI %s %[^(]s", funcType, funcName); - - if (strcmp(funcType, "const") == 0) - { - sscanf(buffer, "RLAPI %s %s %[^(]s", funcType, funcTypeAux, funcName); - strcpy(funcType, "string"); - } - - if ((funcName[0] == '*') && (funcName[1] == '*')) strcpy(funcName, funcName + 2); - else if (funcName[0] == '*') strcpy(funcName, funcName + 1); - - int index = 0; - char *ptr = NULL; - - ptr = strchr(buffer, '('); - - if (ptr != NULL) index = (int)(ptr - buffer); - else printf("Character not found!\n"); - - sscanf(buffer + (index + 1), "%[^)]s", params); // Read what's inside '(' and ')' <-- CRASH after 128 iterations! - - ptr = strchr(buffer, '/'); - index = (int)(ptr - buffer); - - sscanf(buffer + index, "%[^\n]s", funcDesc); // Read function comment after declaration - - // Generate Lua function lua_FuncName() - //--------------------------------------- - fprintf(rluaFile, "%s\n", funcDesc); - - fprintf(rluaFile, "int lua_%s(lua_State *L)\n{\n", funcName); - - // Scan params string for number of func params, type and name - char *paramPtr[16]; // Allocate 16 pointers for possible parameters - int paramsCount = 0; - paramPtr[paramsCount] = strtok(params, ","); - - bool funcVoid = (strcmp(funcType, "void") == 0); - bool paramsVoid = false; - char paramConst[8][16]; - - int len = 0; - - while (paramPtr[paramsCount] != NULL) - { - sscanf(paramPtr[paramsCount], "%s %s\n", paramType[paramsCount], paramName[paramsCount]); - - if (paramName[paramsCount][0] == '*') strcpy(paramName[paramsCount], paramName[paramsCount] + 1); - - if (strcmp(paramType[paramsCount], "void") == 0) - { - paramsVoid = true; - break; - } - - if (strcmp(paramType[paramsCount], "const") == 0) - { - sscanf(paramPtr[paramsCount], "%s %s %s\n", paramConst[paramsCount], paramType[paramsCount], paramName[paramsCount]); - - if (paramName[paramsCount][0] == '*') strcpy(paramName[paramsCount], paramName[paramsCount] + 1); - - fprintf(rluaFile, " %s %s %s = LuaGetArgument_%s(L, %i);\n", paramConst[paramsCount], paramType[paramsCount], paramName[paramsCount], (strcmp(paramType[paramsCount], "char") == 0) ? "string" : paramType[paramsCount], paramsCount + 1); - } - else if (strcmp(paramType[paramsCount], "unsigned") == 0) - { - sscanf(paramPtr[paramsCount], "%s %s %s\n", paramConst[paramsCount], paramType[paramsCount], paramName[paramsCount]); - - if (paramName[paramsCount][0] == '*') strcpy(paramName[paramsCount], paramName[paramsCount] + 1); - - fprintf(rluaFile, " %s %s %s = LuaGetArgument_%s(L, %i);\n", paramConst[paramsCount], paramType[paramsCount], paramName[paramsCount], paramConst[paramsCount], paramsCount + 1); - } - //else if (strcmp(paramType[paramsCount], "...") == 0) - else fprintf(rluaFile, " %s %s = LuaGetArgument_%s(L, %i);\n", paramType[paramsCount], paramName[paramsCount], paramType[paramsCount], paramsCount + 1); - - paramsCount++; - paramPtr[paramsCount] = strtok(NULL, ","); - } - - if (funcVoid) fprintf(rluaFile, " %s(", funcName); - else fprintf(rluaFile, " %s result = %s(", funcType, funcName); - - if (!paramsVoid) - { - for (int i = 0; i < paramsCount - 1; i++) fprintf(rluaFile, "%s, ", paramName[i]); - fprintf(rluaFile, "%s", paramName[paramsCount - 1]); - } - - fprintf(rluaFile, ");\n"); - - if (!funcVoid) fprintf(rluaFile, " LuaPush_%s(L, result);\n", funcType); - - fprintf(rluaFile, " return %i;\n}\n\n", funcVoid ? 0:1); - - fflush(rluaFile); - - funcsCount++; - printf("Function processed %02i: %s\n", funcsCount, funcName); - - memset(buffer, 0, MAX_BUFFER_SIZE); - - // Register function names REG() into luaREG string - //-------------------------------------------------- - len += sprintf(luaREGPtr + len, " REG(%s)\n", funcName); - luaREGPtr += len; - - } - else if (strncmp(buffer, "typedef", 7) == 0) // raylib data type definition - { - char typeName[64]; - char typeDesc[256]; - - int paramsCount = 0; - char paramTypes[16][32] = {{ 0 }}; - char paramNames[16][32] = {{ 0 }}; - char paramDescs[16][128] = {{ 0 }}; - - if (strncmp(buffer + 8, "struct", 6) == 0) - { - - - sscanf(buffer, "typedef struct %s {", typeName); - - fgets(buffer, MAX_BUFFER_SIZE, rFile); // Read one new full line - - while (buffer[0] != '}') // Not closing structure type - { - if (buffer[0] != '\n') - { - sscanf(buffer, " %s %[^;]s %[^\n]s", ¶mTypes[paramsCount][0], ¶mNames[paramsCount][0], ¶mDescs[paramsCount][0]); - paramsCount++; - } - - fgets(buffer, MAX_BUFFER_SIZE, rFile); // Read one new full line - } - - // Generate LuaGetArgument functions - //----------------------------------- - fprintf(rluaFile, "static %s LuaGetArgument_%s(lua_State *L, int index)\n{\n", typeName, typeName); - fprintf(rluaFile, " %s result = { 0 };\n", typeName); - fprintf(rluaFile, " index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values\n"); - for (int i = 0; i < paramsCount; i++) - { - // TODO: Consider different types (LUA_TNUMBER, LUA_TTABLE) - fprintf(rluaFile, " luaL_argcheck(L, lua_getfield(L, index, \"%s\") == LUA_TNUMBER, index, \"Expected %s.%s\");\n", paramNames[i], typeName, paramNames[i]); - - // TODO: Consider different data types (lua_tonumber, LuaGetArgument_Vector3) - fprintf(rluaFile, " result.%s = LuaGetArgument_%s(L, -1);\n", paramNames[i], paramTypes[i]); - } - fprintf(rluaFile, " lua_pop(L, %i);\n", paramsCount); - fprintf(rluaFile, " return result;\n}\n\n"); - - // Generate LuaPush functions - // NOTE: LuaPush functions are written in a separate string buffer, that will be written to file at the end - //----------------------------------- - int len = 0; - len += sprintf(luaPushPtr + len, "static void LuaPush_%s(lua_State* L, %s obj)\n{\n", typeName, typeName); - len += sprintf(luaPushPtr + len, " lua_createtable(L, 0, %i);\n", paramsCount); - for (int i = 0; i < paramsCount; i++) - { - len += sprintf(luaPushPtr + len, " LuaPush_%s(L, obj.%s);\n", paramTypes[i], (paramNames[i][0] == '*') ? (paramNames[i] + 1) : paramNames[i]); - len += sprintf(luaPushPtr + len, " lua_setfield(L, -2, \"%s\");\n", paramNames[i]); - } - len += sprintf(luaPushPtr + len, "}\n\n"); - - luaPushPtr += len; - } - else if (strncmp(buffer + 8, "enum", 4) == 0) - { - //sscanf(buffer, "typedef enum {"); - //printf("enum detected!\n"); - - fgets(buffer, MAX_BUFFER_SIZE, rFile); // Read one new full line - fprintf(rluaFile, "LuaStartEnum();\n"); - - while (buffer[0] != '}') // Not closing structure type - { - if (buffer[0] != '\n') - { - sscanf(buffer, " %s", ¶mNames[paramsCount][0]); - fprintf(rluaFile, "LuaSetEnum(\"%s\", %s);\n", ¶mNames[paramsCount][0], ¶mNames[paramsCount][0]); - paramsCount++; - } - - fgets(buffer, MAX_BUFFER_SIZE, rFile); // Read one new full line - } - fprintf(rluaFile, "LuaEndEnum(\"name\");\n"); - } - } - } - - fprintf(rluaFile, "%s", luaPushFuncs); - fprintf(rluaFile, "// raylib Functions (and data types) list\nstatic luaL_Reg raylib_functions[] = {\n"); - fprintf(rluaFile, "%s\n", luaREG); - fprintf(rluaFile, " { NULL, NULL } // sentinel: end signal\n};"); - - free(buffer); - free(luaPushFuncs); - free(luaREG); - - fclose(rFile); - fclose(rluaFile); - - return 0; -} \ No newline at end of file diff --git a/tools/rLuaParser/rluaparser.lua b/tools/rLuaParser/rluaparser.lua new file mode 100755 index 0000000..9ba710d --- /dev/null +++ b/tools/rLuaParser/rluaparser.lua @@ -0,0 +1,1812 @@ +#!/usr/bin/env lua +--[[ ********************************************************************************************** + + rluaparser v6.0 - A simple raylib header parser to generate automatic Lua bindings + + FEATURES: + - Scans raylib.h to generate C binding header (raylib-lua.h) + - Generates LuaLS type annotations (_meta.lua) for full LSP support + - Hybrid type system with automatic resource management (__gc) + - Support for RAYLIB_STRIP_PREFIX global namespace toggle + + NOTES: + - Designed for raylib 6.0 and Lua 5.5 + - Resolves alias chains (e.g. Texture2D -> Texture) automatically + - TODO: Missing low-level callbacks: + - [ ] LoadFileData + - [ ] SaveFileData + - [ ] LoadFileText + - [ ] SaveFileText + - [ ] AudioCallback + - TODO: Generate type annotations for RAYLIB_STRIP_PREFIX + + DEPENDENCIES: + - Lua 5.5 (Standard library only, no external dependencies) + + USAGE: + lua rluaparser.lua [output.lua] + + LICENSE: zlib/libpng + + rluaparser is licensed under an unmodified zlib/libpng license, which is an OSI-certified, + BSD-like license that allows static linking with closed source software: + + Copyright (c) 2026 yilisharcs + + This software is provided "as-is", without any express or implied warranty. In no event + will the authors be held liable for any damages arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, including commercial + applications, and to alter it and redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not claim that you + wrote the original software. If you use this software in a product, an acknowledgment + in the product documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be misrepresented + as being the original software. + + 3. This notice may not be removed or altered from any source distribution. + +********************************************************************************************** ]] + +-- PARSER ====================================================================================== {{{ + +local Parser = {} + +function Parser.preprocess(text) + -- strip block comments + text = text:gsub("/%*.-%*/", "") + + local result, acc, line_nr = {}, {}, 0 + for raw_line in text:gmatch("([^\n]+)") do + line_nr = line_nr + 1 + local line = raw_line + + if line:match("^%s*//") then + -- standalone comment + local c = line:match("^%s*//(.+)$") + c = c and c:match("^%s*(.-)%s*$") + if c then + acc[#acc + 1] = c + end + else + -- collect trailing + local t_part, t_comment = line:match("^(.-)//(.+)$") + if t_part then + -- trim before + t_part = t_part:match("^%s*(.-)%s*$") + if #t_part > 0 then + -- trim after + local comment = t_comment:match("^%s*(.-)%s*$") + -- snapshots acc into notes, then resets + local notes = #acc > 0 and { table.unpack(acc) } or nil + acc = {} -- start fresh for next block + result[#result + 1] = { + text = t_part, + comment = comment, + notes = notes, + line = line_nr, + } + end + else + -- plain code. trim again + local trimmed = line:match("^%s*(.-)%s*$") + if #trimmed > 0 then + -- snapshots acc into notes, then resets + local notes = #acc > 0 and { table.unpack(acc) } or nil + acc = {} -- start fresh for next block + result[#result + 1] = { + text = trimmed, + notes = notes, + line = line_nr, + } + end + end + end + end + + return result +end + +-- keywords for type-name splitting +local C_KEYWORDS = { + bool = true, + char = true, + const = true, + double = true, + enum = true, + float = true, + int = true, + long = true, + short = true, + signed = true, + struct = true, + union = true, + unsigned = true, + void = true, +} + +-- split "unsigned char *name" into type="unsigned char *", name="name" +function Parser.split_type_name(s) + local tokens = {} + -- split by whitespace + for tok in s:gmatch("%S+") do + tokens[#tokens + 1] = tok + end + if #tokens == 0 then + return "", "" + end + + local name_tok = tokens[#tokens] + -- strip leading * from name, as they are pointer qualifiers on the type + local pointer_prefix = name_tok:match("^(%*+)") + if pointer_prefix then + name_tok = name_tok:sub(#pointer_prefix + 1) + end + if #name_tok == 0 or C_KEYWORDS[name_tok] then + return s, "" + end + + -- all tokens except last form the type; reattach any * prefixes + local type_tokens = {} + for i = 1, #tokens - 1 do + type_tokens[#type_tokens + 1] = tokens[i] + end + if pointer_prefix then + type_tokens[#type_tokens + 1] = pointer_prefix + end + return table.concat(type_tokens, " "), name_tok +end + +-- }}} + +-- SCANNERS ==================================================================================== {{{ +local matchers = { + -- RLAPI function declaration + { + match = function(line) + return line.text:match("^RLAPI") + end, + consume = function(lines, idx) + local line = lines[idx] + local retType, funcName, params = line.text:match("^RLAPI%s+(.-)%s*([%w_]+)%s*%((.-)%)%s*;%s*$") + if not retType then + io.stderr:write("WARN: failed to parse RLAPI: ", line.text, "\n") + return nil, 1 + end + local node = { + type = "function", + name = funcName, + retType = retType, + params = {}, + notes = line.notes, + comment = line.comment, + } + if params == "void" then + goto finalize + end + + for param in params:gmatch("[^,]+") do + local trimmed = param:match("^%s*(.-)%s*$") + if trimmed:match("^%.%.%.$") then + node.params[#node.params + 1] = { + name = "...", + isVariadic = true, + } + else + local pType, pName = Parser.split_type_name(trimmed) + node.params[#node.params + 1] = { + type = pType, + name = pName, + } + end + end + + ::finalize:: + + return node, 1 + end, + }, + -- typedef struct ... { ... } Name; + { + match = function(line) + return line.text:match("^typedef struct") and line.text:match("{") + end, + consume = function(lines, idx) + local line = lines[idx] + local structName = line.text:match("^typedef struct%s+([%w_]+)%s*{") + local fields = {} + local i = idx + 1 + while i <= #lines do + local l = lines[i] + local closeName = l.text:match("^}%s*([%w_]+)%s*;%s*$") + if closeName then + structName = structName or closeName + return { + type = "struct", + name = structName, + fields = fields, + notes = line.notes, + comment = line.comment, + }, + -- lines consumed: from typedef struct to closing } Name; + i - idx + 1 + end + local fieldText = l.text:match("^%s*(.-);%s*$") + if fieldText then + -- handle comma-separated fields like "float m0, m4, m8, m12;" + local clean = fieldText:gsub(",%s+", ",") + local fType, fNames = clean:match("^(.-)%s+([%w_,]+)%s*$") + if not fType then + fType, fNames = Parser.split_type_name(clean) + end + if fType and fNames then + for fName in fNames:gmatch("[^,]+") do + fields[#fields + 1] = { + type = fType, + name = fName, + comment = l.comment, + } + end + end + end + -- advance to next line in struct body + i = i + 1 + end + io.stderr:write("WARN: unclosed struct: ", line.text, "\n") + return nil, #lines - idx + 1 + end, + }, + -- typedef enum { ... } Name; + { + match = function(line) + return line.text:match("^typedef enum") and line.text:match("{") + end, + consume = function(lines, idx) + local line = lines[idx] + local text = line.text + local fields = {} + -- handle single-line typedef enum { a, b } Name; or typedef enum Name { a, b } Name; + local body, closeName = text:match("{(.-)}%s*([%w_]+)%s*;%s*$") + if closeName then + if closeName == "bool" then + return nil, 1 + end + for part in body:gmatch("[^,]+") do + local trimmed = part:match("^%s*(.-)%s*$") + local name, value = trimmed:match("^([%w_]+)%s*=%s*(.+)$") + if name then + fields[#fields + 1] = { name = name, value = value } + else + name = trimmed:match("^([%w_]+)%s*$") + if name then + fields[#fields + 1] = { + name = name, + value = nil, + } + end + end + end + return { + type = "enum", + name = closeName, + fields = fields, + notes = line.notes, + comment = line.comment, + }, + 1 + end + local i = idx + 1 + while i <= #lines do + local l = lines[i] + closeName = l.text:match("^}%s*([%w_]+)%s*;%s*$") + if closeName then + if closeName ~= "bool" then + return { + type = "enum", + name = closeName, + fields = fields, + notes = line.notes, + comment = line.comment, + }, + i - idx + 1 + end + return nil, i - idx + 1 + end + local fText = l.text:match("^%s*(.-),?%s*$") + if fText and #fText > 0 then + local name, value = fText:match("^([%w_]+)%s*=%s*(.+)$") + if name then + fields[#fields + 1] = { + name = name, + value = value, + comment = l.comment, + } + else + name = fText:match("^([%w_]+)%s*$") + if name then + fields[#fields + 1] = { + name = name, + value = nil, + comment = l.comment, + } + end + end + end + i = i + 1 + end + io.stderr:write("WARN: unclosed enum: ", text, "\n") + return nil, #lines - idx + 1 + end, + }, + -- #define NAME value + { + match = function(line) + local text = line.text + if not text:match("^#define") then + return false + elseif text:match("^#define%s+RL_") then + return false + elseif text:match("^#define%s+RAYLIB_H%s*$") then + return false + else + return true + end + end, + consume = function(lines, idx) + local line = lines[idx] + local name, value = line.text:match("^#define%s+([%w_]+)%s+(.*)$") + if not name then + return nil, 1 + end + -- filter function-like macros (value contains ( but not as leading expression) + -- e.g. __declspec(dllexport) vs (PI/180.0f) + if value:match("%S%(") and not value:match("CLITERAL") then + return nil, 1 + end + local category + if name:match("^RAYLIB_VERSION") then + category = "version" + elseif value:match("CLITERAL") then + category = "color" + elseif value:match('^"') then + category = "string" + elseif value:match("%.") or value:match("%df$") or value:match("^PI$") then + category = "float" + elseif value:match("^[%w_]+$") then + category = "alias" + else + category = "integer" + end + return { + type = "define", + name = name, + value = value, + category = category, + notes = line.notes, + comment = line.comment, + }, + 1 + end, + }, + -- typedef ; (alias, forward decl, or callback) + { + match = function(line) + local text = line.text + return text:match("^typedef") and not text:match("^typedef%s+(enum|struct)") + end, + consume = function(lines, idx) + local line = lines[idx] + local text = line.text + -- callback typedef: typedef (*)(); + if text:match("%(%*") then + local retType, cbName, params = text:match("^typedef%s+(.-)%s*%(%*([%w_]+)%)%s*%((.-)%)%s*;%s*$") + if retType and cbName then + local node = { + type = "function", + name = cbName, + retType = retType, + isCallback = true, + notes = line.notes, + comment = line.comment, + } + if params and params ~= "void" then + node.params = {} + for param in params:gmatch("[^,]+") do + local trimmed = param:match("^%s*(.-)%s*$") + local pType, pName = Parser.split_type_name(trimmed) + node.params[#node.params + 1] = { + type = pType, + name = pName, + } + end + end + return node, 1 + end + io.stderr:write("WARN: failed to parse callback typedef: ", text, "\n") + return nil, 1 + end + -- regular alias: typedef ; + local aliasedType, aliasName = text:match("^typedef%s+(.-)%s*([%w_]+)%s*;%s*$") + if aliasedType and aliasName then + aliasedType = aliasedType:match("^%s*(.-)%s*$") + return { + type = "alias", + name = aliasName, + aliasedType = aliasedType, + notes = line.notes, + comment = line.comment, + }, + 1 + end + io.stderr:write("WARN: failed to parse typedef: ", text, "\n") + return nil, 1 + end, + }, +} + +function Parser.scan(lines) + local ast = { + function_xs = {}, + struct_xs = {}, + enum_xs = {}, + define_xs = {}, + alias_xs = {}, + } + local idx = 1 + while idx <= #lines do + local line = lines[idx] + local matched = false + for _, m in ipairs(matchers) do + if m.match(line) then + local node, consumed = m.consume(lines, idx) + if node then + local key = node.type .. "_xs" + -- push node onto its type-specific list in the ast table + ast[key][#ast[key] + 1] = node + end + -- always consume + idx = idx + consumed + matched = true + break + end + end + if not matched then + if + -- blank lines + not line.text:match("^%s*$") + -- preproc conds + and not line.text:match("^#if") + and not line.text:match("^#else") + and not line.text:match("^#endif") + and not line.text:match("^#ifdef") + and not line.text:match("^#ifndef") + and not line.text:match("^#elif") + and not line.text:match("^#pragma") + and not line.text:match("^#error") + and not line.text:match("^#undef") + and not line.text:match("^#include") + -- unused defines + and not line.text:match("^#define%s+RAYLIB_H") + and not line.text:match("^#define%s+RL_%w+_TYPE%s*$") + and not line.text:match("^#define%s+RL_MALLOC") + and not line.text:match("^#define%s+RL_CALLOC") + and not line.text:match("^#define%s+RL_REALLOC") + and not line.text:match("^#define%s+RL_FREE") + and not line.text:match('^extern%s+"C"') + -- final closing brace + and not line.text:match("^}%s*$") + then + io.stderr:write("WARN: unrecognized: ", line.text, "\n") + end + idx = idx + 1 + end + end + return ast +end + +function Parser.analyze(ast) + -- build alias resolution map + local type_map = {} + for _, alias in ipairs(ast.alias_xs) do + type_map[alias.name] = alias.aliasedType + end + -- resolve alias chains (e.g. Color -> unsigned int -> stop) + for name, resolved in pairs(type_map) do + local seen = {} + while type_map[resolved] and not seen[resolved] do + seen[resolved] = true + resolved = type_map[resolved] + end + type_map[name] = resolved + end + ast.type_map = type_map + + -- fill sequential enum values + for _, enum in ipairs(ast.enum_xs) do + local val = 0 + for _, field in ipairs(enum.fields) do + if field.value == nil then + field.value = val + else + val = tonumber(field.value) or val + end + val = val + 1 + end + end + + -- classify mutated types + local mutated_types = {} + for _, f in ipairs(ast.function_xs) do + if f.name:match("^Unload") or f.name:match("^Export") then + goto next_func + end + for _, p in ipairs(f.params or {}) do + if not p.type then + goto next_param + end + local base = p.type:match("^(.-)%s*%*$") + if not base or base:match("const%s+") then + goto next_param + end + base = base:match("^%s*(.-)%s*$") + mutated_types[base] = true + ::next_param:: + end + ::next_func:: + end + + -- resolve mutated aliases to base types + for name, _ in pairs(mutated_types) do + local resolved = type_map[name] + if resolved then + mutated_types[resolved] = true + end + end + ast.mutated_types = mutated_types +end +-- }}} + +-- C EMITTER =================================================================================== {{{ + +-- value types: structs passed by value (Lua tables) +local VALUE_STRUCTS = { + -- math + Matrix = true, + Quaternion = true, + Vector2 = true, + Vector3 = true, + Vector4 = true, + -- geometry and color + Color = true, + Rectangle = true, + -- cameras + Camera = true, + Camera2D = true, + Camera3D = true, + -- collision + BoundingBox = true, + Ray = true, + RayCollision = true, + -- asset + GlyphInfo = true, + NPatchInfo = true, + -- nested and auxiliary types + BoneInfo = true, + MaterialMap = true, + ModelSkeleton = true, + Transform = true, + -- system and VR + AutomationEvent = true, + AutomationEventList = true, + FilePathList = true, + VrDeviceInfo = true, + VrStereoConfig = true, +} + +-- resource types: structs passed by pointer with __gc/unload +local RESOURCE_TYPES = { + -- visual + Image = "UnloadImage", + RenderTexture = "UnloadRenderTexture", + RenderTexture2D = "UnloadRenderTexture", + Texture = "UnloadTexture", + Texture2D = "UnloadTexture", + TextureCubemap = "UnloadTexture", + -- 3D + Mesh = "UnloadMesh", + Model = "UnloadModel", + ModelAnimation = "", -- Requires count for unloading, skip __gc for now + -- audio + AudioStream = "UnloadAudioStream", + Music = "UnloadMusicStream", + Sound = "UnloadSound", + Wave = "UnloadWave", + -- other + Font = "UnloadFont", + Material = "UnloadMaterial", + Shader = "UnloadShader", +} + +-- stylua: ignore +local PRIMITIVE_TYPES = { + int = { check = "(int)luaL_checkinteger", push = "lua_pushinteger" }, + float = { check = "(float)luaL_checknumber", push = "lua_pushnumber" }, + bool = { check = "lua_toboolean", push = "lua_pushboolean" }, + double = { check = "luaL_checknumber", push = "lua_pushnumber" }, + long = { check = "(long)luaL_checkinteger", push = "lua_pushinteger" }, + unsigned = { check = "(unsigned)luaL_checkinteger", push = "lua_pushinteger" }, + unsigned_int = { check = "(unsigned int)luaL_checkinteger", push = "lua_pushinteger" }, + unsigned_char = { check = "(unsigned char)luaL_checkinteger", push = "lua_pushinteger" }, + char = { check = "(char)luaL_checkinteger", push = "lua_pushinteger" }, + unsigned_short = { check = "(unsigned short)luaL_checkinteger", push = "lua_pushinteger" }, + short = { check = "(short)luaL_checkinteger", push = "lua_pushinteger" }, + const_char_ptr = { check = "luaL_checkstring", push = "lua_pushstring" }, + char_ptr = { check = "luaL_checkstring", push = "lua_pushstring" }, + void_ptr = { check = "lua_touserdata", push = "lua_pushlightuserdata" }, + unsigned_char_ptr = { check = "(unsigned char *)lua_touserdata", push = "lua_pushlightuserdata" }, + const_unsigned_char_ptr = { check = "(const unsigned char *)lua_touserdata", push = "lua_pushlightuserdata" }, +} + +-- normalize "const char *" -> "const_char_ptr" +function Parser.normalizeType(t) + if not t then + return "" + else + return t:gsub("%s*%*%s*", "_ptr"):gsub("%s+", "_"):gsub("_+", "_"):gsub("^_", ""):gsub("_$", "") + end +end + +function Parser.getCheckExpression(normType, rawType, index) + if PRIMITIVE_TYPES[normType] then + return ("%s(L, %d)"):format(PRIMITIVE_TYPES[normType].check, index) + elseif normType:match("_ptr$") or normType:match("Callback$") then + return ("(%s)lua_touserdata(L, %d)"):format(rawType, index) + elseif RESOURCE_TYPES[normType] then + return ('*(%s*)RLUA_CHECK_Resource(L, %d, "%s")'):format(rawType, index, normType) + else + return ("RLUA_CHECK_%s(L, %d)"):format(normType, index) + end +end + +function Parser.getPushStatement(normType, rawType, source) + if PRIMITIVE_TYPES[normType] then + return ("%s(L, %s);"):format(PRIMITIVE_TYPES[normType].push, source) + elseif normType:match("_ptr$") then + return ("lua_pushlightuserdata(L, %s);"):format(source) + elseif RESOURCE_TYPES[normType] then + return ('RLUA_PUSH_Resource(L, &%s, sizeof(%s), "%s");'):format(source, rawType, normType) + else + return ("RLUA_PUSH_%s(L, %s);"):format(normType, source) + end +end + +-- render function wrapper +function Parser.renderFunction(func) + local t = {} + for _, note in ipairs(func.notes or {}) do + t[#t + 1] = ("// %s"):format(note) + end + + -- discard typedefs but keep the comments + if func.isCallback then + if #t > 0 then + return table.concat(t, "\n") .. "\n" + else + return nil + end + end + + if func.comment then + t[#t + 1] = ("// %s"):format(func.comment) + end + t[#t + 1] = ("static int rl_%s(lua_State *L)"):format(func.name) + t[#t + 1] = "{" + + if func.name == "SetTraceLogCallback" then + t[#t + 1] = [[ + if (lua_isnil(L, 1)) { + if (RLUA_LogRef != LUA_REFNIL) { + luaL_unref(L, LUA_REGISTRYINDEX, RLUA_LogRef); + RLUA_LogRef = LUA_REFNIL; + } + SetTraceLogCallback(NULL); + } else { + luaL_checktype(L, 1, LUA_TFUNCTION); + if (RLUA_LogRef != LUA_REFNIL) luaL_unref(L, LUA_REGISTRYINDEX, RLUA_LogRef); + lua_pushvalue(L, 1); + RLUA_LogRef = luaL_ref(L, LUA_REGISTRYINDEX); + SetTraceLogCallback(RLUA_TraceLogTrampoline); + } + return 0; +} +]] + t[#t + 1] = "" + return table.concat(t, "\n") + end + + local isVariadic = false + for _, p in ipairs(func.params or {}) do + if p.isVariadic then + isVariadic = true + break + end + end + + if isVariadic then + if func.name == "TraceLog" then + t[#t + 1] = + -- c + [[ + int n = lua_gettop(L); + if (n < 2) return luaL_error(L, "TraceLog requires at least 2 arguments"); + int logLevel = (int)luaL_checkinteger(L, 1); + if (n == 2) { + TraceLog(logLevel, "%s", luaL_checkstring(L, 2)); + } else { + lua_getglobal(L, "string"); + lua_getfield(L, -1, "format"); + for (int i = 2; i <= n; i++) lua_pushvalue(L, i); + lua_call(L, n - 1, 1); + TraceLog(logLevel, "%s", lua_tostring(L, -1)); + lua_pop(L, 2); + } + return 0;]] + elseif func.name == "TextFormat" then + t[#t + 1] = + -- c + [[ + int n = lua_gettop(L); + if (n < 1) return luaL_error(L, "TextFormat requires at least 1 argument"); + if (n == 1) { + lua_pushstring(L, TextFormat("%s", luaL_checkstring(L, 1))); + } else { + lua_getglobal(L, "string"); + lua_getfield(L, -1, "format"); + for (int i = 1; i <= n; i++) lua_pushvalue(L, i); + lua_call(L, n, 1); + const char *formatted = lua_tostring(L, -1); + lua_pushstring(L, TextFormat("%s", formatted)); + lua_insert(L, 1); + lua_settop(L, 1); + } + return 1;]] + else + t[#t + 1] = (" // TODO: Hand-write variadic wrapper for %s"):format(func.name) + t[#t + 1] = " return 0;" + end + else + -- check for "pointer return + out-param count" pattern + local retNorm = Parser.normalizeType(func.retType) + local countParam = nil + if func.retType:match("%*$") then + for _, p in ipairs(func.params or {}) do + if p.type == "int *" or p.type == "unsigned int *" then + countParam = p + break + end + end + end + + -- check for value-struct mutation candidates + local mutates = {} + if func.name:match("^Unload") or func.name:match("^Export") then + goto end_mutates + end + for i, p in ipairs(func.params or {}) do + local base = p.type:match("^(.-)%s*%*$") + if not base or base:match("const%s+") then + goto next_mutate + end + base = base:match("^%s*(.-)%s*$") + if VALUE_STRUCTS[base] then + mutates[i] = base + end + ::next_mutate:: + end + ::end_mutates:: + + -- unpack arguments from the Lua stack + for i, p in ipairs(func.params or {}) do + if p == countParam then + t[#t + 1] = (" int %s = 0;"):format(p.name) + elseif mutates[i] then + t[#t + 1] = (" %s %s = RLUA_CHECK_%s(L, %d);"):format(mutates[i], p.name, mutates[i], i) + else + local pNorm = Parser.normalizeType(p.type) + local expr = Parser.getCheckExpression(pNorm, p.type, i) + local declType = p.type + if pNorm == "char_ptr" or pNorm == "const_char_ptr" then + declType = "const char *" + end + t[#t + 1] = (" %s %s = %s;"):format(declType, p.name, expr) + end + end + + -- construct the raylib C function call + local callArgs = {} + for i, p in ipairs(func.params or {}) do + if p == countParam then + callArgs[#callArgs + 1] = "&" .. p.name + elseif mutates[i] then + callArgs[#callArgs + 1] = "&" .. p.name + else + local arg = p.name + local pNorm = Parser.normalizeType(p.type) + if pNorm == "char_ptr" then + arg = ("(%s)%s"):format(p.type, p.name) + end + callArgs[#callArgs + 1] = arg + end + end + local args = table.concat(callArgs, ", ") + + if retNorm == "void" then + t[#t + 1] = (" %s(%s);"):format(func.name, args) + for i, p in ipairs(func.params or {}) do + if mutates[i] then + t[#t + 1] = (" RLUA_WRITEBACK_%s(L, %d, %s);"):format(mutates[i], i, p.name) + end + end + t[#t + 1] = " return 0;" + else + t[#t + 1] = (" %s result = %s(%s);"):format(func.retType, func.name, args) + for i, p in ipairs(func.params or {}) do + if mutates[i] then + t[#t + 1] = (" RLUA_WRITEBACK_%s(L, %d, %s);"):format(mutates[i], i, p.name) + end + end + if countParam then + local baseType = func.retType:gsub("%s*%*$", "") + t[#t + 1] = (' RLUA_PUSH_View(L, result, %s, "%s", true);'):format(countParam.name, baseType) + t[#t + 1] = " return 1;" + else + t[#t + 1] = " " .. Parser.getPushStatement(retNorm, func.retType, "result") + t[#t + 1] = " return 1;" + end + end + end + + t[#t + 1] = "}" + t[#t + 1] = "" + return table.concat(t, "\n") +end + +-- render struct check (table -> C struct) +function Parser.renderStructCheck(struct) + local t = {} + if struct.notes then + for _, note in ipairs(struct.notes) do + t[#t + 1] = ("// %s"):format(note) + end + end + t[#t + 1] = ("static %s RLUA_CHECK_%s(lua_State *L, int index)"):format(struct.name, struct.name) + t[#t + 1] = "{" + t[#t + 1] = (" %s result = { 0 };"):format(struct.name) + t[#t + 1] = " if (lua_istable(L, index)) {" + + local sorted = {} + for i, f in ipairs(struct.fields or {}) do + sorted[#sorted + 1] = { field = f, index = i } + end + table.sort(sorted, function(a, b) + local na = a.field.name:match("^m(%d+)$") + local nb = b.field.name:match("^m(%d+)$") + if na and nb then + return tonumber(na) < tonumber(nb) + end + return a.index < b.index + end) + + for _, entry in ipairs(sorted) do + local field = entry.field + local name, array_size = field.name:match("([%w_]+)%[(%d+)%]") + if not name then + t[#t + 1] = (' lua_getfield(L, index, "%s");'):format(field.name) + local fNorm = Parser.normalizeType(field.type) + local expr = Parser.getCheckExpression(fNorm, field.type, -1) + local comment = field.comment and (" // %s"):format(field.comment) or "" + t[#t + 1] = (" result.%s = %s;%s"):format(field.name, expr, comment) + t[#t + 1] = " lua_pop(L, 1);" + else + t[#t + 1] = (' lua_getfield(L, index, "%s");'):format(name) + if field.type == "char" then + local comment = field.comment and (" // %s"):format(field.comment) or "" + t[#t + 1] = (" if (lua_isstring(L, -1)) { strncpy(result.%s, lua_tostring(L, -1), %s - 1); }%s"):format( + name, + array_size, + comment + ) + else + t[#t + 1] = " if (lua_istable(L, -1)) {" + t[#t + 1] = (" for (int i = 0; i < %s; i++) {"):format(array_size) + t[#t + 1] = " lua_geti(L, -1, i + 1);" + local fNorm = Parser.normalizeType(field.type) + local expr = Parser.getCheckExpression(fNorm, field.type, -1) + t[#t + 1] = (" result.%s[i] = %s;"):format(name, expr) + t[#t + 1] = " lua_pop(L, 1);" + t[#t + 1] = " }" + t[#t + 1] = " }" + end + t[#t + 1] = " lua_pop(L, 1);" + end + end + + t[#t + 1] = " }" + t[#t + 1] = " return result;" + t[#t + 1] = "}" + return table.concat(t, "\n") +end + +-- render struct push (C struct -> Lua table) +function Parser.renderStructPush(struct) + local t = {} + t[#t + 1] = ("static void RLUA_PUSH_%s(lua_State *L, %s result)"):format(struct.name, struct.name) + t[#t + 1] = "{" + t[#t + 1] = (" lua_createtable(L, 0, %d);"):format(#(struct.fields or {})) + + local sorted = {} + for i, f in ipairs(struct.fields or {}) do + sorted[#sorted + 1] = { field = f, index = i } + end + table.sort(sorted, function(a, b) + local na = a.field.name:match("^m(%d+)$") + local nb = b.field.name:match("^m(%d+)$") + if na and nb then + return tonumber(na) < tonumber(nb) + end + return a.index < b.index + end) + + for _, entry in ipairs(sorted) do + local field = entry.field + local name, array_size = field.name:match("([%w_]+)%[(%d+)%]") + if not name then + local fNorm = Parser.normalizeType(field.type) + local comment = field.comment and (" // %s"):format(field.comment) or "" + t[#t + 1] = " " .. Parser.getPushStatement(fNorm, field.type, "result." .. field.name) .. comment + t[#t + 1] = (' lua_setfield(L, -2, "%s");'):format(field.name) + else + if field.type == "char" then + local comment = field.comment and (" // %s"):format(field.comment) or "" + t[#t + 1] = (" lua_pushstring(L, result.%s);%s"):format(name, comment) + t[#t + 1] = (' lua_setfield(L, -2, "%s");'):format(name) + else + t[#t + 1] = (" lua_createtable(L, %s, 0);"):format(array_size) + t[#t + 1] = (" for (int i = 0; i < %s; i++) {"):format(array_size) + local fNorm = Parser.normalizeType(field.type) + t[#t + 1] = " " .. Parser.getPushStatement(fNorm, field.type, "result." .. name .. "[i]") + t[#t + 1] = " lua_seti(L, -2, i + 1);" + t[#t + 1] = " }" + t[#t + 1] = (' lua_setfield(L, -2, "%s");'):format(name) + end + end + end + + t[#t + 1] = "}" + return table.concat(t, "\n") +end + +-- render struct writeback (C struct -> Lua table) +function Parser.renderStructWriteback(struct, ast) + local t = {} + t[#t + 1] = ("static void RLUA_WRITEBACK_%s(lua_State *L, int index, %s val)"):format(struct.name, struct.name) + t[#t + 1] = "{" + t[#t + 1] = " if (lua_istable(L, index)) {" + + local sorted = {} + for i, f in ipairs(struct.fields or {}) do + sorted[#sorted + 1] = { field = f, index = i } + end + table.sort(sorted, function(a, b) + local na = a.field.name:match("^m(%d+)$") + local nb = b.field.name:match("^m(%d+)$") + if na and nb then + return tonumber(na) < tonumber(nb) + end + return a.index < b.index + end) + + for _, entry in ipairs(sorted) do + local f = entry.field + local fNorm = Parser.normalizeType(f.type) + local comment = f.comment and (" // %s"):format(f.comment) or "" + if PRIMITIVE_TYPES[fNorm] then + t[#t + 1] = " " .. Parser.getPushStatement(fNorm, f.type, "val." .. f.name) .. comment + t[#t + 1] = (' lua_setfield(L, index, "%s");'):format(f.name) + elseif VALUE_STRUCTS[fNorm] then + t[#t + 1] = (" RLUA_PUSH_%s(L, val.%s);%s"):format(fNorm, f.name, comment) + t[#t + 1] = (' lua_setfield(L, index, "%s");'):format(f.name) + elseif ast.type_map[f.type] then + local resolved = ast.type_map[f.type] + local rNorm = Parser.normalizeType(resolved) + if PRIMITIVE_TYPES[rNorm] then + t[#t + 1] = " " .. Parser.getPushStatement(rNorm, resolved, "val." .. f.name) .. comment + t[#t + 1] = (' lua_setfield(L, index, "%s");'):format(f.name) + end + end + end + t[#t + 1] = " }" + t[#t + 1] = "}" + return table.concat(t, "\n") +end + +-- render function registry (luaL_Reg array) +function Parser.renderFunctionRegistry(ast) + local function_names = {} + for _, f in ipairs(ast.function_xs) do + function_names[f.name] = true + end + + local t = { + "// raylib functions list", + "static const struct luaL_Reg raylib_functions[] = {", + } + for _, f in ipairs(ast.function_xs) do + if not f.isCallback then + t[#t + 1] = (' {"%s", rl_%s},'):format(f.name, f.name) + end + end + for _, d in ipairs(ast.define_xs) do + if d.category == "alias" and function_names[d.value] then + t[#t + 1] = (' {"%s", rl_%s},'):format(d.name, d.value) + end + end + t[#t + 1] = "" + t[#t + 1] = " { NULL, NULL } // sentinel" + t[#t + 1] = "};" + t[#t + 1] = "" + return table.concat(t, "\n") +end + +-- render constants registry +function Parser.renderDefineRegistry(ast) + local function_names = {} + for _, f in ipairs(ast.function_xs) do + function_names[f.name] = true + end + + local t = { "static void rLuaRegisterConstants(lua_State *L)", "{" } + + -- enum constants + for _, enum in ipairs(ast.enum_xs) do + for _, field in ipairs(enum.fields) do + local v = field.value + if type(v) == "string" then + v = tonumber(v) or v + end + if type(v) == "number" then + t[#t + 1] = (" lua_pushinteger(L, %d);"):format(v) + else + t[#t + 1] = (" lua_pushinteger(L, %s);"):format(tostring(v)) + end + t[#t + 1] = (' lua_setfield(L, -2, "%s");'):format(field.name) + end + end + + -- #define constants + for _, d in ipairs(ast.define_xs) do + if d.category == "alias" and function_names[d.value] then + goto continue_def + end + + if d.category == "version" then + goto continue_def + end + + local pusher = "lua_pushinteger" + if d.category == "float" then + pusher = "lua_pushnumber" + elseif d.category == "string" then + pusher = "lua_pushstring" + elseif d.category == "color" then + pusher = "RLUA_PUSH_Color" + end + + t[#t + 1] = (" %s(L, %s);"):format(pusher, d.value) + t[#t + 1] = (' lua_setfield(L, -2, "%s");'):format(d.name) + + ::continue_def:: + end + + t[#t + 1] = "}" + t[#t + 1] = "" + return table.concat(t, "\n") +end + +-- resource destructors (__gc) +function Parser.renderDestructors() + local t = { "// --- Resource Destructors (__gc) ---", "" } + local sorted = {} + for name, func in pairs(RESOURCE_TYPES) do + if func ~= "" then + sorted[#sorted + 1] = { name = name, func = func } + end + end + table.sort(sorted, function(a, b) + return a.name < b.name + end) + + for _, item in ipairs(sorted) do + t[#t + 1] = ("static int rl_%s_gc(lua_State *L)"):format(item.name) + t[#t + 1] = "{" + t[#t + 1] = (' RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "%s");'):format(item.name) + t[#t + 1] = " if (h->data && h->owned) {" + t[#t + 1] = (" %s(*(%s*)h->data);"):format(item.func, item.name) + t[#t + 1] = " RL_FREE(h->data);" + t[#t + 1] = " }" + t[#t + 1] = " return 0;" + t[#t + 1] = "}" + t[#t + 1] = "" + end + return table.concat(t, "\n") +end + +-- resource indexers (__index) +function Parser.renderIndexers(ast) + local structs_by_name = {} + for _, s in ipairs(ast.struct_xs) do + structs_by_name[s.name] = s + end + + local t = { "// --- Resource Indexers (__index) ---", "" } + local sorted = {} + for name, _ in pairs(RESOURCE_TYPES) do + sorted[#sorted + 1] = name + end + table.sort(sorted) + + for _, tname in ipairs(sorted) do + local struct = structs_by_name[tname] + if struct then + t[#t + 1] = ("static int rl_%s_index(lua_State *L)"):format(tname) + t[#t + 1] = "{" + t[#t + 1] = (' RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, 1, "%s");'):format(tname) + t[#t + 1] = " if (lua_isnumber(L, 2)) {" + t[#t + 1] = " int i = lua_tointeger(L, 2) - 1;" + t[#t + 1] = ' if (i < 0 || i >= h->count) return luaL_error(L, "index out of bounds");' + t[#t + 1] = (" %s *ptr = &((%s *)h->data)[i];"):format(tname, tname) + t[#t + 1] = (' RLUA_PUSH_View(L, ptr, 1, "%s", false);'):format(tname) + t[#t + 1] = " return 1;" + t[#t + 1] = " }" + t[#t + 1] = " const char *key = luaL_checkstring(L, 2);" + t[#t + 1] = (" %s *data = (%s *)h->data;"):format(tname, tname) + + for _, field in ipairs(struct.fields or {}) do + if not field.name:match("%[") then + local comment = field.comment and (" // %s"):format(field.comment) or "" + t[#t + 1] = (' if (strcmp(key, "%s") == 0) {%s'):format(field.name, comment) + local fNorm = Parser.normalizeType(field.type) + if VALUE_STRUCTS[fNorm] then + t[#t + 1] = (" RLUA_PUSH_%s(L, data->%s);"):format(field.type, field.name) + elseif RESOURCE_TYPES[fNorm] then + t[#t + 1] = (' RLUA_PUSH_View(L, &data->%s, 1, "%s", false);'):format(field.name, fNorm) + else + t[#t + 1] = " " .. Parser.getPushStatement(fNorm, field.type, "data->" .. field.name) + end + t[#t + 1] = " return 1;" + t[#t + 1] = " }" + end + end + t[#t + 1] = " return 0;" + t[#t + 1] = "}" + t[#t + 1] = "" + end + end + return table.concat(t, "\n") +end + +-- metatable registries +function Parser.renderMetatableRegistries(ast) + local structs_by_name = {} + for _, s in ipairs(ast.struct_xs) do + structs_by_name[s.name] = s + end + + local t = { "static void rLuaRegisterMetatables(lua_State *L)", "{" } + local sorted = {} + for name, _ in pairs(RESOURCE_TYPES) do + sorted[#sorted + 1] = name + end + table.sort(sorted) + + for _, tname in ipairs(sorted) do + t[#t + 1] = (' luaL_newmetatable(L, "%s");'):format(tname) + if structs_by_name[tname] then + t[#t + 1] = (" lua_pushcfunction(L, rl_%s_index);"):format(tname) + t[#t + 1] = ' lua_setfield(L, -2, "__index");' + end + local func = RESOURCE_TYPES[tname] + if func ~= "" then + t[#t + 1] = (" lua_pushcfunction(L, rl_%s_gc);"):format(tname) + t[#t + 1] = ' lua_setfield(L, -2, "__gc");' + end + t[#t + 1] = " lua_pop(L, 1);" + t[#t + 1] = "" + end + + t[#t + 1] = "}" + return table.concat(t, "\n") +end + +-- type alias marshallers (Camera -> Camera3D, Quaternion -> Vector4, etc.) +function Parser.renderTypeAliases(ast) + local structs_by_name = {} + for _, s in ipairs(ast.struct_xs) do + structs_by_name[s.name] = s + end + + local t = {} + local sorted = {} + for name in pairs(ast.type_map) do + sorted[#sorted + 1] = name + end + table.sort(sorted) + for _, aliasName in ipairs(sorted) do + local resolvedType = ast.type_map[aliasName] + if RESOURCE_TYPES[resolvedType] then + t[#t + 1] = ('#define RLUA_CHECK_%s(L, idx) (*(%s*)RLUA_CHECK_Resource(L, idx, "%s"))'):format( + aliasName, + aliasName, + resolvedType + ) + t[#t + 1] = ('#define RLUA_PUSH_%s(L, val) RLUA_PUSH_Resource(L, &val, sizeof(%s), "%s")'):format( + aliasName, + aliasName, + resolvedType + ) + elseif structs_by_name[resolvedType] then + t[#t + 1] = ("#define RLUA_CHECK_%s RLUA_CHECK_%s"):format(aliasName, resolvedType) + t[#t + 1] = ("#define RLUA_PUSH_%s RLUA_PUSH_%s"):format(aliasName, resolvedType) + if ast.mutated_types[aliasName] or ast.mutated_types[resolvedType] then + t[#t + 1] = ("#define RLUA_WRITEBACK_%s RLUA_WRITEBACK_%s"):format(aliasName, resolvedType) + end + elseif resolvedType:match("%*$") then + local base = resolvedType:gsub("%s*%*$", "") + if structs_by_name[base] then + t[#t + 1] = ('#define RLUA_CHECK_%s(L, idx) (%s)RLUA_CHECK_Resource(L, idx, "%s")'):format( + aliasName, + aliasName, + base + ) + t[#t + 1] = ('#define RLUA_PUSH_%s(L, val) RLUA_PUSH_View(L, val, 1, "%s", false)'):format( + aliasName, + base + ) + end + end + end + return table.concat(t, "\n") +end + +function Parser.emit_c(ast, out) + local sections = {} + + -- header (boilerplate before implementation) + sections[#sections + 1] = string.format( + -- c + [[ +/********************************************************************************************** +* +* raylib-lua v6.0 - raylib Lua bindings for raylib v6.0 +* +* AUTO-GENERATED by tools/rLuaParser/rluaparser.lua +* +* Parsed: %d functions, %d structs, %d enums, %d defines, %d aliases +* +* NOTES: +* +* The following types are treated as Lua tables with named fields, same as in C: +* Matrix, Vector2, Vector3, Vector4, Color, Rectangle, Ray, Camera, BoundingBox +* +* The following types are opaque userdata with field access and automatic memory management (__gc): +* Image, Texture2D, RenderTexture2D, Mesh, Model, Shader, Font, Sound, Music, Wave +* +* Remember that ALL raylib types have REFERENCE SEMANTICS in Lua. +* Tables (value types) are passed to C by copying fields, but multiple references +* on the Lua side point to the same table object. +* +* Some raylib functions take pointers to objects to modify (e.g. UpdateCamera(), etc.) +* For table-based types like Camera, the binding automatically writes modified fields +* back to the original Lua table. For resource types like Image, changes are made +* directly to the memory block. +* +* CONTRIBUTORS: +* Ghassan Al-Mashareqa (ghassan@ghassan.pl): Original binding creation (for raylib 1.3) +* Ramon Santamaria (@raysan5): Review, update and maintenance +* yilisharcs: Modernization and automatic generator (for raylib 6.0) +* +* LICENSE: zlib/libpng +* +* Copyright (c) 2015-2017 Ghassan Al-Mashareqa and Ramon Santamaria (@raysan5) +* Copyright (c) 2026 yilisharcs +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#pragma once + +#include +#include +#include + +#ifdef RLUA_STATIC + #define RLUADEF static // Functions just visible to module including this file +#else + #ifdef __cplusplus + #define RLUADEF extern "C" // Functions visible from other files (no name mangling of functions in C++) + #else + #define RLUADEF extern // Functions visible from other files + #endif +#endif + +RLUADEF lua_State *rlua_open(void); +RLUADEF void rlua_close(lua_State *L); +]], + #ast.function_xs, + #ast.struct_xs, + #ast.enum_xs, + #ast.define_xs, + #ast.alias_xs + ) + + sections[#sections + 1] = + -- c + [[ +#ifdef RLUA_IMPLEMENTATION +#include "raylib.h" +#include +#include +#include +#include // Required for: va_list - Only used by TraceLogCallback +#include + +// --- Global State --- +static lua_State *RLUA_State = NULL; +static int RLUA_LogRef = LUA_REFNIL; +static pthread_mutex_t RLUA_LogMutex = PTHREAD_MUTEX_INITIALIZER; + +// --- Marshalling Helpers --- + +typedef struct { + void *data; + int count; + const char *tname; + bool owned; +} RLUA_Handle; + +static void* RLUA_CHECK_Resource(lua_State *L, int index, const char *tname) { + RLUA_Handle *h = (RLUA_Handle *)luaL_checkudata(L, index, tname); + return h->data; +} + +static void RLUA_PUSH_Resource(lua_State *L, void *data, size_t size, const char *tname) { + RLUA_Handle *h = (RLUA_Handle *)lua_newuserdata(L, sizeof(RLUA_Handle)); + h->data = RL_MALLOC(size); + memcpy(h->data, data, size); + h->count = 1; + h->tname = tname; + h->owned = true; + luaL_setmetatable(L, tname); +} + +static void RLUA_PUSH_View(lua_State *L, const void *data, int count, const char *tname, bool owned) { + RLUA_Handle *h = (RLUA_Handle *)lua_newuserdata(L, sizeof(RLUA_Handle)); + h->data = (void *)data; + h->count = count; + h->tname = tname; + h->owned = owned; + luaL_setmetatable(L, tname); +} + +// --- Callback Trampolines --- +static void RLUA_TraceLogTrampoline(int logLevel, const char *text, va_list args) { + if (!RLUA_State || RLUA_LogRef == LUA_REFNIL) return; + char buffer[1024]; + vsnprintf(buffer, sizeof(buffer), text, args); + pthread_mutex_lock(&RLUA_LogMutex); + lua_State *L = RLUA_State; + lua_rawgeti(L, LUA_REGISTRYINDEX, RLUA_LogRef); + lua_pushinteger(L, logLevel); + lua_pushstring(L, buffer); + if (lua_pcall(L, 2, 0, 0) != LUA_OK) { + TraceLog(LOG_ERROR, "LUA: TraceLogCallback: %s", lua_tostring(L, -1)); + lua_pop(L, 1); + } + pthread_mutex_unlock(&RLUA_LogMutex); +} +]] + + -- type aliases + local aliases = Parser.renderTypeAliases(ast) + if #aliases > 0 then + sections[#sections + 1] = "// --- Type Aliases ---\n" + sections[#sections + 1] = aliases + sections[#sections + 1] = "\n" + end + + -- generated struct marshallers + sections[#sections + 1] = "// --- Generated Marshallers ---\n" + for _, s in ipairs(ast.struct_xs) do + if VALUE_STRUCTS[s.name] then + sections[#sections + 1] = Parser.renderStructCheck(s) + sections[#sections + 1] = Parser.renderStructPush(s) + if ast.mutated_types[s.name] then + sections[#sections + 1] = Parser.renderStructWriteback(s, ast) + end + sections[#sections + 1] = "\n" + end + end + + -- destructors + sections[#sections + 1] = Parser.renderDestructors() + + -- indexers + sections[#sections + 1] = Parser.renderIndexers(ast) + + -- function wrappers + sections[#sections + 1] = "// --- Wrappers ---\n" + for _, f in ipairs(ast.function_xs) do + sections[#sections + 1] = Parser.renderFunction(f) + end + + -- registries + sections[#sections + 1] = "// --- Registries ---\n" + sections[#sections + 1] = Parser.renderMetatableRegistries(ast) + sections[#sections + 1] = Parser.renderDefineRegistry(ast) + sections[#sections + 1] = Parser.renderFunctionRegistry(ast) + + -- rlua_open / rlua_close + sections[#sections + 1] = + -- c + [[ +RLUADEF lua_State *rlua_open(void) { + lua_State *L = luaL_newstate(); + luaL_openlibs(L); + + RLUA_State = L; + rLuaRegisterMetatables(L); + +#ifdef RAYLIB_STRIP_PREFIX + // Register functions as globals + lua_pushglobaltable(L); + luaL_setfuncs(L, raylib_functions, 0); + lua_pop(L, 1); + + // Register constants as globals + lua_pushglobaltable(L); + rLuaRegisterConstants(L); + lua_pop(L, 1); + + // rl table mirrors globals via __index = _G + lua_newtable(L); + lua_newtable(L); + lua_pushglobaltable(L); + lua_setfield(L, -2, "__index"); + lua_setmetatable(L, -2); + lua_setglobal(L, "rl"); +#else + lua_newtable(L); + rLuaRegisterConstants(L); + luaL_setfuncs(L, raylib_functions, 0); + lua_setglobal(L, "rl"); +#endif + + return L; +} + +RLUADEF void rlua_close(lua_State *L) { + if (RLUA_LogRef != LUA_REFNIL) { + luaL_unref(L, LUA_REGISTRYINDEX, RLUA_LogRef); + RLUA_LogRef = LUA_REFNIL; + } + RLUA_State = NULL; + lua_close(L); +} + +#endif +]] + + out:write(table.concat(sections, "\n")) +end + +-- }}} + +-- LUA EMITTER ================================================================================= {{{ + +function Parser.cToLuaType(c_type, ast) + if not c_type or c_type == "" then + return "any" + end + local t = c_type:gsub("%s*const%s*", " "):match("^%s*(.-)%s*$") + if t == "const char *" or t == "const char*" or t == "char *" or t == "char*" then + return "string" + end + if t == "bool" then + return "boolean" + end + if + t == "int" + or t == "unsigned int" + or t == "char" + or t == "unsigned char" + or t == "short" + or t == "unsigned short" + or t == "long" + or t == "unsigned long" + or t == "unsigned" + or t:match("^RL_") + then + return "integer" + end + if t == "float" or t == "double" then + return "number" + end + if t:match("%*$") or t:match("%* ") then + return "userdata" + end + local resolved = ast.type_map and ast.type_map[t] + if resolved then + return Parser.cToLuaType(resolved, ast) + end + return ("rl.%s"):format(t) +end + +function Parser.cToLuaTypename(c_type, ast) + if not c_type or c_type == "" or c_type:match("^void$") then + return "nil" + end + return Parser.cToLuaType(c_type, ast) +end + +function Parser.emit_lua(ast, out) + local t = {} + + local funcs_by_name = {} + for _, f in ipairs(ast.function_xs) do + funcs_by_name[f.name] = f + end + + local function render_lua_func(f, name) + for _, note in ipairs(f.notes or {}) do + if not note:match("^%s*[-=]+%s*$") then + t[#t + 1] = ("--- %s"):format(note) + end + end + if f.comment then + t[#t + 1] = ("--- %s"):format(f.comment) + end + + local isVariadic = false + for _, p in ipairs(f.params or {}) do + if p.isVariadic then + isVariadic = true + break + end + end + + for _, p in ipairs(f.params or {}) do + if not p.isVariadic then + local pname = p.name == "end" and "end_" or p.name + t[#t + 1] = ("---@param %s %s"):format(pname, Parser.cToLuaTypename(p.type, ast)) + end + end + if isVariadic then + t[#t + 1] = "---@param ... any" + end + local ret_type = Parser.cToLuaTypename(f.retType, ast) + if ret_type ~= "nil" then + t[#t + 1] = ("---@return %s"):format(ret_type) + end + local pnames = {} + for _, p in ipairs(f.params or {}) do + if p.isVariadic then + pnames[#pnames + 1] = "..." + else + local pname = p.name == "end" and "end_" or p.name + pnames[#pnames + 1] = pname + end + end + t[#t + 1] = ("function rl.%s(%s) end"):format(name, table.concat(pnames, ", ")) + t[#t + 1] = "" + end + + t[#t + 1] = "---@meta _" + t[#t + 1] = "--[[ **********************************************************************************************" + t[#t + 1] = "" + t[#t + 1] = " raylib-lua v6.0 - raylib Lua type definitions for LuaLS" + t[#t + 1] = "" + t[#t + 1] = " AUTO-GENERATED by tools/rLuaParser/rluaparser.lua" + t[#t + 1] = "" + t[#t + 1] = " LICENSE: zlib/libpng" + t[#t + 1] = "" + t[#t + 1] = " Copyright (c) 2026 yilisharcs" + t[#t + 1] = "" + t[#t + 1] = "************************************************************************************************ ]]" + t[#t + 1] = "" + t[#t + 1] = 'error("Cannot require a meta file")' + t[#t + 1] = "" + + -- struct class definitions + local sorted_structs = {} + for _, s in ipairs(ast.struct_xs) do + sorted_structs[#sorted_structs + 1] = s + end + table.sort(sorted_structs, function(a, b) + return a.name < b.name + end) + + for _, s in ipairs(sorted_structs) do + for _, note in ipairs(s.notes or {}) do + if not note:match("^%s*[-=]+%s*$") then + t[#t + 1] = ("--- %s"):format(note) + end + end + if s.comment then + t[#t + 1] = ("--- %s"):format(s.comment) + end + t[#t + 1] = ("---@class rl.%s"):format(s.name) + local sorted_fields = {} + for i, f in ipairs(s.fields or {}) do + sorted_fields[#sorted_fields + 1] = { field = f, index = i } + end + table.sort(sorted_fields, function(a, b) + local na = a.field.name:match("^m(%d+)$") + local nb = b.field.name:match("^m(%d+)$") + if na and nb then + return tonumber(na) < tonumber(nb) + end + return a.index < b.index + end) + for _, entry in ipairs(sorted_fields) do + local f = entry.field + if f.comment then + t[#t + 1] = ("--- %s"):format(f.comment) + end + local baseName, arraySize = f.name:match("([%w_]+)%[(%d+)%]") + if baseName then + if f.type == "char" then + t[#t + 1] = ("---@field %s string"):format(baseName) + else + local entries = {} + local fType = Parser.cToLuaType(f.type, ast) + for i = 1, tonumber(arraySize) do + entries[#entries + 1] = ("[%d]: %s"):format(i, fType) + end + t[#t + 1] = ("---@field %s { %s }"):format(baseName, table.concat(entries, ", ")) + end + else + t[#t + 1] = ("---@field %s %s"):format(f.name, Parser.cToLuaType(f.type, ast)) + end + end + t[#t + 1] = "" + end + + -- module table declaration + t[#t + 1] = "---@class (partial) rl" + t[#t + 1] = "rl = {}" + t[#t + 1] = "" + + -- enum type aliases + for _, enum in ipairs(ast.enum_xs) do + t[#t + 1] = ("---@alias rl.%s integer"):format(enum.name) + end + t[#t + 1] = "" + + -- enum constants + for _, enum in ipairs(ast.enum_xs) do + for _, field in ipairs(enum.fields) do + if field.comment then + t[#t + 1] = ("--- %s"):format(field.comment) + end + t[#t + 1] = ("---@type rl.%s"):format(enum.name) + t[#t + 1] = ("rl.%s = %s"):format(field.name, field.value or "nil") + end + end + + -- define constants + for _, d in ipairs(ast.define_xs) do + if d.category ~= "version" then + if d.category == "alias" and funcs_by_name[d.value] then + render_lua_func(funcs_by_name[d.value], d.name) + else + if d.comment then + t[#t + 1] = ("--- %s"):format(d.comment) + end + local def_type = "integer" + local val = "nil" + if d.category == "float" then + def_type = "number" + val = d.value:gsub("([%d.])f", "%1"):gsub("PI", "rl.PI") + elseif d.category == "string" then + def_type = "string" + val = d.value + elseif d.category == "color" then + def_type = "rl.Color" + val = "nil" + elseif d.category == "alias" then + val = "nil" + elseif d.category == "integer" then + val = d.value + end + t[#t + 1] = ("---@type %s"):format(def_type) + t[#t + 1] = ("rl.%s = %s"):format(d.name, val) + end + end + end + + t[#t + 1] = "" + + -- function declarations + for _, f in ipairs(ast.function_xs) do + render_lua_func(f, f.name) + end + + out:write(table.concat(t, "\n")) +end + +-- }}} + +-- EXECUTION ============================================================================================== + +local input_f, c_out_f, lua_out_f = ... + +if not input_f or not c_out_f then + io.stderr:write("Usage: rluaparser.lua [output.lua]\n") + os.exit(1) +end + +local rl = assert(io.open(input_f, "r")) +local content = rl:read("*a") + +local major = tonumber(content:match("#define%s+RAYLIB_VERSION_MAJOR%s+(%d+)")) +local minor = tonumber(content:match("#define%s+RAYLIB_VERSION_MINOR%s+(%d+)")) + +local EXPECTED_MAJOR = 6 +local EXPECTED_MINOR = 0 + +-- manually verify that version changes didn't introduce any bugs in the parser! +if major ~= EXPECTED_MAJOR or minor ~= EXPECTED_MINOR then + io.stderr:write( + ("ERROR: Version mismatch.\nExpected raylib %d.%d, found %s.%s\n"):format( + EXPECTED_MAJOR, + EXPECTED_MINOR, + major or "unknown", + minor or "unknown" + ) + ) + os.exit(1) +end + +local lines = Parser.preprocess(content) +local ast = Parser.scan(lines) +Parser.analyze(ast) + +-- io.stderr:write(("functions: %d\n"):format(#ast.function_xs)) +-- io.stderr:write(("structs: %d\n"):format(#ast.struct_xs)) +-- io.stderr:write(("enums: %d\n"):format(#ast.enum_xs)) +-- io.stderr:write(("defines: %d\n"):format(#ast.define_xs)) +-- io.stderr:write(("aliases: %d\n"):format(#ast.alias_xs)) + +local c_out = assert(io.open(c_out_f, "w")) +Parser.emit_c(ast, c_out) + +if lua_out_f then + local lua_out = assert(io.open(lua_out_f, "w")) + Parser.emit_lua(ast, lua_out) +end From 02642dd0f05642c264162c35cd5f61f79030974e Mon Sep 17 00:00:00 2001 From: yilisharcs Date: Sun, 31 May 2026 03:40:26 -0300 Subject: [PATCH 3/3] feat: new raylib-lua build script and up-to-date lua headers no windows support yet because i don't use windows. chore: update README --- .gitignore | 9 +- README.md | 21 +- build.lua | 205 ++++++++++++ src/external/lua/include/lauxlib.h | 109 ++++--- src/external/lua/include/lua.h | 151 ++++++--- src/external/lua/include/lua.hpp | 3 +- src/external/lua/include/luaconf.h | 452 ++++++++++++-------------- src/external/lua/include/lualib.h | 51 +-- src/external/lua/lib-win64/liblua55.a | Bin 0 -> 95174 bytes src/external/lua/lib-win64/lua55.dll | Bin 0 -> 371668 bytes src/external/lua/lib/liblua53.a | Bin 322424 -> 0 bytes src/external/lua/lib/liblua53dll.a | Bin 91416 -> 0 bytes src/external/lua/lib/liblua55.a | Bin 0 -> 547636 bytes src/external/lua/lib/liblua55.so | Bin 0 -> 337016 bytes src/external/lua/lib/lua53.dll | Bin 232960 -> 0 bytes 15 files changed, 642 insertions(+), 359 deletions(-) create mode 100755 build.lua mode change 100644 => 100755 src/external/lua/include/lauxlib.h mode change 100644 => 100755 src/external/lua/include/lua.h mode change 100644 => 100755 src/external/lua/include/lua.hpp mode change 100644 => 100755 src/external/lua/include/luaconf.h mode change 100644 => 100755 src/external/lua/include/lualib.h create mode 100644 src/external/lua/lib-win64/liblua55.a create mode 100644 src/external/lua/lib-win64/lua55.dll delete mode 100644 src/external/lua/lib/liblua53.a delete mode 100644 src/external/lua/lib/liblua53dll.a create mode 100755 src/external/lua/lib/liblua55.a create mode 100755 src/external/lua/lib/liblua55.so delete mode 100644 src/external/lua/lib/lua53.dll diff --git a/.gitignore b/.gitignore index f55bbc8..98f7c04 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ /.direnv/ +/build/ + # Compiled Lua sources luac.out @@ -42,6 +44,7 @@ luac.out # Avoid ignoring release execs !release/win32/rlua.exe -!src/external/lua/lib/liblua53.a -!src/external/lua/lib/liblua53dll.a -!src/external/lua/lib/lua53.dll +!src/external/lua/lib/liblua55.a +!src/external/lua/lib/liblua55.so +!src/external/lua/lib-win64/liblua55.a +!src/external/lua/lib-win64/lua55.dll diff --git a/README.md b/README.md index a1ad0dc..426085f 100644 --- a/README.md +++ b/README.md @@ -10,15 +10,30 @@ raylib-lua could be useful for prototyping, tools development, graphic applicati

-**WARNING: Current raylib-lua binding is very outdated! It's based on raylib 1.7 and port to newer raylib versions is stopped. Consider switching to [raylib-lua-sol](https://github.com/RobLoach/raylib-lua-sol), updated to latest raylib 2.6.** +### Build and Usage +A Linux build script is provided to compile the library and the launcher: + +```bash +./build.lua +``` + +It supports both X11 (default) and Wayland backends. For Wayland: + +```bash +CFLAGS="-D_GLFW_WAYLAND" ./build.lua +``` ### rLuaLauncher A raylib-lua launcher is also provided: [rluaLauncher](tools/rLuaLauncher/rlualauncher.c). This launcher allows you to run raylib-lua -programs from command line, or just with *drag & drop* of .lua files into *rlualauncher.exe*. +programs from the command line: + +```bash +./build/rlualauncher examples/core/core_basic_window.lua +``` -Note that launcher can also be compiled for other platforms, just need to link with Lua library and raylib library. +Note that the launcher can also be compiled for other platforms, just link with the Lua library and raylib library. For more details, just check comments on sources. ### rLuaParser diff --git a/build.lua b/build.lua new file mode 100755 index 0000000..f9d0b98 --- /dev/null +++ b/build.lua @@ -0,0 +1,205 @@ +#!/usr/bin/env lua + +local u = assert(io.popen("uname -s"), "popen failed") +local uname = u:read("*l") + +-- TODO: add Windows support (MinGW or MSVC toolchain, Win32 platform libs) +if uname ~= "Linux" then + print("ERROR: this build script only supports Linux (detected: " .. tostring(uname) .. ")") + os.exit(1) +end + +local CC = os.getenv("CC") or "gcc" +local AR = os.getenv("AR") or "ar" +local CFLAGS = os.getenv("CFLAGS") or "" +local LDFLAGS = os.getenv("LDFLAGS") or "" +local BUILD = os.getenv("BUILD_DIR") or "build" +local RAYLIB_SRC_PATH = os.getenv("RAYLIB_SRC_PATH") or "../raylib/src" + +-- library types: STATIC or SHARED +local RAYLIB_LIBTYPE = os.getenv("RAYLIB_LIBTYPE") or "STATIC" +local LUA_LIBTYPE = os.getenv("LUA_LIBTYPE") or "STATIC" + +-- backend: X11 default (alt: -D_GLFW_WAYLAND in CFLAGS) +local glfw_flag = CFLAGS:match("-D_GLFW_[%w_]+") or "-D_GLFW_X11" +local platform_libs = glfw_flag:find("WAYLAND") and "-lwayland-client -lwayland-cursor -lwayland-egl -lxkbcommon" + or "-lX11" + +local common_libs = table.concat({ + "-lGL", -- OpenGL + "-lm", -- math functions, used internally + "-lpthread", -- POSIX threads + "-ldl", -- dlopen/dlsym + "-lrt", -- real-time extensions + platform_libs, +}, " ") + +local function exists(path) + local f = io.open(path, "r") + return f ~= nil +end + +local function run(cmd) + print(cmd) + local ok = os.execute(cmd) + if not ok then + os.exit(1) + end +end + +os.execute("mkdir -p " .. BUILD) + +-- libraylib +local raylib_lib = (RAYLIB_LIBTYPE == "SHARED") and (BUILD .. "/libraylib.so") or (BUILD .. "/libraylib.a") + +-- invalidate cache on backend switch +local marker_path = BUILD .. "/.backend" +local m_in = io.open(marker_path, "r") +local old_backend = m_in and m_in:read("*l") or "" + +if old_backend ~= glfw_flag and exists(raylib_lib) then + print("INFO: backend changed; rebuilding raylib") + os.execute("rm " .. raylib_lib) +end + +-- generate wayland protocol headers from bundled XML +if glfw_flag:find("WAYLAND") then + local wl_deps = RAYLIB_SRC_PATH .. "/external/glfw/deps/wayland" + local protocols = { + "fractional-scale-v1.xml", + "idle-inhibit-unstable-v1.xml", + "pointer-constraints-unstable-v1.xml", + "relative-pointer-unstable-v1.xml", + "viewporter.xml", + "wayland.xml", + "xdg-activation-v1.xml", + "xdg-decoration-unstable-v1.xml", + "xdg-shell.xml", + } + for _, xml in ipairs(protocols) do + local base = xml:gsub("%.xml$", "") + run(("wayland-scanner client-header %s/%s %s/%s-client-protocol.h"):format(wl_deps, xml, BUILD, base)) + run(("wayland-scanner private-code %s/%s %s/%s-client-protocol-code.h"):format(wl_deps, xml, BUILD, base)) + end +end + +if not exists(raylib_lib) then + local raylib_sources = { + RAYLIB_SRC_PATH .. "/raudio.c", + RAYLIB_SRC_PATH .. "/rcore.c", + RAYLIB_SRC_PATH .. "/rglfw.c", + RAYLIB_SRC_PATH .. "/rmodels.c", + RAYLIB_SRC_PATH .. "/rshapes.c", + RAYLIB_SRC_PATH .. "/rtext.c", + RAYLIB_SRC_PATH .. "/rtextures.c", + } + + local raylib_cflags = table.concat({ + "-std=c99", + "-DPLATFORM_DESKTOP_GLFW", + "-DGRAPHICS_API_OPENGL_33", + "-D_GNU_SOURCE", + glfw_flag, + -- raylib default, good balance of speed and perf + "-O1", + "-Wall", + -- required for shared, safe for static + "-fPIC", + CFLAGS, + -- [[ INCLUDES ]] + "-I" .. RAYLIB_SRC_PATH, + "-I" .. RAYLIB_SRC_PATH .. "/external/glfw/include", + "-I" .. BUILD, + }, " ") + + if RAYLIB_LIBTYPE == "SHARED" then + run(table.concat({ + CC, + "-o", + raylib_lib, + "-shared", + raylib_cflags, + table.concat(raylib_sources, " "), + -- [[ LIBS ]] + common_libs, + LDFLAGS, + }, " ")) + else + -- compile raylib into object files for the static lib archive + local objs = {} + for _, src in ipairs(raylib_sources) do + local obj = BUILD .. "/" .. src:match("([^/]+)%.c$") .. ".o" + run(table.concat({ + CC, + "-c", + src, + "-o", + obj, + raylib_cflags, + }, " ")) + table.insert(objs, obj) + end + -- generate archive + run(table.concat({ + AR, + "rcs", + raylib_lib, + table.concat(objs, " "), + }, " ")) + -- cleanup artifacts + run("rm " .. table.concat(objs, " ")) + end + + local m = io.open(marker_path, "w") + if m then + m:write(glfw_flag) + end +else + print(raylib_lib .. " found; skipping (cached)") +end + +-- tools/rLuaLauncher/rlualauncher.c +local lua_lib_path = "src/external/lua/lib/liblua55.a" +if LUA_LIBTYPE == "SHARED" then + lua_lib_path = "-llua55" + -- deploy .so for shared build + if exists("src/external/lua/lib/liblua55.so") then + run("cp src/external/lua/lib/liblua55.so " .. BUILD .. "/liblua55.so") + end +end + +local raylib_link = (RAYLIB_LIBTYPE == "SHARED") and "-lraylib" or raylib_lib + +run(table.concat({ + CC, + "-o", + BUILD .. "/rlualauncher", + "-std=c99", + -- raylib default, good balance of speed and perf + "-O1", + "-Wall", + CFLAGS, + -- [[ INCLUDES ]] + "-I" .. RAYLIB_SRC_PATH, + "-Isrc", + "-Isrc/external/lua/include", + -- [[ SOURCES ]] + "tools/rLuaLauncher/rlualauncher.c", + -- prepend lib dirs to the linker path + "-L" .. BUILD, + "-Lsrc/external/lua/lib", + -- [[ LIBS ]] + raylib_link, + lua_lib_path, + common_libs, + LDFLAGS, + -- embed the executable's dir as the dll search path at runtime + "-Wl,-rpath,'$ORIGIN'", +}, " ")) + +print("---") +print(raylib_lib) +print(BUILD .. "/rlualauncher") +if LUA_LIBTYPE == "SHARED" then + print(BUILD .. "/liblua55.so") +end diff --git a/src/external/lua/include/lauxlib.h b/src/external/lua/include/lauxlib.h old mode 100644 new mode 100755 index ddb7c22..7f1d3ca --- a/src/external/lua/include/lauxlib.h +++ b/src/external/lua/include/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.129 2015/11/23 11:29:43 roberto Exp $ +** $Id: lauxlib.h $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -12,14 +12,29 @@ #include #include +#include "luaconf.h" #include "lua.h" +/* global table */ +#define LUA_GNAME "_G" -/* extra error code for 'luaL_load' */ + +typedef struct luaL_Buffer luaL_Buffer; + + +/* extra error code for 'luaL_loadfilex' */ #define LUA_ERRFILE (LUA_ERRERR+1) +/* key, in the registry, for table of loaded modules */ +#define LUA_LOADED_TABLE "_LOADED" + + +/* key, in the registry, for table of preloaded loaders */ +#define LUA_PRELOAD_TABLE "_PRELOAD" + + typedef struct luaL_Reg { const char *name; lua_CFunction func; @@ -36,6 +51,7 @@ LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len); LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg); +LUALIB_API int (luaL_typeerror) (lua_State *L, int arg, const char *tname); LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg, size_t *l); LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg, @@ -65,6 +81,10 @@ LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def, LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname); LUALIB_API int (luaL_execresult) (lua_State *L, int stat); +LUALIB_API void *luaL_alloc (void *ud, void *ptr, size_t osize, + size_t nsize); + + /* predefined references */ #define LUA_NOREF (-2) #define LUA_REFNIL (-1) @@ -83,10 +103,14 @@ LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); LUALIB_API lua_State *(luaL_newstate) (void); +LUALIB_API unsigned luaL_makeseed (lua_State *L); + LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx); -LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, - const char *r); +LUALIB_API void (luaL_addgsub) (luaL_Buffer *b, const char *s, + const char *p, const char *r); +LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, + const char *p, const char *r); LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup); @@ -112,7 +136,11 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) #define luaL_argcheck(L, cond,arg,extramsg) \ - ((void)((cond) || luaL_argerror(L, (arg), (extramsg)))) + ((void)(luai_likely(cond) || luaL_argerror(L, (arg), (extramsg)))) + +#define luaL_argexpected(L,cond,arg,tname) \ + ((void)(luai_likely(cond) || luaL_typeerror(L, (arg), (tname)))) + #define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) #define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) @@ -131,19 +159,43 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, #define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL) +/* +** Perform arithmetic operations on lua_Integer values with wrap-around +** semantics, as the Lua core does. +*/ +#define luaL_intop(op,v1,v2) \ + ((lua_Integer)((lua_Unsigned)(v1) op (lua_Unsigned)(v2))) + + +/* push the value used to represent failure/error */ +#if defined(LUA_FAILISFALSE) +#define luaL_pushfail(L) lua_pushboolean(L, 0) +#else +#define luaL_pushfail(L) lua_pushnil(L) +#endif + + + /* ** {====================================================== ** Generic Buffer manipulation ** ======================================================= */ -typedef struct luaL_Buffer { +struct luaL_Buffer { char *b; /* buffer address */ size_t size; /* buffer size */ size_t n; /* number of characters in buffer */ lua_State *L; - char initb[LUAL_BUFFERSIZE]; /* initial buffer */ -} luaL_Buffer; + union { + LUAI_MAXALIGN; /* ensure maximum alignment for buffer */ + char b[LUAL_BUFFERSIZE]; /* initial buffer */ + } init; +}; + + +#define luaL_bufflen(bf) ((bf)->n) +#define luaL_buffaddr(bf) ((bf)->b) #define luaL_addchar(B,c) \ @@ -152,6 +204,8 @@ typedef struct luaL_Buffer { #define luaL_addsize(B,s) ((B)->n += (s)) +#define luaL_buffsub(B,s) ((B)->n -= (s)) + LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz); LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); @@ -190,45 +244,6 @@ typedef struct luaL_Stream { /* }====================================================== */ - -/* compatibility with old module system */ -#if defined(LUA_COMPAT_MODULE) - -LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname, - int sizehint); -LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname, - const luaL_Reg *l, int nup); - -#define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0)) - -#endif - - -/* -** {================================================================== -** "Abstraction Layer" for basic report of messages and errors -** =================================================================== -*/ - -/* print a string */ -#if !defined(lua_writestring) -#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) -#endif - -/* print a newline and flush the output */ -#if !defined(lua_writeline) -#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout)) -#endif - -/* print an error message */ -#if !defined(lua_writestringerror) -#define lua_writestringerror(s,p) \ - (fprintf(stderr, (s), (p)), fflush(stderr)) -#endif - -/* }================================================================== */ - - /* ** {============================================================ ** Compatibility with deprecated conversions diff --git a/src/external/lua/include/lua.h b/src/external/lua/include/lua.h old mode 100644 new mode 100755 index f78899f..ab473dc --- a/src/external/lua/include/lua.h +++ b/src/external/lua/include/lua.h @@ -1,7 +1,7 @@ /* -** $Id: lua.h,v 1.331 2016/05/30 15:53:28 roberto Exp $ +** $Id: lua.h $ ** Lua - A Scripting Language -** Lua.org, PUC-Rio, Brazil (http://www.lua.org) +** Lua.org, PUC-Rio, Brazil (www.lua.org) ** See Copyright Notice at the end of this file */ @@ -13,18 +13,19 @@ #include -#include "luaconf.h" +#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2025 Lua.org, PUC-Rio" +#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" -#define LUA_VERSION_MAJOR "5" -#define LUA_VERSION_MINOR "3" -#define LUA_VERSION_NUM 503 -#define LUA_VERSION_RELEASE "3" +#define LUA_VERSION_MAJOR_N 5 +#define LUA_VERSION_MINOR_N 5 +#define LUA_VERSION_RELEASE_N 0 -#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR -#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE -#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2016 Lua.org, PUC-Rio" -#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" +#define LUA_VERSION_NUM (LUA_VERSION_MAJOR_N * 100 + LUA_VERSION_MINOR_N) +#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + LUA_VERSION_RELEASE_N) + + +#include "luaconf.h" /* mark for precompiled code ('Lua') */ @@ -36,10 +37,10 @@ /* ** Pseudo-indices -** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty -** space after that to help overflow detection) +** (The stack size is limited to INT_MAX/2; we keep some free empty +** space after that to help overflow detection.) */ -#define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000) +#define LUA_REGISTRYINDEX (-(INT_MAX/2 + 1000)) #define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i)) @@ -49,8 +50,7 @@ #define LUA_ERRRUN 2 #define LUA_ERRSYNTAX 3 #define LUA_ERRMEM 4 -#define LUA_ERRGCMM 5 -#define LUA_ERRERR 6 +#define LUA_ERRERR 5 typedef struct lua_State lua_State; @@ -71,7 +71,7 @@ typedef struct lua_State lua_State; #define LUA_TUSERDATA 7 #define LUA_TTHREAD 8 -#define LUA_NUMTAGS 9 +#define LUA_NUMTYPES 9 @@ -80,9 +80,10 @@ typedef struct lua_State lua_State; /* predefined values in the registry */ -#define LUA_RIDX_MAINTHREAD 1 +/* index 1 is reserved for the reference mechanism */ #define LUA_RIDX_GLOBALS 2 -#define LUA_RIDX_LAST LUA_RIDX_GLOBALS +#define LUA_RIDX_MAINTHREAD 3 +#define LUA_RIDX_LAST 3 /* type of numbers in Lua */ @@ -124,6 +125,23 @@ typedef int (*lua_Writer) (lua_State *L, const void *p, size_t sz, void *ud); typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); +/* +** Type for warning functions +*/ +typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont); + + +/* +** Type used by the debug API to collect debug information +*/ +typedef struct lua_Debug lua_Debug; + + +/* +** Functions to be called by the debugger in specific events +*/ +typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); + /* ** generic extra include file @@ -142,14 +160,15 @@ extern const char lua_ident[]; /* ** state manipulation */ -LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); +LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud, unsigned seed); LUA_API void (lua_close) (lua_State *L); LUA_API lua_State *(lua_newthread) (lua_State *L); +LUA_API int (lua_closethread) (lua_State *L, lua_State *from); LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); -LUA_API const lua_Number *(lua_version) (lua_State *L); +LUA_API lua_Number (lua_version) (lua_State *L); /* @@ -182,7 +201,7 @@ LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum); LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum); LUA_API int (lua_toboolean) (lua_State *L, int idx); LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); -LUA_API size_t (lua_rawlen) (lua_State *L, int idx); +LUA_API lua_Unsigned (lua_rawlen) (lua_State *L, int idx); LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); LUA_API void *(lua_touserdata) (lua_State *L, int idx); LUA_API lua_State *(lua_tothread) (lua_State *L, int idx); @@ -225,6 +244,8 @@ LUA_API void (lua_pushnil) (lua_State *L); LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len); +LUA_API const char *(lua_pushexternalstring) (lua_State *L, + const char *s, size_t len, lua_Alloc falloc, void *ud); LUA_API const char *(lua_pushstring) (lua_State *L, const char *s); LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, va_list argp); @@ -247,9 +268,9 @@ LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n); LUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p); LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); -LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz); +LUA_API void *(lua_newuserdatauv) (lua_State *L, size_t sz, int nuvalue); LUA_API int (lua_getmetatable) (lua_State *L, int objindex); -LUA_API int (lua_getuservalue) (lua_State *L, int idx); +LUA_API int (lua_getiuservalue) (lua_State *L, int idx, int n); /* @@ -263,7 +284,7 @@ LUA_API void (lua_rawset) (lua_State *L, int idx); LUA_API void (lua_rawseti) (lua_State *L, int idx, lua_Integer n); LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p); LUA_API int (lua_setmetatable) (lua_State *L, int objindex); -LUA_API void (lua_setuservalue) (lua_State *L, int idx); +LUA_API int (lua_setiuservalue) (lua_State *L, int idx, int n); /* @@ -288,7 +309,8 @@ LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip); */ LUA_API int (lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx, lua_KFunction k); -LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg); +LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg, + int *nres); LUA_API int (lua_status) (lua_State *L); LUA_API int (lua_isyieldable) (lua_State *L); @@ -296,7 +318,14 @@ LUA_API int (lua_isyieldable) (lua_State *L); /* -** garbage-collection function and options +** Warning-related functions +*/ +LUA_API void (lua_setwarnf) (lua_State *L, lua_WarnFunction f, void *ud); +LUA_API void (lua_warning) (lua_State *L, const char *msg, int tocont); + + +/* +** garbage-collection options */ #define LUA_GCSTOP 0 @@ -305,11 +334,30 @@ LUA_API int (lua_isyieldable) (lua_State *L); #define LUA_GCCOUNT 3 #define LUA_GCCOUNTB 4 #define LUA_GCSTEP 5 -#define LUA_GCSETPAUSE 6 -#define LUA_GCSETSTEPMUL 7 -#define LUA_GCISRUNNING 9 +#define LUA_GCISRUNNING 6 +#define LUA_GCGEN 7 +#define LUA_GCINC 8 +#define LUA_GCPARAM 9 + + +/* +** garbage-collection parameters +*/ +/* parameters for generational mode */ +#define LUA_GCPMINORMUL 0 /* control minor collections */ +#define LUA_GCPMAJORMINOR 1 /* control shift major->minor */ +#define LUA_GCPMINORMAJOR 2 /* control shift minor->major */ -LUA_API int (lua_gc) (lua_State *L, int what, int data); +/* parameters for incremental mode */ +#define LUA_GCPPAUSE 3 /* size of pause between successive GCs */ +#define LUA_GCPSTEPMUL 4 /* GC "speed" */ +#define LUA_GCPSTEPSIZE 5 /* GC granularity */ + +/* number of parameters */ +#define LUA_GCPN 6 + + +LUA_API int (lua_gc) (lua_State *L, int what, ...); /* @@ -323,11 +371,15 @@ LUA_API int (lua_next) (lua_State *L, int idx); LUA_API void (lua_concat) (lua_State *L, int n); LUA_API void (lua_len) (lua_State *L, int idx); -LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s); +#define LUA_N2SBUFFSZ 64 +LUA_API unsigned (lua_numbertocstring) (lua_State *L, int idx, char *buff); +LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s); LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); +LUA_API void (lua_toclose) (lua_State *L, int idx); +LUA_API void (lua_closeslot) (lua_State *L, int idx); /* @@ -377,16 +429,16 @@ LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); /* ** {============================================================== -** compatibility macros for unsigned conversions +** compatibility macros ** =============================================================== */ -#if defined(LUA_COMPAT_APIINTCASTS) -#define lua_pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n)) -#define lua_tounsignedx(L,i,is) ((lua_Unsigned)lua_tointegerx(L,i,is)) -#define lua_tounsigned(L,i) lua_tounsignedx(L,(i),NULL) +#define lua_newuserdata(L,s) lua_newuserdatauv(L,s,1) +#define lua_getuservalue(L,idx) lua_getiuservalue(L,idx,1) +#define lua_setuservalue(L,idx) lua_setiuservalue(L,idx,1) + +#define lua_resetthread(L) lua_closethread(L,NULL) -#endif /* }============================================================== */ /* @@ -414,12 +466,6 @@ LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); #define LUA_MASKLINE (1 << LUA_HOOKLINE) #define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) -typedef struct lua_Debug lua_Debug; /* activation record */ - - -/* Functions to be called by the debugger in specific events */ -typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); - LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar); LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar); @@ -444,13 +490,17 @@ struct lua_Debug { const char *namewhat; /* (n) 'global', 'local', 'field', 'method' */ const char *what; /* (S) 'Lua', 'C', 'main', 'tail' */ const char *source; /* (S) */ + size_t srclen; /* (S) */ int currentline; /* (l) */ int linedefined; /* (S) */ int lastlinedefined; /* (S) */ unsigned char nups; /* (u) number of upvalues */ unsigned char nparams;/* (u) number of parameters */ char isvararg; /* (u) */ + unsigned char extraargs; /* (t) number of extra arguments */ char istailcall; /* (t) */ + int ftransfer; /* (r) index of first value transferred */ + int ntransfer; /* (r) number of transferred values */ char short_src[LUA_IDSIZE]; /* (S) */ /* private part */ struct CallInfo *i_ci; /* active function */ @@ -459,8 +509,19 @@ struct lua_Debug { /* }====================================================================== */ +#define LUAI_TOSTRAUX(x) #x +#define LUAI_TOSTR(x) LUAI_TOSTRAUX(x) + +#define LUA_VERSION_MAJOR LUAI_TOSTR(LUA_VERSION_MAJOR_N) +#define LUA_VERSION_MINOR LUAI_TOSTR(LUA_VERSION_MINOR_N) +#define LUA_VERSION_RELEASE LUAI_TOSTR(LUA_VERSION_RELEASE_N) + +#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR +#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE + + /****************************************************************************** -* Copyright (C) 1994-2016 Lua.org, PUC-Rio. +* Copyright (C) 1994-2025 Lua.org, PUC-Rio. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the diff --git a/src/external/lua/include/lua.hpp b/src/external/lua/include/lua.hpp old mode 100644 new mode 100755 index ec417f5..2853364 --- a/src/external/lua/include/lua.hpp +++ b/src/external/lua/include/lua.hpp @@ -1,6 +1,7 @@ // lua.hpp // Lua header files for C++ -// <> not supplied automatically because Lua also compiles as C++ +// 'extern "C" not supplied automatically in lua.h and other headers +// because Lua also compiles as C++ extern "C" { #include "lua.h" diff --git a/src/external/lua/include/luaconf.h b/src/external/lua/include/luaconf.h old mode 100644 new mode 100755 index 867e9cb..96a7780 --- a/src/external/lua/include/luaconf.h +++ b/src/external/lua/include/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.255 2016/05/01 20:06:09 roberto Exp $ +** $Id: luaconf.h $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -14,6 +14,16 @@ /* ** =================================================================== +** General Configuration File for Lua +** +** Some definitions here can be changed externally, through the compiler +** (e.g., with '-D' options): They are commented out or protected +** by '#if !defined' guards. However, several other definitions +** should be changed directly here, either because they affect the +** Lua ABI (by making the changes here, you ensure that all software +** connected to Lua, such as C libraries, will be compiled with the same +** configuration); or because they are seldom changed. +** ** Search for "@@" to find all configurable definitions. ** =================================================================== */ @@ -22,20 +32,10 @@ /* ** {==================================================================== ** System Configuration: macros to adapt (if needed) Lua to some -** particular platform, for instance compiling it with 32-bit numbers or -** restricting it to C89. +** particular platform, for instance restricting it to C89. ** ===================================================================== */ -/* -@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. You -** can also define LUA_32BITS in the make file, but changing here you -** ensure that all software connected to Lua will be compiled with the -** same configuration. -*/ -/* #define LUA_32BITS */ - - /* @@ LUA_USE_C89 controls the use of non-ISO-C89 features. ** Define it if you want Lua to avoid the use of a few C99 features @@ -58,48 +58,62 @@ #endif +/* +** When POSIX DLL ('LUA_USE_DLOPEN') is enabled, the Lua stand-alone +** application will try to dynamically link a 'readline' facility +** for its REPL. In that case, LUA_READLINELIB is the name of the +** library it will look for those facilities. If lua.c cannot open +** the specified library, it will generate a warning and then run +** without 'readline'. If that macro is not defined, lua.c will not +** use 'readline'. +*/ #if defined(LUA_USE_LINUX) #define LUA_USE_POSIX #define LUA_USE_DLOPEN /* needs an extra library: -ldl */ -#define LUA_USE_READLINE /* needs some extra libraries */ +#define LUA_READLINELIB "libreadline.so" #endif #if defined(LUA_USE_MACOSX) #define LUA_USE_POSIX -#define LUA_USE_DLOPEN /* MacOS does not need -ldl */ -#define LUA_USE_READLINE /* needs an extra library: -lreadline */ +#define LUA_USE_DLOPEN /* macOS does not need -ldl */ +#define LUA_READLINELIB "libedit.dylib" #endif -/* -@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for -** C89 ('long' and 'double'); Windows always has '__int64', so it does -** not need to use this case. -*/ -#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS) -#define LUA_C89_NUMBERS +#if defined(LUA_USE_IOS) +#define LUA_USE_POSIX +#define LUA_USE_DLOPEN #endif +#if defined(LUA_USE_C89) && defined(LUA_USE_POSIX) +#error "POSIX is not compatible with C89" +#endif + /* -@@ LUAI_BITSINT defines the (minimum) number of bits in an 'int'. +@@ LUAI_IS32INT is true iff 'int' has (at least) 32 bits. */ -/* avoid undefined shifts */ -#if ((INT_MAX >> 15) >> 15) >= 1 -#define LUAI_BITSINT 32 -#else -/* 'int' always must have at least 16 bits */ -#define LUAI_BITSINT 16 -#endif +#define LUAI_IS32INT ((UINT_MAX >> 30) >= 3) + +/* }================================================================== */ + +/* +** {================================================================== +** Configuration for Number types. These options should not be +** set externally, because any other code connected to Lua must +** use the same configuration. +** =================================================================== +*/ + /* @@ LUA_INT_TYPE defines the type for Lua integers. @@ LUA_FLOAT_TYPE defines the type for Lua floats. -** Lua should work fine with any mix of these options (if supported -** by your C compiler). The usual configurations are 64-bit integers +** Lua should work fine with any mix of these options supported +** by your C compiler. The usual configurations are 64-bit integers ** and 'double' (the default), 32-bit integers and 'float' (for ** restricted platforms), and 'long'/'double' (for C compilers not ** compliant with C99, which may not have support for 'long long'). @@ -115,49 +129,79 @@ #define LUA_FLOAT_DOUBLE 2 #define LUA_FLOAT_LONGDOUBLE 3 -#if defined(LUA_32BITS) /* { */ + +/* Default configuration ('long long' and 'double', for 64-bit Lua) */ +#define LUA_INT_DEFAULT LUA_INT_LONGLONG +#define LUA_FLOAT_DEFAULT LUA_FLOAT_DOUBLE + + +/* +@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. +*/ +/* #define LUA_32BITS */ + + +/* +@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for +** C89 ('long' and 'double'); Windows always has '__int64', so it does +** not need to use this case. +*/ +#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS) +#define LUA_C89_NUMBERS 1 +#else +#define LUA_C89_NUMBERS 0 +#endif + + +#if defined(LUA_32BITS) /* { */ /* ** 32-bit integers and 'float' */ -#if LUAI_BITSINT >= 32 /* use 'int' if big enough */ +#if LUAI_IS32INT /* use 'int' if big enough */ #define LUA_INT_TYPE LUA_INT_INT #else /* otherwise use 'long' */ #define LUA_INT_TYPE LUA_INT_LONG #endif #define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT -#elif defined(LUA_C89_NUMBERS) /* }{ */ +#elif LUA_C89_NUMBERS /* }{ */ /* ** largest types available for C89 ('long' and 'double') */ #define LUA_INT_TYPE LUA_INT_LONG #define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE -#endif /* } */ +#else /* }{ */ +/* use defaults */ +#define LUA_INT_TYPE LUA_INT_DEFAULT +#define LUA_FLOAT_TYPE LUA_FLOAT_DEFAULT -/* -** default configuration for 64-bit Lua ('long long' and 'double') -*/ -#if !defined(LUA_INT_TYPE) -#define LUA_INT_TYPE LUA_INT_LONGLONG -#endif +#endif /* } */ -#if !defined(LUA_FLOAT_TYPE) -#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE -#endif /* }================================================================== */ - /* ** {================================================================== ** Configuration for Paths. ** =================================================================== */ +/* +** LUA_PATH_SEP is the character that separates templates in a path. +** LUA_PATH_MARK is the string that marks the substitution points in a +** template. +** LUA_EXEC_DIR in a Windows path is replaced by the executable's +** directory. +*/ +#define LUA_PATH_SEP ";" +#define LUA_PATH_MARK "?" +#define LUA_EXEC_DIR "!" + + /* @@ LUA_PATH_DEFAULT is the default path that Lua uses to look for ** Lua libraries. @@ -167,6 +211,7 @@ ** hierarchy or if you want to install your libraries in ** non-conventional directories. */ + #define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #if defined(_WIN32) /* { */ /* @@ -176,29 +221,40 @@ #define LUA_LDIR "!\\lua\\" #define LUA_CDIR "!\\" #define LUA_SHRDIR "!\\..\\share\\lua\\" LUA_VDIR "\\" + +#if !defined(LUA_PATH_DEFAULT) #define LUA_PATH_DEFAULT \ LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \ LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \ ".\\?.lua;" ".\\?\\init.lua" +#endif + +#if !defined(LUA_CPATH_DEFAULT) #define LUA_CPATH_DEFAULT \ LUA_CDIR"?.dll;" \ LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \ - LUA_CDIR"loadall.dll;" ".\\?.dll;" \ - LUA_CDIR"?53.dll;" ".\\?53.dll" + LUA_CDIR"loadall.dll;" ".\\?.dll" +#endif #else /* }{ */ #define LUA_ROOT "/usr/local/" #define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR "/" #define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR "/" + +#if !defined(LUA_PATH_DEFAULT) #define LUA_PATH_DEFAULT \ LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \ LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" \ "./?.lua;" "./?/init.lua" +#endif + +#if !defined(LUA_CPATH_DEFAULT) #define LUA_CPATH_DEFAULT \ - LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so;" \ - LUA_CDIR"lib?53.so;" "./lib?53.so" + LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so" +#endif + #endif /* } */ @@ -207,12 +263,25 @@ ** CHANGE it if your machine does not use "/" as the directory separator ** and is not Windows. (On Windows Lua automatically uses "\".) */ +#if !defined(LUA_DIRSEP) + #if defined(_WIN32) #define LUA_DIRSEP "\\" #else #define LUA_DIRSEP "/" #endif +#endif + + +/* +** LUA_IGMARK is a mark to ignore all after it when building the +** module name (e.g., used to build the luaopen_ function name). +** Typically, the suffix after the mark is the module version, +** as in "mod-v1.2.so". +*/ +#define LUA_IGMARK "-" + /* }================================================================== */ @@ -246,34 +315,17 @@ #endif /* } */ -/* more often than not the libs go together with the core */ +/* +** More often than not the libs go together with the core. +*/ #define LUALIB_API LUA_API -#define LUAMOD_API LUALIB_API - - -/* -@@ LUAI_FUNC is a mark for all extern functions that are not to be -** exported to outside modules. -@@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables -** that are not to be exported to outside modules (LUAI_DDEF for -** definitions and LUAI_DDEC for declarations). -** CHANGE them if you need to mark them in some special way. Elf/gcc -** (versions 3.2 and later) mark them as "hidden" to optimize access -** when Lua is compiled as a shared library. Not all elf targets support -** this attribute. Unfortunately, gcc does not offer a way to check -** whether the target offers that support, and those without support -** give a warning about it. To avoid these warnings, change to the -** default definition. -*/ -#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ - defined(__ELF__) /* { */ -#define LUAI_FUNC __attribute__((visibility("hidden"))) extern -#else /* }{ */ -#define LUAI_FUNC extern -#endif /* } */ -#define LUAI_DDEC LUAI_FUNC -#define LUAI_DDEF /* empty */ +#if defined(__cplusplus) +/* Lua uses the "C name" when calling open functions */ +#define LUAMOD_API extern "C" +#else +#define LUAMOD_API LUA_API +#endif /* }================================================================== */ @@ -285,88 +337,26 @@ */ /* -@@ LUA_COMPAT_5_2 controls other macros for compatibility with Lua 5.2. -@@ LUA_COMPAT_5_1 controls other macros for compatibility with Lua 5.1. -** You can define it to get all options, or change specific options -** to fit your specific needs. +@@ LUA_COMPAT_GLOBAL avoids 'global' being a reserved word */ -#if defined(LUA_COMPAT_5_2) /* { */ +#define LUA_COMPAT_GLOBAL + /* @@ LUA_COMPAT_MATHLIB controls the presence of several deprecated ** functions in the mathematical library. +** (These functions were already officially removed in 5.3; +** nevertheless they are still available here.) */ -#define LUA_COMPAT_MATHLIB - -/* -@@ LUA_COMPAT_BITLIB controls the presence of library 'bit32'. -*/ -#define LUA_COMPAT_BITLIB - -/* -@@ LUA_COMPAT_IPAIRS controls the effectiveness of the __ipairs metamethod. -*/ -#define LUA_COMPAT_IPAIRS - -/* -@@ LUA_COMPAT_APIINTCASTS controls the presence of macros for -** manipulating other integer types (lua_pushunsigned, lua_tounsigned, -** luaL_checkint, luaL_checklong, etc.) -*/ -#define LUA_COMPAT_APIINTCASTS - -#endif /* } */ - - -#if defined(LUA_COMPAT_5_1) /* { */ - -/* Incompatibilities from 5.2 -> 5.3 */ -#define LUA_COMPAT_MATHLIB -#define LUA_COMPAT_APIINTCASTS - -/* -@@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'. -** You can replace it with 'table.unpack'. -*/ -#define LUA_COMPAT_UNPACK - -/* -@@ LUA_COMPAT_LOADERS controls the presence of table 'package.loaders'. -** You can replace it with 'package.searchers'. -*/ -#define LUA_COMPAT_LOADERS - -/* -@@ macro 'lua_cpcall' emulates deprecated function lua_cpcall. -** You can call your C function directly (with light C functions). -*/ -#define lua_cpcall(L,f,u) \ - (lua_pushcfunction(L, (f)), \ - lua_pushlightuserdata(L,(u)), \ - lua_pcall(L,1,0,0)) - +/* #define LUA_COMPAT_MATHLIB */ -/* -@@ LUA_COMPAT_LOG10 defines the function 'log10' in the math library. -** You can rewrite 'log10(x)' as 'log(x, 10)'. -*/ -#define LUA_COMPAT_LOG10 - -/* -@@ LUA_COMPAT_LOADSTRING defines the function 'loadstring' in the base -** library. You can rewrite 'loadstring(s)' as 'load(s)'. -*/ -#define LUA_COMPAT_LOADSTRING - -/* -@@ LUA_COMPAT_MAXN defines the function 'maxn' in the table library. -*/ -#define LUA_COMPAT_MAXN /* @@ The following macros supply trivial compatibility for some ** changes in the API. The macros themselves document how to ** change your code to avoid using them. +** (Once more, these macros were officially removed in 5.3, but they are +** still available here.) */ #define lua_strlen(L,i) lua_rawlen(L, (i)) @@ -375,69 +365,41 @@ #define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ) #define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT) -/* -@@ LUA_COMPAT_MODULE controls compatibility with previous -** module functions 'module' (Lua) and 'luaL_register' (C). -*/ -#define LUA_COMPAT_MODULE - -#endif /* } */ - - -/* -@@ LUA_COMPAT_FLOATSTRING makes Lua format integral floats without a -@@ a float mark ('.0'). -** This macro is not on by default even in compatibility mode, -** because this is not really an incompatibility. -*/ -/* #define LUA_COMPAT_FLOATSTRING */ - /* }================================================================== */ /* ** {================================================================== -** Configuration for Numbers. +** Configuration for Numbers (low-level part). ** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_* ** satisfy your needs. ** =================================================================== */ /* -@@ LUA_NUMBER is the floating-point type used by Lua. -@@ LUAI_UACNUMBER is the result of an 'usual argument conversion' +@@ LUAI_UACNUMBER is the result of a 'default argument promotion' @@ over a floating number. -@@ l_mathlim(x) corrects limit name 'x' to the proper float type +@@ l_floatatt(x) corrects float attribute 'x' to the proper float type ** by prefixing it with one of FLT/DBL/LDBL. @@ LUA_NUMBER_FRMLEN is the length modifier for writing floats. -@@ LUA_NUMBER_FMT is the format for writing floats. -@@ lua_number2str converts a float to a string. +@@ LUA_NUMBER_FMT is the format for writing floats with the maximum +** number of digits that respects tostring(tonumber(numeral)) == numeral. +** (That would be floor(log10(2^n)), where n is the number of bits in +** the float mantissa.) +@@ LUA_NUMBER_FMT_N is the format for writing floats with the minimum +** number of digits that ensures tonumber(tostring(number)) == number. +** (That would be LUA_NUMBER_FMT+2.) @@ l_mathop allows the addition of an 'l' or 'f' to all math operations. @@ l_floor takes the floor of a float. -@@ lua_str2number converts a decimal numeric string to a number. +@@ lua_str2number converts a decimal numeral to a number. */ -/* The following definitions are good for most cases here */ +/* The following definition is good for most cases here */ #define l_floor(x) (l_mathop(floor)(x)) -#define lua_number2str(s,sz,n) l_sprintf((s), sz, LUA_NUMBER_FMT, (n)) - -/* -@@ lua_numbertointeger converts a float number to an integer, or -** returns 0 if float is not within the range of a lua_Integer. -** (The range comparisons are tricky because of rounding. The tests -** here assume a two-complement representation, where MININTEGER always -** has an exact representation as a float; MAXINTEGER may not have one, -** and therefore its conversion to float may have an ill-defined value.) -*/ -#define lua_numbertointeger(n,p) \ - ((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \ - (n) < -(LUA_NUMBER)(LUA_MININTEGER) && \ - (*(p) = (LUA_INTEGER)(n), 1)) - /* now the variable definitions */ @@ -445,12 +407,13 @@ #define LUA_NUMBER float -#define l_mathlim(n) (FLT_##n) +#define l_floatatt(n) (FLT_##n) #define LUAI_UACNUMBER double #define LUA_NUMBER_FRMLEN "" #define LUA_NUMBER_FMT "%.7g" +#define LUA_NUMBER_FMT_N "%.9g" #define l_mathop(op) op##f @@ -461,12 +424,13 @@ #define LUA_NUMBER long double -#define l_mathlim(n) (LDBL_##n) +#define l_floatatt(n) (LDBL_##n) #define LUAI_UACNUMBER long double #define LUA_NUMBER_FRMLEN "L" #define LUA_NUMBER_FMT "%.19Lg" +#define LUA_NUMBER_FMT_N "%.21Lg" #define l_mathop(op) op##l @@ -476,12 +440,13 @@ #define LUA_NUMBER double -#define l_mathlim(n) (DBL_##n) +#define l_floatatt(n) (DBL_##n) #define LUAI_UACNUMBER double #define LUA_NUMBER_FRMLEN "" -#define LUA_NUMBER_FMT "%.14g" +#define LUA_NUMBER_FMT "%.15g" +#define LUA_NUMBER_FMT_N "%.17g" #define l_mathop(op) op @@ -496,16 +461,14 @@ /* -@@ LUA_INTEGER is the integer type used by Lua. -** @@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER. -** -@@ LUAI_UACINT is the result of an 'usual argument conversion' -@@ over a lUA_INTEGER. +@@ LUAI_UACINT is the result of a 'default argument promotion' +@@ over a LUA_INTEGER. @@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers. @@ LUA_INTEGER_FMT is the format for writing integers. @@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER. @@ LUA_MININTEGER is the minimum value for a LUA_INTEGER. +@@ LUA_MAXUNSIGNED is the maximum value for a LUA_UNSIGNED. @@ lua_integer2str converts an integer to a string. */ @@ -513,10 +476,12 @@ /* The following definitions are good for most cases here */ #define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d" -#define lua_integer2str(s,sz,n) l_sprintf((s), sz, LUA_INTEGER_FMT, (n)) #define LUAI_UACINT LUA_INTEGER +#define lua_integer2str(s,sz,n) \ + l_sprintf((s), sz, LUA_INTEGER_FMT, (LUAI_UACINT)(n)) + /* ** use LUAI_UACINT here to avoid problems with promotions (which ** can turn a comparison between unsigneds into a signed comparison) @@ -534,6 +499,8 @@ #define LUA_MAXINTEGER INT_MAX #define LUA_MININTEGER INT_MIN +#define LUA_MAXUNSIGNED UINT_MAX + #elif LUA_INT_TYPE == LUA_INT_LONG /* }{ long */ #define LUA_INTEGER long @@ -542,6 +509,8 @@ #define LUA_MAXINTEGER LONG_MAX #define LUA_MININTEGER LONG_MIN +#define LUA_MAXUNSIGNED ULONG_MAX + #elif LUA_INT_TYPE == LUA_INT_LONGLONG /* }{ long long */ /* use presence of macro LLONG_MAX as proxy for C99 compliance */ @@ -554,6 +523,8 @@ #define LUA_MAXINTEGER LLONG_MAX #define LUA_MININTEGER LLONG_MIN +#define LUA_MAXUNSIGNED ULLONG_MAX + #elif defined(LUA_USE_WINDOWS) /* }{ */ /* in Windows, can use specific Windows types */ @@ -563,6 +534,8 @@ #define LUA_MAXINTEGER _I64_MAX #define LUA_MININTEGER _I64_MIN +#define LUA_MAXUNSIGNED _UI64_MAX + #else /* }{ */ #error "Compiler does not support 'long long'. Use option '-DLUA_32BITS' \ @@ -597,7 +570,7 @@ /* -@@ lua_strx2number converts an hexadecimal numeric string to a number. +@@ lua_strx2number converts a hexadecimal numeral to a number. ** In C99, 'strtod' does that conversion. Otherwise, you can ** leave 'lua_strx2number' undefined and Lua will provide its own ** implementation. @@ -608,13 +581,21 @@ /* -@@ lua_number2strx converts a float to an hexadecimal numeric string. +@@ lua_pointer2str converts a pointer to a readable string in a +** non-specified way. +*/ +#define lua_pointer2str(buff,sz,p) l_sprintf(buff,sz,"%p",p) + + +/* +@@ lua_number2strx converts a float to a hexadecimal numeral. ** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that. ** Otherwise, you can leave 'lua_number2strx' undefined and Lua will ** provide its own implementation. */ #if !defined(LUA_USE_C89) -#define lua_number2strx(L,b,sz,f,n) ((void)L, l_sprintf(b,sz,f,n)) +#define lua_number2strx(L,b,sz,f,n) \ + ((void)L, l_sprintf(b,sz,f,(LUAI_UACNUMBER)(n))) #endif @@ -653,12 +634,33 @@ /* @@ lua_getlocaledecpoint gets the locale "radix character" (decimal point). ** Change that if you do not want to use C locales. (Code using this -** macro must include header 'locale.h'.) +** macro must include the header 'locale.h'.) */ #if !defined(lua_getlocaledecpoint) #define lua_getlocaledecpoint() (localeconv()->decimal_point[0]) #endif + +/* +** macros to improve jump prediction, used mostly for error handling +** and debug facilities. (Some macros in the Lua API use these macros. +** Define LUA_NOBUILTIN if you do not want '__builtin_expect' in your +** code.) +*/ +#if !defined(luai_likely) + +#if defined(__GNUC__) && !defined(LUA_NOBUILTIN) +#define luai_likely(x) (__builtin_expect(((x) != 0), 1)) +#define luai_unlikely(x) (__builtin_expect(((x) != 0), 0)) +#else +#define luai_likely(x) (x) +#define luai_unlikely(x) (x) +#endif + +#endif + + + /* }================================================================== */ @@ -682,10 +684,7 @@ @@ LUA_USE_APICHECK turns on several consistency checks on the C API. ** Define it as a help when debugging C code. */ -#if defined(LUA_USE_APICHECK) -#include -#define luai_apicheck(l,e) assert(e) -#endif +/* #define LUA_USE_APICHECK */ /* }================================================================== */ @@ -694,23 +693,10 @@ ** {================================================================== ** Macros that affect the API and must be stable (that is, must be the ** same when you compile Lua and when you compile code that links to -** Lua). You probably do not want/need to change them. +** Lua). ** ===================================================================== */ -/* -@@ LUAI_MAXSTACK limits the size of the Lua stack. -** CHANGE it if you need a different limit. This limit is arbitrary; -** its only purpose is to stop Lua from consuming unlimited stack -** space (and to reserve some numbers for pseudo-indices). -*/ -#if LUAI_BITSINT >= 32 -#define LUAI_MAXSTACK 1000000 -#else -#define LUAI_MAXSTACK 15000 -#endif - - /* @@ LUA_EXTRASPACE defines the size of a raw memory area associated with ** a Lua state with very fast access. @@ -721,35 +707,27 @@ /* @@ LUA_IDSIZE gives the maximum size for the description of the source -@@ of a function in debug information. +** of a function in debug information. ** CHANGE it if you want a different size. */ #define LUA_IDSIZE 60 /* -@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. -** CHANGE it if it uses too much C-stack space. (For long double, -** 'string.format("%.99f", 1e4932)' needs ~5030 bytes, so a -** smaller buffer would force a memory allocation for each call to -** 'string.format'.) +@@ LUAL_BUFFERSIZE is the initial buffer size used by the lauxlib +** buffer system. */ -#if defined(LUA_FLOAT_LONGDOUBLE) -#define LUAL_BUFFERSIZE 8192 -#else -#define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer))) -#endif - -/* }================================================================== */ +#define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number))) /* -@@ LUA_QL describes how error messages quote program elements. -** Lua does not use these macros anymore; they are here for -** compatibility only. +@@ LUAI_MAXALIGN defines fields that, when used in a union, ensure +** maximum alignment for the other items in that union. */ -#define LUA_QL(x) "'" x "'" -#define LUA_QS LUA_QL("%s") +#define LUAI_MAXALIGN lua_Number n; double u; void *s; lua_Integer i; long l + +/* }================================================================== */ + @@ -763,7 +741,5 @@ - - #endif diff --git a/src/external/lua/include/lualib.h b/src/external/lua/include/lualib.h old mode 100644 new mode 100755 index 5165c0f..068f60a --- a/src/external/lua/include/lualib.h +++ b/src/external/lua/include/lualib.h @@ -1,5 +1,5 @@ /* -** $Id: lualib.h,v 1.44 2014/02/06 17:32:33 roberto Exp $ +** $Id: lualib.h $ ** Lua standard libraries ** See Copyright Notice in lua.h */ @@ -11,48 +11,55 @@ #include "lua.h" +/* version suffix for environment variable names */ +#define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR +#define LUA_GLIBK 1 LUAMOD_API int (luaopen_base) (lua_State *L); +#define LUA_LOADLIBNAME "package" +#define LUA_LOADLIBK (LUA_GLIBK << 1) +LUAMOD_API int (luaopen_package) (lua_State *L); + + #define LUA_COLIBNAME "coroutine" +#define LUA_COLIBK (LUA_LOADLIBK << 1) LUAMOD_API int (luaopen_coroutine) (lua_State *L); -#define LUA_TABLIBNAME "table" -LUAMOD_API int (luaopen_table) (lua_State *L); +#define LUA_DBLIBNAME "debug" +#define LUA_DBLIBK (LUA_COLIBK << 1) +LUAMOD_API int (luaopen_debug) (lua_State *L); #define LUA_IOLIBNAME "io" +#define LUA_IOLIBK (LUA_DBLIBK << 1) LUAMOD_API int (luaopen_io) (lua_State *L); +#define LUA_MATHLIBNAME "math" +#define LUA_MATHLIBK (LUA_IOLIBK << 1) +LUAMOD_API int (luaopen_math) (lua_State *L); + #define LUA_OSLIBNAME "os" +#define LUA_OSLIBK (LUA_MATHLIBK << 1) LUAMOD_API int (luaopen_os) (lua_State *L); #define LUA_STRLIBNAME "string" +#define LUA_STRLIBK (LUA_OSLIBK << 1) LUAMOD_API int (luaopen_string) (lua_State *L); +#define LUA_TABLIBNAME "table" +#define LUA_TABLIBK (LUA_STRLIBK << 1) +LUAMOD_API int (luaopen_table) (lua_State *L); + #define LUA_UTF8LIBNAME "utf8" +#define LUA_UTF8LIBK (LUA_TABLIBK << 1) LUAMOD_API int (luaopen_utf8) (lua_State *L); -#define LUA_BITLIBNAME "bit32" -LUAMOD_API int (luaopen_bit32) (lua_State *L); -#define LUA_MATHLIBNAME "math" -LUAMOD_API int (luaopen_math) (lua_State *L); +/* open selected libraries */ +LUALIB_API void (luaL_openselectedlibs) (lua_State *L, int load, int preload); -#define LUA_DBLIBNAME "debug" -LUAMOD_API int (luaopen_debug) (lua_State *L); - -#define LUA_LOADLIBNAME "package" -LUAMOD_API int (luaopen_package) (lua_State *L); - - -/* open all previous libraries */ -LUALIB_API void (luaL_openlibs) (lua_State *L); - - - -#if !defined(lua_assert) -#define lua_assert(x) ((void)0) -#endif +/* open all libraries */ +#define luaL_openlibs(L) luaL_openselectedlibs(L, ~0, 0) #endif diff --git a/src/external/lua/lib-win64/liblua55.a b/src/external/lua/lib-win64/liblua55.a new file mode 100644 index 0000000000000000000000000000000000000000..d6ae7709d989051b4551ad6d6b5eebc648ddaeb4 GIT binary patch literal 95174 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 d1Dun;}k6LdbYpO56IH)+!pMS}jGHDbx#0 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

y=yT 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 h%+7^XczEvsXgNmV|F%A&1`a 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 zʨ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

NwtueCn~Xls=wYK@V4qLW_AfTN zWAsby^RMaWMOHWQDKmQ1g#U7@8~fEpcZ^wNB>Zq=>Mp_4_t?0Ig_8_>3~;?4dj+3n-C zfCJQVV`|FAxU;%SHZjy!yQj&RHZ$XLX~*lUD>ih&6{@soIcH;O zRpr~Nii?8}d=86@=ONK8SUOGH?c;4{Khc6yJXZZQUFBrab z_(j8)55HJtmbjksj~nxU-QQE~w6g7ZFu<@=NgOXMsU)45aL>$?gDw6)+s>!*K-%kG zh)itAgm#Hr(~x$|sn8uZb5=@{$8~1Kk9B$8)vU4A;JXGtF!+f<_a$*(mM7fUs?y4` zGS|JxvPcOV=cp%{w56{dsb0d&ggbH0U_`d((Du4rX_g`uM_rSNKhgd=Gj#c%X7uBj#*rcn^=x^bnSGUsoSx=MDO=w?*b&=! zuwyB>-f+=>;NhZ+Z1dl+rzRHh$^(aSnyqPs;a1&WrJbclR9ZP~2U0CHU`<68sTq_W9T3(`{Jd z{DxyO5;o66aQiG7T6^|c`=CbNp_u3%uubI!(ZY0M+`41DkyC`kJ;sE%Q_fUOwfluI z>~q5`^HMB)=v^u@kECy+=yb%|Gl}J^jl2#L$D1BH*zt8_D6;86Ewg@bu%i`u4YMDD zyD=B(ItUq+DxtR8$>P|MIq*-r#g!KBUlM!v6CQafmTdXpn4)_>jb5;z-ILwVokuCn z)2@s$2HcTg500EszAP9$EvTZIr%9bcUE{W)x-{8*%FHYpIgZd}k96zg%EjD8BZaK1 zE8ZENL)v4#TtC^Z@t8OWIvi9{V}=Lq8I{u`llW6(3}yw#1xKmiGLE+_(`Q^dw=|A9 zZFtb>JmWI9GYw2A*}kst=ozKPD7s9pb)A}w?Y*6YE7@|U`#SDwRcD+Pr(%)d*Em>H zB-59=hBu3aRqnkaRc_(!^xM<_aMv?sT~mi=q+0Rl!HyP>jQfe!Eqb5*tGvqNZcp!8 z|3_o@L`3{O9M%d+LXbG`|;rAt>V--dlS@{*BGQ5heQJSiLL$V8F;pwwj} zPCae<*sM!3$B_B9T*|~3^`M-77Q1wCt5`vGD@q*=Q&6mZuLWHSvgB%vQKn)TXJ@|0 z*~K_L#Uy+PxK(t^u^4EJO(=+=h#Mwdo9vh@9UULR%3 zi$IL{^n|fL*XV`0`uTjLJ9D(Y(CAIZ{$=+4bM^CLqlb)sxzU4H>gUx)Z~nU0V@5B$ zRO`#FzEJBcjox^%)_uvN*8WVVPk4cTev{FIMvogk!{}ETz5RS`KW6k6qgNZf+34j) zZ!~(5(W6E`(S*+*F01SD<_Fgqbo&52i`(ZK&H1Y&{pUJ{ekB!hSD5}ADTRe4#j%|a z%ytAucSUB%nci2b`+9qMiQC(jZAX)-`Rx9X>CEI(0lV|A+!v7Ew@W!&jpQ^7tF?>G z)|SlDbX5?ZKTEcj*l@en<(?KB9bu6hF=vh&+}X@*&y``)NlGu3ax|xi9V6wAH#+V`FFM?KHCeVns6}e5Dwvs{ zH{*Q0uS9w|sz4U4WHPY;8=dJUn^W9Hc{jmK9YGaSp-S9;iI~?n>Xc5uB}(eSvfjV0+A*1ML(Ell0lXS(k%N+tCq%%^cUr|oA#m0qFjtRKgXtP;` z8q9ZhtH!uN^=)HrY<8Vd4N~J>SFv{-e%1YXU*G%oy>6J~yR^^Q8`1e`m`{Newf7+D zRlCX>X$~q>4adRsRubK~)W^!Wto4ikLR)osqh`G;-{|co{TCQL^j)1Eml-{HoYqT? zo(O8a-00D%TCXyChN=J^Rmcka>8Pd0jVqt@TvZpuS4&#ajzKb=|ne%w$< zW6KY;JJ#wPn$M+UmYzAm;RA3dg=J3|H=j<{_n&2#mhyqH2`_3-{c+__d1MSz%QAta z9OuGHHfj`AomU@W7ogryCPO9Jk0?3qo+xJC%D7_v?R+n+_sQBf-KjB2Qiq`+mqR+v z1?J#!v@TL#D&N1%kh+ssve&JKiCo9d1ZS3xwYRo?(R&7Q|@^G);I>g`Wy*2?<{y0(ALHu_fG&+WL*+LTqlu0QKdN>#}E`ZO%E=%s#U?#khG8yDQ*T;ArIinH?R^BVx806#FZ{MaVEj z+)B5H6T#T<8>(*y2 zN0zv_>UVd#7TIat^N73<9|FjC;Y+NufKEbxjEl{ zZBFl(+T)$$>@5wu?)>R18>f8j!G~TO{&C)0xFmCC&F0dq z-aBlwNN{|A#{Z+Md;R?9kKZ=?pPx?OojPygobks8Kh0gb@*7j0s=Mxw^9I-Z-s)5r zD`rbo39|(;#@HOu;6J4b=qs7cX$58)tbheipOH9{ZO)jm@aOi;_34_doOyGy^X87~ zdMtPO)pH<%rohQMKkpo#xqtI$`{n9cy-&E+sbsu)1DG zyI)?-L^p#1<}S0s`SZ>{-*st04U618*jmtOOQ{9izak?Bw&c;Xl>rLJ&$)h-SyxbU#z#j(EWLf>2K=PRjTm(?!T`L6>vJ#U(}O;JqEByqzI%9^eBoE|?&0a<(=&X! z|JtU>IWsx^m9=c*nFVJ~7$f7DWptG*#xThn9PP}gucX{?hMZpaITww&h+a2+Sh=8j zlym0T31g{W|MUKT((gaz=Re=if9j9_)Sv%pKmN~aKW#tY{~FBTzBfc=q^U5t=18VS z;f>&Ln4A~}Zvjsn#P7Jk9q=w>0=x-4jme9N@F3WVd=OayZw99_VG@Ujz-y4z@Hn`J!C<4<2mgU= zfVYFkFuBqMcfdU4A$S-pMw;PK@HXU8coXB?;2z{1u@A0dLg#&WBe)aU4{rt2jz9!7Zw6mMhQV9K`~;;& zh&gyT6GTCH2AGRXgonX9kr2EI+=Ar76X2;1c>!mOj><+BihVGGEP_YDRY)Pc5gc?9 z>kM!QT#r=2o4`{}CSTw|umV{DkAklwtKhBRqfA<@g(twbkqz*6Fl_{LsqhT&ETjn@ z0yS2hBX|JW z3ztc>Qe;0o3jPR5JCgJSXEH*}fQLb@UQol}oIO(CWYTQ}yb-()35tF2Rb&FZ6`X$> zcY4AL!5O1Tb9fkh7g+#r2d`q{ZV@~VzB-n)gSUdWGnp5IH-Udb;$jZ|6)2wa^>`XKwoJ~-_x{5T4Cz%@t)yb=5y846bu z$sc4GydA8VMBM_9g3llm;Vs~&$P}?ZnR*2Y!NcG+qQm3hGf1x32Om6}w178*cTFL` z;j;7p)Tz`V@F3W08g&Ic100X6hljxXktTRE_>1XEZH6bnY1x!%u>;d=_~V-U7adw8GoLBWDt4xC7pSw8NXghmrm8X7J)1#m9%6;8vs$yagOF zi*$nr!3&TPVh6kt$$~e6_aUR<&EOs+2yX}b%_a@u8Q={_uGj~UJcsfLcfcr83KzT< zses49=koaW;Voe8xul_(gTKz_dlz%?;W>Qc@MiFcxs*wG23UDY;BUf|D|ic7cOKv7VEh9Ah-AQ9!Ey7Me1iwU50KIDc5vYNlnuB8o`vMV zL*Nw)h%Y<}rd~jN;Thnd3#seGKDhTH;ty8~mAdC*zCn01c-$p?cVY*;xtO{O-UvQ~ zG>aWDuY|mZhrvG~JK(M0N2QbpxQdY1<>WiO37lO){tm%DIOuY|5x4_pT|xfBgJ4q? z`3o1!Ud%JG4_=7`;c;*;G661^7WF|U!ZX05ktuKo9EpVBL9iUjfk(krHKYl=5$qc! z+VBkUGNce*2!`q@18~8uNF3e*7A>J(f=9vQmXhyq2i%Bkf;WM`MViGvIA|H^BX+>6 zknQj|_%hN0Zv{_YPMre}g7cAg;Dz8-$opa++==WJ```;#^S!`Zz*Z#VXw1Q@SKuE! z4nB!E@C11DHIx&$14fV_JPPhdCcxFT^bM{f&SD2#h=k#V;NL`t%c|JvalR3F2rNUY z;8F0|>nT6*7I67W>K1q$%)5cQ1s(?D$VM>-8&;9W@J2B2M!pfT13rQz;LYHe)s!W8 z5WK2^^nu60acfBvF$Xu?q9`<^Ik@#(#2wxO7B>=icoZCPD{+Tsfa*5N30yD($q{pK z6_N{Y1V2NtT2c7|5gRF(e!K?4&HR0f9WD~p@?7xw3 zM(l%E-Ax?D4)_4lB6h&O-zSb@2mChD3U30x)EerrEWpi!W+R?kd5$Guy!-)1CN8}|B&(k zF9hE}c8DFY*N;dmcm_BV*#!@SxBr;5f;WN9NIP7xteNix9tHo1?1Q(02arC;5}uz> zZzCD-X7H1rQf9>bXS7+5QcmFQ;J_`!7w&*RMhe9~_~et6d3XZ+@l(W6%)zAz;s}p} z=WL^l!o%Pj$R@a)+Ph#oVTBih+mJ2r7VxHDlV|Wo@CjrGJOQRYLwffxE6UI-UyD~K{~*L;1!5Ej&uO$JV$)tVQ@P#0^S17eV(!*=HR`^6nHau(hHOa zco4h~Ss>=%nJ<#x@DTVcQVMSYZ+?k1fj5GmAS>Xig>L~_1#brXzD#+AXMoor8{u(q z-cHg79tJN%9)%ZzHz8Z#jo<~Z5pFRDXS_xGBKE-}-X`ww4Ddo^pV$GfLewza2ao;> z`3`r$^?&7?gg1dtBM!U;eD+hJ1xwQcY6mKjlQClEGpH{!tC!NvUoDhQ8)3yuk>5WEm!swK<$G&;Oj`5gE<(SM1H{q2Tj2bxB~`} z(P9psCpx?kY?vBQ6X1>DK_moM(*o-2NG?1KK8!4YH-l-@Nh^2;xEU!FbMW|V$|u|b zi;>mvD7X(<3s*A&>NsSB*a3@>jbaD|`L7tf;H z!VAIW$UE>j_z2PlZw5P%cDR~No+5kUVQ|kmlx=uBxF#>4`kX}E!MBm2@OJRIuaj=@ z7I4J5q#Ha4zLHP6!CS!#&Lgehh2U%FQ!d3E3@jiW;2GfgNKEX2-$7Quo4^l|I9y#2 zP*)&p;Zg8$WIa3qo^l~+1rLHRBOBqZV8=xPwF#~k22>T&43C1(B3s}s;LeNrcEmnd z{*8coUhIIym+&142j5#ny20DQGcF~4;34oMB<*C}zbv4(7E+erE#SDKfO6nLFoFc( zQScRH3cMApC?-wB9NdNEi#fQogz^oKgYC#7xZsVY!~xz2{ux;z_Q9bM$`9ND!^m2= z;09zpyb0_;n&7I8G_Roiz%#(VAqjXp`1a*|U&6uTt{}c}2dqQhhsVLkkiGB(czjiW zNe=9Q7bE@Qh2VFPq3|Z~ATk2376;T>HGDhp5SUWW_X5uVUs}p{0dE1%0;O^%rpYV3@ug_B^g@Y|G zkauvwU%W^h;R&$dCE^7y1e*76QVI`(wX@s|erN5^P!=vD<$R;rd&-(-U3ois8LlW==xadvX5_51TvPA8C0lXc| zc$>N!E|~Tg!XzAAhE&1hVEVi0Vh&D2*1|*JjmUay*!TXS*@MdriGD7TtbM}z$ z@Gy8EGDYlwvA>h=@HjZ`AJS*S9q{H4h$Flad>2^(ZwCYIlsR|?n1if^hrt(+4e%E5 z=)L4G+yQS!w!j;~A0s>9&ET>BB!9&YcdoJyL2FCv5BE#St|VgeSn?A{*c>;3@r5)JAv^EJHTIqu^7>X0Z>R-akb>4iABkBHP6r zJnHZi)<{S<@O9)(cq=&M2+~T-!8?)n;Z5Mv$Ub-rI5s1Nfg}Ec%aNh*I5=n^=>vDb zQAehzpx6O-9Yy-UTfw1&Q`ADS1D<^h=>QLbE00Z4%ixXR$m57RJP0mB8sTy9Psj#% zE0`EYeBpxcA&O z#XflIiNtp_;Q^N*{o!$N7cvOm3QltA2J%=44!^cikc|qVCl&zDiDwM961%Bhq; zu>;OWTH%G@-KV9fHn9WlLiWR3!N6$B-x$&a9D`)QgWyk)q3{HF$Ub;0=$x6tIF@(8xk!I_7`zr41doHiM~1;$!6VKht>78pG$aTQfodY@ z1{eI(B)$u=59UwiyMTwmCZrH9c;4Bh8@v!~MpnQDdrcvI;2Gdr5qKjQnMyfZ%e&khnGx!&z72XckWK(9~QScdLFT4dDGK2Vx zBTc|C(jP9k0T~2u0{6@$?cnX;vRQl=@Hm*7OFF0mba*4UC69D~C%^;9 zGPwFW`HZZ9H-qEPC2sH#_zR>-?1M+oA-&)ZcrUVD?1N+GQSRYEa0l`ZyakMhi5FZj za2|095;kx=G7KI9|ALHww}ThXCr{ypVEOqeY6?6GUXSF$8^L>!e0Vds6$!&zz_*YE z@OCh;fcU~Qz>|5C32fx39aKf9w2ayE4 z8GHiS4o`sVR+4}4MsVN_lvTI`{sVa*-VR=PBjJY^g0I{}o{lG8;4fBFr@<58lm^Nq zJOn<8Oc8VNWh7VZgPYcpckpJg1F3+kbt&qXNKEX5BfiD=2oHiUBJ1HT;EG1dBs>o8 zMVjI2))aL$k`QxnKk~eof19u)yWs8MYwIbW@K*5qw^J9vo4}`${$Im=aMK;6FT5GN z@=o#+9tZD5MvFOk5Saj18z}!s2p$CMkX*43?nV~C+rd-rBEQ5ASb8g`>B5>kiX!|$RN1$K#F<+83u0wcOxUMm0$vD~B5`;Wd>L5< zZv{h}Nguf2SwALCgoC@9iM!YVpZ^Kv9Nq%n`!nifcr$qHqx4(g4)}fKeRvZ%<>!WWkp*HOyaQPXZvr1c7Qvgr+kQzI6LWCs7Rn7g4rV<` z+QNfi(^Hf;u@9b@AU)v@ScI&CN5StQjqoP$H^>Hf3;2tzybo^&w``;BgD1fMMz+A! zcG6fx?1P6rL%PE=z(@MbXc1?m=f5Ip)tzCm~)*#9Nc`AqDC55Gd%!kfXjkSusR zc=b-w5FQ7^ACQJ{!Q0!Z1K~|z`F|4^coZz%OI(D5&mtS(E#T|_Brfn)@Rg7GHiUyC zKcNnR2f^PW&x?I<%Rb5sJOR$#Pu&U+gC`vz{9+$u)lQ|IMLK|4fmAgV9t8i4WWig( zveZ;H0UiZk@108j1#|GFeyM69yagOMBvnHOU+@*gfwzLMPbV(I!I>fA0uO_qB2(ZhJ5`;6`Yz0dEE0 z$VpYpgo7u|!auPO-Zz^#!<)e;&Pi2G@C3LkH&s0(_Q76x#1WnW_WOFOdR#d881lT> z2UE{YRd0$pcqP&bkAt5g@4!`ls#-CJG!b(_WG}oO+%uPaoCF8IK978ahr#7Y7Ca7i zAfw?boT_q=31SDFc^-Kx9IQhYz%v%4s-uyGa0eWPEP@BYI;0RD2Y-cBz!TuJNEF@z z{tk)3TfylUkZ$l0xB-d73olGn_aLj`&EOWK5uN}yUzDoW3kTmrs$@>}KYuFFi~j!j zKrqn%Fx7uXpWtDIy`#OtX^9lps{`r1Rr>he!Cr-F(bRBCB9O-X+Dgnxx4>a(>ah8# z!IZ*4v`233jW_m0_lxyk+@8Vn0CQJC&~I*^%lnplu{epjbwhAIaqQbm^_|fxm{yn? zO=eAwcn?g>N6uPm|B<;4TLebaTEV+SZY0C5kFTZ$sg}~$-W~o zTbbnB^13Z)@@-F=c+<^W_G*c{xc9WrJsVdEi~WXdxFpUt&%F5{&r?#A#3F(#Y?E2lZ?|R+zhU17n>WKO2!M=rkqKAchC(>F{S`YbFy?%M!@tXVVD}OjL z`l^iL{=t5Q>CwL7K8fBfX{{;k#7*3|*W|0bbFZgNc-@zDzt@-U-nh;8zAL~G?#GNcqdC!f1TbpP4x{NrRyDUT8bNzFOsI-Z}5xKP3*qy`JQarS@h&tt8xaOOB$)>g6 z4e`etmY%qM-|N1Y+voo8$L5vyxwoI*Q(c?PZR>`FIa#@~-=sfZ#lH7l(XEI-D@}Xq z54+eI&_@jjoTR)pZ)aUs!TfKrr(B9#PaC%+9e--leqdiUFfdwm&nXioDHGl_x8bsF zm_NU49L3!Gt@zW~uZthGCOq=4H{3ntftcUhLpx~Q@`l|XR-5L2|NLR`e%n3ynXEmK z{POlo{r>x(i`#D}iI2Ce9hI(*3LL|_NB5qW+ZHBE3vc=Hy5p9cf!)iE`2V!uWy*m! z4JFLq?rK3@f0Kn-(&KG!sl**`SloCFJ~SSZC(yOy+KJ&ic6PI-J)+_cq^15TcDX$w|f0L!jj3oIbZhPJ6Nw@tHf7rb5 zil5%^SlqJdBix2h-s#CbvF8taGBdYK3_P?<^i<}({tNepTf!y%A2An^Fx$G!wmDw= z_I(=%Z+s+=>^uE?tNsJRbbr`=ng9{cs;{wu!zg1_wg zbz43yN?2?j_v@wl(MERal5QfB4&E{^b=eGGT_$N*oFokg^i~6wF|UrhZawDr!!19l zU2UDXldS&q=Y%=+)PrQbWWKJeO?_r31< z^DtR>(tD}&z&DkyolTzE^5L%o#eG|@z5ZJJUcY;4tE}Cg(Csu*X{&~cHy;VQPJhr9`_;s(F5-yu3Hmu$>k^aUj zzW#=_XVDusG4tl1wPVq1*URm5i|+Tay6gLJ>)i%j@A}i+te|hqT z$;xSQsHxH#ed&{)xp~qCi7qX__pcGyJh>+;Vn!z&nBrxMgu@S9{>iN1L}j zx$RFsZ#na)fj1ofv`%JshG%|wy!k%8@lIAhB{Q?>;|;6V9sArH?__3uQdJ+;?A(1U zU-fX7Y$wgjb!s65@&xuC7GEGi=foYHg7F@<1b;6GF|KG`=|Hn zmHtZaR5vGNUqw&v*?4&KTf%d%x76|e(DWOJrgqi}iNjiYwWhWQ!kzB=zh@i%WMyZD z?UCWGwP(?WN6?$LHvC@|z3zzH($GS^W1HN4^zE9 z;=Ln!sUw#4W)6jS-{zTwN9+i$^x3sxJ+`kpc3HYQvZ60zogrP{uGd{}e)cqWvEi4n z6%SLzZG+Xty9TN7j-%8$j~~e#&OqjHGMK{|z#PsI)Q5*tAC5V+K1%l8dDBC}eJ^p5 zbQmvjPO={7%^Ppn<=tZ5J^ZjV+CF$K$Ti~`geM#RW?O{*vq@{J$4dS+S ze`S)k)|;j_Y+`2HPiyA?zO1?AnScGrLw{ zYdrcN`FrxV>Pm4qRF>wJi;ZxRtim+4p*T(TiKMw_e&t-ToF|rZ#B%;z&T7l~YdJqG zXP4!?ww!I2v(a+)Sc3jR}%Nb)iLoDZ=`tD zf^PIZfISDtwsKfi1HG)ATj5P5q1Ha^c+aPx29@tAHfQComCgGO*1fy`dvsCT@lzU9&PE@&LSMK|iJ3{47 zQn|BM?xdAFXEO-9+*K?0(#rj{a>uOPIV*S2I>a%I#Q#6`-UcwLqud{!O#&o^mMx_% zt+Z}i+R~Pfg$7Dn+HOb!NeQq`!bdB0Hzb>nl8-gnK%l*LRaCrIZ`7)&s0)OYLV&1P z(OcVSsiJb*SgTU4HfptaMU7goXi?waGhb(BCxLWt{QuwA*8`Jt&TpQX-^?@5%$YN1 zc4i)U=HnXi(AuK3-Y=~;N54y^-}TV%Z|QfL^jkvuogV!riGE{6YbDTcZtjFFu7<0F z+W@x(?myr@3AYdK%W&U zRk-iK{S@x^a13>A5?laoKHOrsRd6x5jd1UV`vhDU+-KqX;GTo~3EUvu-{H<{$YGbj zO@o^QcPrcyxVzw@aQDG=z-@(l81B<>d*BYkeFg4YaL>UF!2KHTHMnv2<*+Gm)8Xd8 z-3GS;ZY^9B+-A6U!+j8L2i#}io`gFF_X6ArxKnU!J?34(T?97`Za&-{a20TGhHHj< z5bh&z-Efb=9fNxj?gZSQ;KnxQunXa?g3E_1fGdMr16Kpr0=F6NU2q?S`y|{RxX0k0 zg8MeykKld*cM5Jy6Vd~B72GVi+u-hmTM1VWw*l^5a36%*0e2AY%W&U+#uXv z;l?-Tus6V63wI;jZEz)UE8*(k+ToIL?}OV0w+HSEa8JXb)n)kQC_{?aST+vZ1ERmg z#$%1HbFo*~M6A(uKAVKyx+Y_{u8Y{kYzlTAx|F>E`*mH$E@y9K0d@tul3m57v8&lN z>{>Jl*J01D8`uo&+BJ*K#@0%6*j!Y+d^Qi&;wCJCdoz}`y_GFwx3SyV9W2BO*dkWQ zidZpQ%$BecR?6;VOIaCP#+I`cEX?j=<*b5LvXyKVTaD#P?`HR~H(}@7d)b?@)oqkj zv30DP)nL)lT2{yESp&O|t;f0rO=z-Oux`Oyu!m0@cJXP)em)yn2iwFpv-{Zt*g5H~ z>_L`fZ)0y~?_gWlJK4L~yV+Lu9`^58mFyw*KK6e0A6S>{1MGunxE^L7W*=c6W!u=t z*vHu?Xp7x>^Z4enxGIZO)zpZMu;opo-0)O+rrq)#xG4^VY{b5Q^0Ku~Y^1|I*0tC2 zEvkf{y5n1CbN_0DY>FkSgg^F5#{S67n~Xc`<`_eS24ba(hiGnZT4#y0#QFAzf`Q`1 zzM9m2a&3E*rBRM zs53&_RMk_mB2|faRdWNk+XxvVw~z=oDQz$jv8gPH^Q*ST7GCz^PHtAqeOsF1*e04s zj2%_0tE5;?(NjR3_(+{d3QUIAC$25pnM<1!-PARZ1 z`j!@vYI$9at-=Md1e&Vav_OLj)zDnqqOaTAVy(I=Q=GJgrzWt9hI~EE;Ks`i-L%A2 zr0sDp#)h_PDs5FGBMm4EU8iy9nHg?8Gsg|3Ow~->dK>*x=4I{Sm50-sRv*EQQ8u_! zakX!d!W}|Qf*m`R8q9Ie7|5#EwX`(Gu)`&>(tR}<0ybgQK&&GXYsJ>MW)zUCO}jU< zP4P4~)YW4*Vnxv6o^7Tr9-JA&Dt4qE?y1K!h zxav~vsjlulgXQt*65@9w*-#xly?-5^1{TJt?<~fz^T*}6Tb>`2=O^U(oAUg;JpWjpPssD{<@vNckG)@{?>u?FNS-g3=jrmCFV73* zxk#Ru%kwIEj>_|W^4u!Vo8@_nJU=AQ56km*dG40y1M>WsJU=1NN9DO+o_`?EFU#|9 zDp0~?$w>*DV zo*$RzugP=2JpVwRUzX=Vc|I-AWB*O$!!OU5%JVdNo+Zx<zhd=+SuR`zts;@#1|EjM-5C3niug6&tUb+*pLcDHbN8`o{ynr{fG_yam zV)PDM(_wa>Z*fa2I#SDGZEaO`u>$O7>E@zGI-3ct@|Q0m#nJLin<(wnTAjYfCGZRi^u8Ej8_pvBel_SdK0wIH!AP zNmX-AV{A2Js|h2@f|?q<@wZ_qVL~c4wIyOrl?@2jMlsM8>n5MdhU)c&{6&=gC9AX< z`LAkh*z9QH{Or=UqD6%jWk}(oO^H}>2g8CUxZB`}Vu6w}jEP8H6n7w{_h&D|FiZml ztZZ4`P!lVxuWDsaWZ%^uYuyyazSE>l>?6$+f)4hWobp5?axYmBk6gcerC z6L_C1Y(c@`weVcR%J5>{9#_IBG86%}cY@EVhSmh$omMt)#Fzs1m&mDzB~~`qb8XcW zcT~st;1e{0Qf9q56^*f2oIR0K8Eb87XvW)+Dm?adPGw^o)U~Rru|39~%NaHjHkczx z5jFukV(j+{;n~HGP-Bz|DqFN(Fftj5L>j9j)h#u#IE*Sn?<^RRj6`ZMVAmY$Xh>jG zG7@QMStq75C0sd7(jXr4u?n%e3jJUII%qY;c|d_lR@ z7pZGXzzXK)vpane+L<0IXkwrD;Uyh4Kzgyq`2BkJ=B!B5dI?r%MPzy!vLbQuF4c@H zdNZJ9#V8T?HO1MD*%28cKReRijCj|xoSdq4Ev*TZWmPp^KG=kuDhx5u20Qc~k8w$C zBT|hw_*SHovCD8xp{~vm>Ax|R`9gLPP11XppgZ5G8<8(zI)tO{4{@i=^2aMe-MP=^9%Z8^L+Vi=_Y(+1qt%?Ywi zI5*dkjyLDfrs<@&WKL78sk$CodmF!kCwn`;!k`x0LRTmk?30y)tn(lr#T9?MWZQ7X z-&5JAav&rq*{A7x14a^ADu;G^#~1|LpM&>8&T@cX5z9e-)dDSjj;>^R9HQ%5G63vL zM%Oed!4A_^b2WnfCtbzYwXSE6(-n{O%XHO7yJtPYuM)`3H*?x}Hedb2cagV871USlz}`f=xW|k?jADTUuPc zytwSfxqLVu{l&>h$G_a@>Y%A@Lv?FHX;}5l|6h3aPr;MPJ^CNLl;bIRb|wCW{8MS5 zb1EPgwkohD8-U;tcwP?nwu0Z9R1Uj7+Y5Dl zHYShYOEvn2_*=}sU66 z|C@za+VLfQ7W`WgFUjX>`8a%<@!fnm&J>o8vNZWh%ntDB^b|p=4Lx8=XB!c6xzK9b#_e zIgKODlmeO+fUedMSb#kW#yQZ`&Ct|L%v1=%%>!oVZw8PsW*`(orktl>7UElonG!yf zr{JIxA!b!3bSJbWbUP0WvoKEq-=q-s&6qoZ*t6-+*}%RY*+?^D^4O(TMah<2nF~+Qd^8L#jn; zYBAHp)=z-jV=GS`S=J(++A6LqvW@@iM-=OuQX*2RRB!5VsxNgk#gbS<6VSk}6T1d? zo!Z5^a=ZLpQ@R3O)4PIQ3%WvGC0*gJHC@rJ`mT6aM_00IYgcF2wyspyp03`m!(Dw{ zN4xsFj&}`oo#-0uI@QH?=k6XjaN@w=fl~+A!Q6xXgHsL$4o*K9Jh%>~5JZ-rte`-o9keZ$frWT|^sghJUwI=m?`2D-5 z><;XnzB{;k!S2xRlHK9mYj#I>*YA$+?%18&y>)lz?rpnMyZ7ww-F-|nNk`*$DT zJ+S-4?!n!scC+r>Zh!Zb?m+kS?qK(V?ofA0cer~^ceJ~{JKo*Vo$TJ)-PygZJJr3X zySMvrcVG9>?*8uM-2>exx(B;Yb+bo8drS6)_paF+-CMsmzPDp)jww3=JErdl?pUxRv?H){ z`p)3a1v^7KOLm5LuGtygS-&&Bvtws+=hmH_JGbpj?cB4ocjw`qeLIit?B98O=fKVr zI|p~3+R1k1?(*-NvMaD_`mW%v1-nAKN_K^Jt=SdbRlh5~t7BJk*VbK~yHdN7S|cOR zW9}pVN2WXycx3t`!ABN65_+WMk?KI(ro^k~VW;YX8?c0Ri8(bS`R9_@Yf z@S|*R?q2`iDSHEZr|%8!U9i{GQQzL9d;9ku-#f7P#NNTZr}naax%>S4rtAyso4zl& zZ^6FMzLI_6eQWkb_to!9_3Y{C?K#}j*K@R|zvp<*K+lPu!Jbn+Y=7>4|Nbfa1N*1% z5AI*EKeWGOe|Z0z{n7pP`{VmN_9ypm-QT%?+y2!4J^Oq2AKu@$|LFey{m1tY>_4%8 zaQ~_O>_F}T|AD}P;DOMA@PX)oXN-O;&Y+m6(ZJv(}L z9Ny8l^QMwaL1_~Y-jFH|IR5pspL}o_U!B3cX(glzN7p4_Z{Ciuf6tVjK+p7^V9$b{P)|uuxMxjIw5Pr&-qX>O?AhAW*|V*Oa(wpOB7J?? zEQM1*)|+Ump4(F|ujl=#fz%*uYa}TqTRXGOY}?hh>*%ijUB`EYhOAwEyiTPK_8#mz z*ne=~;2_oS{%rotVyN8#)a(#ybu<-EC1Ls08ug`A8vU?+$S1LeFiul=D}akmaj)_R zY#wzl^^^-j(fdT~}Q_bN;OSS;5(u3y7Q97zM0tsGHqznPqq^ul~Ok2R0tM7S^viy8NIZ)HmP9Ivba&y#GPEIW*xMI8>A0C?G_(EZP zaL8)?C{M!`Fza!-@5S|8T;=V@1w#M~+tSyD#)dZNr0Ys}39Olh_Oo_V%5|(&t(Z@l zb%^3Ku?;Ni@dpubOzu1RU*gdIm?c#Qfg>sI)y@BYz!1RLd_yZf;$`(y6e`$84ZlDE z6&$Z?LJ6^~pAwM*H!Ad36uUxeoA8B(W&M#7dyZ5~OIy6LDnXyIP{)09@p?Wc_mh@C z=6A8IJnp3eq55)kQaajHbsy|L>kSUx&`kI=j*rEMopp`tQPM1X9&sUkZ83ZdYDjFt zN2HeZ4KbGUz-{D#`N7Z?8*>%cAD>NJ!^X_vC4f6Bk1_Mr9RN1w7P=dgdoKQF{}H(v z8>y+<#OFY=v2jsyHEoG?4OMMy>{}k>dXGY~1`8a6cyZCHx&vN%#XUxTugHt7FBNE%2iJ#{K6f zAtO9uZ}H$Kz6tm|e7ZnW))L1A`#P4xOaHQGG1fA%xdqb|g&*$FQdQ&o3)beuH0=oH zYS%V&MCL@+;oB(7GO>JtWt-Rnf#pnWYypuBHHP1@u@f<$8ed^zHTZ;wDU{JFyYplX=?mSoT#&SMF;l*q3nOXW7r=bPn2tc&u8cwG9hz`N&to8$A5o96w*> zi9GPBv~CldkoVN8vG~48UnBF5Y=%zRBvMA+)1-%-NzE?}7k+EJs{)$t?^Ua8S4l@Z6x!?Z`I1 zFXAKMbYI@FE$2`|YHC>Ce~Col10&0OhOToawbeJ&;sJ?vJ?~jUawURC7#glT+A^3; znAC*t*ZeCf%lr1n5S?Ej>+p>(?>i(iZBk9c20YhT-t*)?eG;)&FA3?K)YcZ0VSYtnwsAm&IZ3f@=YS0J8$$L_EEFu!f}D#<<#~e?_|T-rIhfOr zx%{%UX^Uodcv9nB3;hG3k58f+gAcIvk#+pjaNer~_rWx%h^m@nn2O7570JZfSl%DW z|Hvdv%xFd+G76UWC&G?Ss^vCuif)cgszrE~_h-84pHz#&WO;v~o97{hA7bRaMmNVN z)mGQz<}}^BIH|VnE%=t5_gA_bm`vYa@vSwF`HmvLC+MEOxXSy%$!)0jc=RD|%S;KDPH zdrlA`c@^arBYn@|zJB4`j<3L|!lwUt?mtIqekI8)# zA~~ml`pF{i7x)G^PHlw1sgaSMlYInV#Kozb3&X8xK=UG+_q_GKn=eF*z6Oz1u3TOm zsVFQdE?QYuY+~Vp^2*YJvPgOHl1Nc;xOjO{@$$mE(fWI#DvBe+NM+el72&edN{Xq1 zWqUpVYV{B51Oxbn)Hn4IWI&DqUV!R9wiWdMHY`cu8@2q-Zfh6!QY8V3&FRE5enL zf+Z{2S|MR}y4sHmL1(ete+Td_J)igL%FWjD^Hl3;;hyce)5JRcD) z#3L)huz!lXklVwRo{TJ(ipp~61f_75=Y?ujP*%ERc`@aE6!@n zM@2!&Vs^ES6_!;Nv1@E>Q6;<9MoLP#x)zrr5z}q23d8F<+iUUS^5Wt!yWT^K*HlIp z1aDk$Q>1Xkax@6bD=XLyp7*Na!parprS}v^gz2#vp5GE!1ga%(m?9OF8&sAuHq(w?sX$eLa-5m+9Sy9gBdY)vCh!V|(1)yq)Yz~h&wFt}MWxggEB0WcS&XbM zFRjGy&^=GyWGtH#SyfsPfkiIye3q}Mgm%LPrR4>9P_PouNA&=xk0GArrG}?W<6XQp zV0XGcC8eTIvDEXD86x$uG7lD}TDC$yAS>81&yS3AO<~EBMQphZB1b{C!ow&Z!s4jq zVqwomn3%LiJRZpVu5|Ck1!Z7DSBf{xia$&9y&Hr|gE-Ao!lP3va<#rJE~%`7NKPmCT$vWqG2!=!lGr!=7j zi!h`>eKroRp_(E(j{JU6#p;5v>?d-7r+JJ>^Iuh(u`(s^|MG-+Y0k-_M4i)t$n_f; z-tJi51zD8kiz79dp&h|oo5#6=!rULKJ*=S(a`uY8U089%YCcu4`84j#jViRQx%{YBo% z43j5%hq$SLm7;N=`-u}5<7p!M=l+TG%v)Sq4#OeO^F>zH@aH3sdJ>o5mlsSdUIl&% z!S5$eTqNSGK<^IyUC-yDiOZJBgkG%DqJvE_5~RUPWU4f9sRXD;&Dq|7>{ogeQw@I| z=(35+3M!UHcrtmQ%LTx%-^kO*F9Q?NiKJ*Fg)pWHJRz=N*-;cQe?_|sMat_zm}M8> z`kb0|9TAi~Mu=lHhds{ns&h$*Jm%-8dDRH7whgWM5jS9r`*NDYie@~^-b1mGks`XL zHX4)OfVuD(u%a~q)?pwU<;5ihW#|Ow8CV70@a|qzURt!I7_VKPY)L`I>SA=_#v9n870WSe zxr|LPu!_<$^l5n7&o$ts%gazdyyz;H-c5Oo6s%e^Z_Zp)70-)0T4i``@{lFP)bO8g zAWP@tP016$Qwh%?c7XvcU4YjkLtE-FG&=irsdljG1_ybh&7H{vxY z4a&#sjsaEjxGqhH=Hf-ile&jGd~@)Y<3ThwdYSPUV0oA1{f3NGH?l16QUl?QYb%*4 z|1K6;hu`Yd&~J?LuE^tK%sgB}b9D=Sz;lGI_(~cW zJX*)b|H?-qfU6rf3*>hk$)TUqMCcpOgzK>)7R&uA#C`-lW>1$Z&1sI;jI+D4!jK6g}-He$CZ@L(puhBa$S%@{s z#$Cv+#VOb4E4{!6fxIgadiHqeK}wD(y+BBgztDH>B|>Pz7*28SHAu*LIY<^oPFxhj z#Oa`ziWvM?!2A3QxVQ40bgt%K0Fev0?-=DfS^9#Ld@nR^k>`sHrZL2H@x_RYGBG8e zEg}9fSuoarzGEY@l*Q-b`h2gQcP{Poi5i6|kjyud58N0-RiFOxOE2~9pJHHnS!ymp z_Ew+o$}8*c4z@3?s|(&%cIA~>m{9E71+gqft%XBfc*|@xd0@79Ob$DFKnaTTY&1EI z?fBkd#$bP%R}wONG@aoL((pCsH=IFI&QKVE)}X1@L`|%=ZB{)gx-CJADv4|Hvng>c zANS%0zZt?OP+X&tppTLQrLT)#hG#@yL|9sk@Kpt-+)$AJpj5tuM8H^u8N!@70iP<2?%2P-(w z|Mskc^QI)To6qz26`Ys*)qigN{Iln77XQs6!&-%m{q65)3VhTyH8x_(l65SWcRm(i z+0sTV0o>dL7muQsfOEEw<_CI$Xtwx4zkWzY&n)vE$b{jDON9Fn?&zTQh+@ZYrs2ZT zGskljGSRch{01_Eku%40A+j-WmUwP}O#fMA3Lw*W7MazM={<`~6J$D}7+w~Pj<*2` zoh8&B$Y8>)q17(|2~-WA_gVb6?3@6hAm@7{o*ZN;-Z6`>t|soOtcJ3US?lN*|Ki{! z=tDGV$E*%7BI<)?`|{Hy7@HOMWGIGgAN}HGf+KeviKWh39+$E0kc5@ZQ=6u3ejQ%; zn?0*nc@Ka{88U+!AsKo}4B%V2 zC$kkYVGH>%5mdpNa2l@FIs}=x73v6(l!ZJ8q|ZWL0y1bJCxHa;_Ti=HH6URN!R8Sx zWg(M*3|h$LKssUgUOY6pZ@@x|f%wlgWh#I~Eo2>#UJHp+JQng+k~z9ml)0STOM#&aQRK*~a<0SQhr zW#$2iTSzgG0Sj3Lr0)VV6qcE0gBC)II{DF!@^bNBAR!C+7?7lebW=PUAzMWczrl~e zYcHP9L1w^0o&XZWxTPmUbNpy+Z4db#kN{rWJ>(ZaXgzWd`4bRoB0VGz?Lpi^E(X$T zA=7|_@k%U0QJOK4s3EQq#L4DBrW5ObdoeGhcr2s@$bf}Z0*PV}#|sq$62>5ghin8g zXd!O{lEf5nFFiC>X#lI9dkC$ON^6sQ@jQf30~+C)uSU!op5D6dB2R1t4-tvAXu>4khvAe0)W}vxzE9OAoUIK^Nvw_4$3}2KB7iu&>A1l z@>s-`>H`FEOGcdS3*eONGv#K9C0{wjbK&d9H5%fyV+nE^)GhxVX};cb`48}s&t+N$ z$9XW9Bc5KV!=d^=6mbMHgHfr~Vfx1RLnd^sC<{tA<~RbOT?MEF1@a*v_=&H9q$p+! z*$0Hy^!Gx29!S519Hn@!S27K46@?f(WnqmF`%92XTF7rH9t$}Qr1u6D&-%Ia1Bn)v z!t0~Qo`+|9aHfe|1jIi}A+*{JMt$2t8X@*skm z4M-GSJ+Br#Nby+6`+)RY$aWxu7P22m;6^i^F91nt1oeGs1WWDGt`CBXBdxJS6b9|F ze}%XtBFgj_kl;L1<_AEc7V=9Vofh&xKzc1?Ec!=-8sY3HRR4T4=8GZIX(87F3EX7L z%m)&;kR?Ep7IF`e{+mUpY=*Uo=Ar~y@>YdV>C}_VLKA5N(tDf9wFQX(c7;$p0u%W@kO2$%DUjeIQ|2U) zL5T<(`x}rzp~*fTz0Qz@TmmFsWXfC%#9wS8bASXEo5<}zXgLLuuUPG@c{k66lF`CZ zo(1m zbI*Z|S;*x;f);WEkhq210;Dry#=HcGKWZYCK%y2B1rmyxGEG4GE#!V6@mf=crd$W= zOk^97l!bItJQng8g{n70eGN#`LcRlJz(RfsB-mhv`U8-tg=FK6EomW>fDC9v)h}T` zWY7O~5!O*bQFzCw)h}5uf~qC)(OVr^op-1am=magq7F`n_1lN)eXWJ{iaNL!GBDh< zgX&lB2?Fe(skH$(Y>^lGG?|2zx!++l{g3^K`0 zW~f;}f)6N!_U)iG^ipp%L){9Q{s)x|X{;DXJZU1UfcW2LB2_@J^$gduXp!DRG8Xax zkWLGs@egcQV}$wykUov5`X%g#>eqRA=lsV$zx=2dqVB|D+4iC8&f#2DcM_06Lu?%C z`9-5)RC?LIxlTMJPW5ZBO39$xlXj>P#q|g+-(2WL*r{Q?(AdB`g${?SUtfWY|6Njs z^Be<`w2(|S(nERwI5Y)C7)NI9A)-k; zR9i8ytaDfMH54u z@|psTCEqVKHl$@Rb{*+i$?yc+LVErWrDuZf1d_6lyMcr{O_}?E3|h$j6we1tnfC(e zw2+Sg34F+u=>pPkA)ljo9yVpZ3ZzdX$`V9Q$r9+T7sE`(@p>#FfN+a(}RPFtU48_y*DrBM`RR|VJSl(dB@nuJi;AdI)qR5$Pi0Z6BXTnl7CBW)Y8&T(C=Il0{oH3u?>kxE{_cs#cQiGI?Q zDWP~Yf>FtM73TQ*Kc!@r6jm;ypka;B-AaT?eOk$YxUr#mJ?qs7$wVL%PbnEf62xU8 z?*zhjm@*##(rY1~CYfEP%x8cMcA3bNKmt7qsY+n(Ts7j+2x4H*L8kA3k|E?LKza|F z$Vni{UWL@QHzHrvEc`izV3ms)e(Bphpb?7aPY4w~BxJ->7&E(AzeX^gP#D3l!aF~2 z%3KVYJ`1@Ti2pHDW)6^mg%kq`f5DVl38d3P8h`{3n=+e$#4ThC#q*y^MztHFUQoNy zbqz+ODRcT5?RKLG^<6wcPCBiNYBzGwOA}8J`WA-{lX0kaBc$7n2O&DuiHrBBN6>Ek z3L)haA2S`D2MFtg#`>kkhHE!=kX9cTS`{_-KY{d0MA*jDKn5-_Yvs3r1i!4xg0eUO z#9yV_Lo~2x3)DfeAc0uqp{2D~hRSAbSh$@eLQg36w)GA8VR$UwuMzTp4Ka5m6thN@^@`FV>)m@1#?UBgeT=sC24R`PdXH-kb)l^HGARJ`9=0`vVEacZfk}sI?yapurLlYT$KAu(XWk5P5B5eLmK>97DiDZ6i#{5>2(TK8MQ95M3tI<_n$Tgt;jJEaW z!ZL;RzNjelSy^V_LRl6*`mTPT_NNPF;q<**Somq6cUUrX!+Y=5DjwHgy=`4>ST81j z*TmWk^F=)Gg~kR@iMX{mbwtp97&88!D?KZ%icqB0CWwhL67tA}Hz|hu3{@}G44eQ0 zovkPQveqiK*!H0`_9FTULSs`PKrwoU(tHSBWMA37m7b?@#e2dd&}z)nsu+^7mC8O1 zjfJJghRQopJ_?!6Uzj%kIUv2Sn8=rb3|h!HfW%LjGRJ|0e`zAG07+WN?|`Hq4fM6GQs~g<2fI-rPD$#0}}p~DKj02f6zqoDU^lW2_*14Q|2BZ{T9+h@%-MD zNdigz!9?B%B>t+2>;y9SM-%xhh5D0;JP9OvN+En5H4I$`|Ev(o`?n|_3;8~f_-jgr z_E4nNxuSWr>U01$w63LQ6NT*62=>Fpr=nKYKS9Z$nQx&rrUFx?)#1w#?X3bmV{J1L z&nB^hD`tHtg#3R3_FfD5J&?`|lnjXYVqwXP6hg1&SSqJ&KqC~--w-M~MadA7hyGFW z5``e1IfVAUK_PTE88QPJ5sSxw{W4SLD#-XRR|uB#;tEM>gyOjoGE;Qk2?~2kIcG8~^I9{W zOMwLNQGh?cc;;>(84I};NbovSri4PxFp+YSv5*Lms793439XXV{Tan~t*1_0jkeW2 zj5i9=m*}y0=tfyx4q9#T)H@Dzz9pxuE~;vrk1C3L@SgAptnN|M>S&d=w5MJ(G}bv& zXmzNkUM=lkOj}XSk}^Cgn-MB35n)m91k!6E9|7W@ZI;(gl933i5{`pF0&`56CxOH* zr{R0utIVNrVw7ICR8>P2l)eeeica>}Ao+M@7)8RFo*Q#|RYWU_t3 z_fB8%EDApvYP8xh{!2x?U?ru-hO#K4o(rw^DjA-Z0w8R@(6g|OFp&6VGCf@89w1>$ zCJtoqCNtD#Ae}dx$X1fEkPiXrzr~d40usDcAi|yx02x?lB3}YRvjn+*czT`&5-l*} z`8I_rRH0yXC1iE}B85<}pHe6bISC|XA^!t}6`P^5@D3lhkjX&$EaYk+!Nn>RXUA~G zfJTU&mLp&#N+wPdFEL*$E)k*m+ac4hWhhh_$UvzIMaaEC;&+-z9U)5(>cgzZN)8T~)ufqsoXD+xQ|qx zU+74uwF#7X{+=>|`gPi^!DE%m_6Ivy!n}mMC)ubeSjGEQS85Di0 zCGpV{I*m)tUk$+OM9Y6fr$b#R%RGhtmaxn|c-bvK$@1Rm2(0dM6rJpy;urYtH{MT^ z4(}0K9jaBw*cTsz?OT$~pVS!7#2jkc5;O278H$p_dJs?2LcR#3Pa|lsuxw>(B!G&> zd%`@_5h^bWc?L+zLVgH@-D`&W1&~n0ME(H89}`FxQ{^u5Mdkhy-WiHGqxv)2<(>>k ztMhF`-KA#UJJdJCmvy;s^*rU3D)+w5T#x@n4?hc_E~ zPZKugj?$3q<&X&?nSu-I86qCu7af6(E%t0|Lwd{Bh_xMBv2kL5oh+|mTDDn8PiMVZ zrVD_u1`}BVBy1t8futlNTBKSaq5G62P)<95^hreMsuM`RC9?wv!(<4rFG{~`=(Uh1 zNd`Zy^JJa@GSF-yF9PYr)DBPPS3tt8Ch}(>gP7Xk$&9%KTpLZ~d?0-t3c)jX6_%~7 z@o!QH0WxSIcK~7coAH!UJkzB0>bfJ!i)`%McjA`|M5vEZt2?qi zOlVtO;8=&M7Yntm=0awXP77VACw1UTnG4@^n7-Sq<~`wtFkCUKR~n_3xVUsIPKs)q7mr1*3)w}{SwdY6sf!i4v`Ki?`b5s9ksm6XLl4s z2vkBA+B&x9!aU#Y#rN)M`OstfL z-I3R`;1^U2fEg#aXDo17A?ObA!T(;3VCC=X_23JBQOP9ulIUnR@KbDhUSz|5#OB9? z|EUqI>k-3x-h+>81Vh`^*!`ma%L<{y{}H9!_k=>K+B>k?Ja%$^QX%{na;c{jLZSYS zP@y9N5v|s_m?arP$Ai}t{k#y`0O~u1uVw#ELG>|e)}m(b>ry_2RspYh#-aLJMR;C_ zcI>F(D=w8q4QPwn4i9_$kRW141PwB1&*RkX|jLH<>=F zLdC0^X<`uzYJ}n`La3C5gn@*A4uRCQ-*$fnv@7xIX2lK z9mmd0||WJ4E0GMy%w?`2s>`dJPsseAGL4E22=ofh&-AiWmy z7Yg-rGgK}{7XrU9kqd#OEaZ(O^NJ}m6G+fPZUvImhq)j&cP(gY-BA@>96w~%)OiT_e^@pwK=p?+l| zJAkm0CbAz$*h0Ptq}M{ePN9BnhWa*;l!d$qr1LkX%n2X^7V>)_q2DSQJa?AS=2C${ zg;1h>7`%vE$ao-q7IG1g(C^GpSCWi{%mR}9y(tp{68wWg`1T`s?)Gbh*q1^k{Hl^6 zWF?T$A5EkhNUw#o1M&ZlDf2cUofh&wApI7y4M_Y?W~d$@G_jOSTbTD_Kn`OV&qJO9 zlC+R#fh@3)7l6e7EMgYz&o6)k=Bjv9%@vjj)b|3u82x~%MBtx4;u^Z0%TjSWg24p(!r z$u#r-#Vo<`Ksqht5+HpRaxIX43%LnM@HI1@ML^;fQbF-pNHvhqX){za$ymt!Kmva? zW&Rz=fQ5XVWd5dPRKG5zk(zZ8{wvjfjgW%&B2NelT3#q2X>{)<9k zp&&2RaUcWPCh{_c8e<~A1ro|r2>loh14JqoIi(XIs#z{2J8YuH*ah(3_01p&yE=(Nyw zp&S0jI)Ym80k0M`v^Y;Myk7*MRjI?FYC&COBc?~i*npB@4J`udo1jVu2wzoqP$P*J zu{>N9%RzaTa0R$}HG=h{8e6c$`k;aE7Z>I~&kS_~LWM14K9H1!gn$fc1nJ>X2Pdj{ z60x=f8b_AY2yWO?gc{HY-rj4lpSYI z5&Vn;>+%OLRS3zv4>C~;`51-5TEZglh`F{AvzZ4pQY!$=4O21{&n|=tTF8DNp_^45 zB$>y71T<2MY56e>dGuMKz6KeZBLLx? z5(hNGaQq!I@i!_Ne+jT1K@-qsI^FPRD{;w;9B+NqAft@!#LEa$TqY{qSZpTFzry! zZa?~VqSYdq`_rW4s7RgSy2J5Tvz`0A7OAN!QSY=#lcDGSD`e?7sll?hu>=eVRqjev zf)oul8?1@jNKLG+*G90R-k?S(fo}v?;3_MgHW-7AU`63n8dB8}m}Z4)Y^h6Wgkru9 zF^4g+Thu0=LTu=l(g?}qLuNoDTn3Xp16Ur<2!(y!!WyAacOX>KLP{wf3#kC&zgERV zq3#6|vXCYqY`Q74iQ>7=MBV`;e7%Xh4@k;FJ_;mygDJBUNUuhCzOd(@e}*ZuA2OX5 z@&zFAnL;LuQ7EcmsfDV3Q7(=^CV9I;RBaO00@O#pF#b3R>SNSulYBqjf?6PI%5%~t4%F!X>|$jUwkAvHA`yV zNwFY(23qZ$ZI;dtfv^IlXN(!onl~?hPG3kN6z-QK6Es8p0Z7zB{tBd5BQ4lLxdU5_ z4r+wr8FwYheU2H=Bq047K`1=UtJeqSnlhI|CTtO&H30rcFd zWOzE30_nS1l?8nUp_ysy7KM<|J&@_OkQyMNTa^s4W8Y!crx6MjhfLr$B}2$&ipN6U z1tfTflA(BLhlqZSP^fK?NrtqH{6(0*KqCl6Q)faNNwi>I3_=cSg#SPcNOX}3MKSM0 z%<)1K=>gJdAzuK}Yaw3&(r+Q(0y1bJ-v#0?GGl%TNYFxl2_$SGe*hA-5Z_f`w~)y| z{KaO>mjekcF_G(lL`zI$K9J5*g^-@9q@&9eLfR;ROuXDg?gA31Fp(-C0~XQ(Bw1<7 zya!0XMtJYJ6=_~=%Ittl%0l)7iLX&IltTPU1nc{m2yJH_Sf`LWJe;c0vkO-%L;@^X zqY%p1VZ=PxU?NWwd!s^#s}{d4>9vqL(D!MC;&~RKI$KpJLVf@w&?XSHTD(#s=A~Bq z44J+%g{XE+)KhB5-j63x(nqnWW7OI)`K(-nH+IoRZO>91>a5zRR|BezDuc|2ls7-C zXJvGeZV$&Z_CJ;k-SBte5wv4vUOR@lYIZwD@w^6&4N9#J*N%;y1`BUD%i??>0~<_a zDv-Vo6S)RRXp=%{-2-~e^l5~zJb;&l0gX_4ZbGQu2UI9RN`SC`Gm%xqWg+W;l!R5e zQ>bPj!3R|+8W*KsBK2#8WHv!2nN%`_ydMaAn~8jaWGtkcWZrJdd>+W4L`0!K4J4q` z6JH-8^0t&l8XE-?)rhiHQ5IyYKld~CeM*!*M$J~`GdHzN+1S?X^tmhQnfoewGs2#8 zta?LcAGE`79?j zYIBe_mby!F=`Zpk6tO>vsL+`)j?va?NU{6;NaJLK2^y2F#HlNlR&9S0R$85a+zPFt zgU@wmMa5fy_z1N6pr_U9mR5H>>{sAPy;Iur5LzYH|A9=uk`c+c8uj#DW-T}uNb=n# zGL>X3uX0&Zgz4Z9mM zaVHA^V{f-$E2rAERbJ>T4is6G*_dMRTYN zWgAma9ywfQJN{m)y!lx_LCU2zd|MqmBthO29)bNlgT%<5aC@S5f%6F23LSPTtqx;9 z4?|`UFNI#|q=3X9Qe}bB*47BVTe0^kgi^QQCBS;|M^eps#GoI%l z)29*0&{ESZ@BvfiN0149$V6TN62*e|G%k_Fcms|!g;uIuDBBQur}8Q|2dhOZt( zzoTcf8tCWu({38Xtf*WtB9uVp^}v`dB>y!0EoA;qG}{u9>?bl}?|0Z69rni^_WuU8 z%|4hBJFU)SpSl9^xYu%F6^o%S!VVxBj{VSm73U+A#2k5IjMz2)BHuupT? z6At?fhdnnV_U#UPj>C>>Ve4o9kH=|5TAe>5_H7RPX;eU~Eb_}7c3SOP%E-NkUL2!Z z}a1XM1l7}E}?E)OLm_o)dWEV_4S{n8@A zt*qVj5lW=THyKyd?s$ik$@kK%+5{ubGVlL=hP2N#`#)jfqFNZb;RZfS{SbWyabLY$t@`&lJPS|abbof!#D(xH7Q zJ%_cPA)Nl+Bx~ix$b!&wb5#Oe@mAx-P35bP=biFp^U$5j7nL^G^H4QKwl-86Tw_DU zBhxcmr>73PMYqS}nA&X?{rYPd6X_Ygro0_8{llb3wO=2H%)nV>z6_bvHq%=AfrJoh zES!kxCqM!)cn^6MNT1Ws^mK^nooT;@Q#uSFR-r>&q#epOLclqfuY;~--US(3jjyLH z`c%0O)z-=Outt}~@b&Z|T^2*s)57w~X=}=g79gcOU%Yg&tN0 zT+{Bk=bk8J1Q)fd_Ce{HR!~qt=&&-f{i)OTTuq}`Shvx$Xk|ZPZc&skn}_aRkNxy( z`xzo0uIED9d}R2%3mKlTVfDjhO797rHJ;J}|CwZ@el}?R@NJ7D^|8iy4BP2eBP<NXm?0-b#Bd;&5d ze54TL8x-pE6ptly1W4Z*T2Tu1N67S_MdnIWKz~#)57qNj^+M#7>c!Wg`s*oreY~C$ z)VUa{U6t+FfNsa!{<13NExMGc^|TN596YK^8N$4#d2;F**R4w#JH|%ptD0*XW365x zvk>$X`m`*IA=(6r@gB$wq|EY)1Ib0qUYR}!BrwiI-b08b^C2MpJ5)SM^Mai;zYdzm zgb(9*J({P)@bvhQ)U-os^>MA$K$?WtyEu6!t;!M{T%{}uSx!5Y=D&o*=-x%5zO}~C zItAGaZS?LE+8C~WeG@W$xu#Z+14&uPFMtHPlvXL`?CbEmYfI)LASp{`K9JCE6-t$b zNDr08eb6DQmvOwFvd}5?l^8LIOH~#x>aw6`zkMhR_g|ylwn&D)MtFzP^H)thH^Isc zJ*#{Lx+$lWFE6~ha`Oc-79YrzajmTWqR_C+y8gq0moYNG=lUfJ}(%5Kl%P>b*ds7V>c*y%utiLOr5v zjDj5l(r+Oz1M%-MW&Q-D(?Z6fIqtWRX+YwSs!*<0FGUgN@pP&`s+32fRoWe3*iu&C zO3+H+fd!2XVd3&A9J)qXZwDkXg~&LRwG8UgL1!mY8=n*O%on%Vz$KOl?Ugwl!g{3$ z(=z&vULcf0_1@^wkG3`{wKj&RJ5n2mwKk|8+i6nT$U<`}+Dvzhky5`{KA347DBJgC z{B`-tr3|fzkj=;aaFKRIrHmhVwvT4l+NxC+73P{J89tO~#WGqtq(~cOdT10*?3eA< z=li7$epCS&vN~Hv>2Q+PAwHO40BWvhP}(*+b-oZy+A*5>qVl3r66G}m5BH(Vi+atX zyxw3JgiIUhhib0SPXJf07?mlNq$txz908>t>ZJ%9tHGl1%~%S;P!PgzMLa@3L%#(m z+wgQqZH0Y|mJZdka?J?p*O3v_FWRkB=RIv?vZ%3f84VYv&d}PZybBq!!+(6<*N!0X zG`2;Sh1~|}uT>bT+(SC=n8B53scCNY27Ds4J`%9rGvvJ%o4x1HokKqj%|f1 z@NTWc>R3bLEX-E$4npWIwQu;R75VRm#-cqWLr>XR*bXhy(pneS2+4d7G69Xus&B80 z0S%~Juvwd9tu%jQx`))XASTAn_d+#_Utf&(5H2&9g*8H4PlBseBih1wE~o@)CY0T3 zsoEWe54FK(>Y2^rE)9Qrwjg6U(_EK24pq)Nv(U2~`l^-Q5r^f3TM zo2h)oS+xoD3OK9|rGDP2^&>{rFt@5LZrIhgP`^?Khu2SIOLN_QO>x$(WOOSkLQx8- zZ(u*rM@?fg7a!KSsA;IJr5`iQ&o}!8-$yQbRSNB-aFwZ27BZA(YM*SuQA@LY2TAG@ z9KPL{aHbNJ))Lp&;upnl{8dlSU0Oe)lsCv9HY*+d4EhQ54qwVjKSGA|QvjBKY%8%v z>&G5BpzJ9Nr|&msv+&QP=Ur}Bqw@YL@*W>S-h~Y1eI`=ykF||Xo%i8e$Y~?U`;$8F zm_XHRzDqF15#%H_g1ieE$~#`~(~i-u7u!aV_uvTf{;bYBeio<-Tc#Zdzv>@B-h~Y1 z{S}0<%VX5?F6(mgOm$hd8#DuQ3{rBYmVe<0^z(wLpGN$y7jr3_tGsUEm>V#9`I)n~ z2||X_Lw#cV7&ZOKcK%m7&G_+WTA2dj_f_O@6_c!{1d-Nm-`UyyzDiVjG)~AtaVt6^-ygk5<YKInXdH{Z`o*93r>3>+C%?iLO(;jGa?k1>y+&_dP$Nj_!DGy>_2s`4Vc@LF1Ws?hN+$VBg!G92jyGH{l81^XeBiVh#M z>H~o`!fplvJAzM z-vjBlkg+pRbAN8iTtdh%Ok_Hc;43Dw2uQz$+zX`dgelVsBz)3D-cIrS+C)AIgbkX= zejvI8d77W5P`@)}z6WH$LSCUze=ueKN;3arB7O`Z^uHz$ub&{aN~OHx%Jg;2+}bpq zr^x&>qBjoN+H`7bdDV=9U#r$;P+LnM@Sr89TAQf0%oJLHH`y}snbNH-3VrUm-Ww(f za|GwWSg|*XJEsb*mK>uNGNhk+i-&HMep0yRR_8q`$eSM{(vM8@XLXv@i*W>OO*@iz{yA7V~GhDBAH5g{x| z9b^m2endQ!uR#de{hLwKp|qcVtsi>(vk#@8lOxd2-#q;cS>rm9_vrL9>*tdsbDgSR zN*f{+X=9&7G)bkhPd8?YD;y zRF9f+_yS})C&`(OJj=fzi?WbEkjyL@50@E(*S`UYU@Zc^mQGtDWQCdpnG~e?vx$eA z3WU;3mM+@H=@idwRZmGMA4nKWu6a+!ML^gb6Db1{w2;+6qH~o@e4h9U6R@~yA=9TU zlc-o6$iR&%6e0gcNWO`@8%S`TiF^=9?|c*44y5lU6X~XS7AQp7m?#UfvEuRA`-2Ge z;o2CQL8DbCLDkRH`SSH6hxVcB*JQLU;%VMx3*b(*Khv*M^=l7Me6BPO)eqMi^OZQQ zi)y3FkqXg9wGC;ApM^I3H%o0eu?W(~N#+)%F~W|LRxRXtlDXBC`5BO;MwFff7wP$z zFut^>x$GbIf`MD+5b05RW*10X9ZE(%^$u%258rF**Lq$E*0j+T`Cd@3b=b5HbIvxV z_cRBQQ?^j#eWgE?0JJO3(Ws(Mplh3nnYOm4w?6%Y(u_R3K_~f3?S`zJ$d&l%@4&T?U3rSsPDr+ zPZ#RE58pd|m(Ke}{Ai-3$=qFwvQURoPRhIwWrs2p8hX<<5(pL6h^nU|9@5WK$XQzd z=XKQ6k?3cJ)(?y%?NGK+qV+Qk5>SM3DBE}eEw^avHdeQ#*@i?|xL^df!DT4#R~ang za<>8Xeuw=;M(hh5_Gu1#!eJllun%U$p6{?v zb=Vsn_S1OO+RwOC8LBH*u>Zhe_h-aD&0#-{ZmiXl$uD!*`yKWv8LPK7 zc849)K+^KQ%3<%wh<(suf7oHigqJk-vQc6`>99ZKu)pZA7dh<7jPicMVc+7gKku;5 zci6XP#Qw6w{(!@N%wfOYVeia{eZXN)IP6Cp_JG5_EhF|99ri|t{c(r=B8NSd5&Ln6 zy~bh3r1CVIpWv|X$%y@VhkdQXj-SJ(v1d8#y&19hJM5JXdzZt03L}&D+r;6F*pE5v zWez)*=~7%`#q9aNaoGDZVn6Dz7dh+?JM1qz>_;{}f6euw>dM(mF}>@ytp2ORdJ4*Nhx?1vrpX%2hBVSmD5KammpA%}gc!`|qyKjyFx zX2jm>uupc_YaI3i4*RK$*n1rI2@d;OhrQcjXN8%J9_(@0a~$?chkd)lo|_SSm&1M< zAJMEHY<`);{;qvk2>rNGGgEAupe>QCp+w`9QIH~ z>{}f6#~t^%(>>Un! zm&5+5!=CT3M>AqiIPBXU_LC0#bcek@Blft%{;> z@5qR~-eKS3us`pxpXabAGh(lC*dK7%>38t9&5w21w`Rm1b=VUQ`w@rz^f@{`a_&KA zM(k@H_C|;Oafki)4*Rx@*w;AhH4ghBhy8@Zp2~>5(qUigu=hCZKX%ynWW*kJ*ef0O zE{FYjhrKr=_A-aP%wgZ|uz%BGKb#SJiNjvxus`guKjEct-3C9QJ7rd%|IVzr#L|5qrMFKGk7w zblA5z>?bl}4?66V9rhZBeS^b3m=XJQhdsw(uXNbUM~Qu!!+shQ`K;$@ewo8w{Z)s($YG!Furqw9h8WENd>wNSraJ5=9rlF|d%$Ctv#)=P{)U*<+0vefw&#*Vs8a;zFpn~hOnmyZby_!K<0zdo| z#5mNi2?B4X5~eiMOnCcHGi?8+%R>B49NSNS=U?d8)-viD}h zPEDZo)SGwAVV~--pK#a@XT*Nmn@K1w;fTXN*~V*EAS3pd9rlME z_Lm*@RSx@!jMxVp_J@Pa(TO9W19rhUx`>BlBk2~xSIPAw9_DK#q zTb$nS9Z5U?yu+Sw*pE2ur%?s$mNqvd_G1ovjl+J(VSmnH_h-a@)L~!iu=hCZv_6TQ z_bC~%A92_#9riAVeW$}7$cVkqVJ~yow>#_~bl9h7#QwO$UgWSp?67w@?7@uK4>|1l z4*M2|z1(46kP-VHhkdHU-srGj{*p$#GZ24CpheD z9rlx|C#>1S8L>a?u)nJM;i})8U*xbKa@f~o#NO$!pLE#iT~_K@^!?^<_t@pT%+DsM z_qe85tGU%4!qRaS-dLkNg@IxB%f1;hUZ0;rEdkQ2LNRRYjI9-0Tl+Mk%3Z`vZ+|or zH1t@3e(pdb{ZL~CntiCZ8~ID*t=FkH-)ZU5=#>YK>o;GL!9&qF)L21Oj}?TFA}G{2 zRK9wboc-w;RBx=xT5j6ryeYiwjMwGkMc6LW&CWNe!x^#9aM&j}>}#Fg@;dJwOMeD2;{dwRPS9NW9MMxP4*83awU*PS-Z1Xdo%X6K;}F7@3vG5gOE8Q z%T$EA4amcCUXwtU0#VPeEQVDDP;XmW8K1$W;#mh77Bw}t5s1IaMBYm=Yc8xMSG^vA z#J3w2&o;=MhT5q-1p9u983&9?B98-!M$MRi$YrL~{Qd7r<`p18Erb238zV@|bj0D6 z@?RmNW^f6v@pBndU$O*pArNMj`;|acpG3&q0;CW5g3@FP?*d}mPYlSb@<}8@Z3Lob z>I&qYKwi|EM`^{HH=skbk*@&}-wOgVh2Q3(0!FA` z0YN4VWZaFgLv26AF&T)h!)t)3r%V>@1Kt>^VQc|pJv}diOpVT01p7fp&;~>y@Nmdo`%D6EbB!rI@_YY%6T_Z+lX1eDSL3X;Q zcV;p@JHvMGu&iiJz4z+9uI+lS-oC2W9|H#dSa6A$U=$^&VNorTXnm8M?3p*@2PXY&OP7vRz3N%RhV=oiQQ=RJwFG| z2SY#OeB7VzCCLL}Px*1g?cRKtye>eb$N!?0eP8Q2PZ(JMUS4J;{P&^jWq}2y-K)6elYUNMshU5`GB;F^w@`i_-v2$^A|u~WKpe_ z_!}VdXDgM`KLBYWiTehSSStSqh|gwN&p&w*-SUfGw-ohsKIu2fW4bQCik}51manrw z{QJw+&jlcNMWa6mCm)H%+5_kJqkjGX$g{YxC`qU~9G3HX zlXZpNk)A&ej?YZmd>#klfAQQPp969c+*VG%3dBdphVxw@{&d?Q{|&^)aYvG@SLx43 zy*C>D<)_%eh!0NzdH#l(rVPYi ztNpgYi6OrY#7BR&ioXK#WV9Dg0P#M*;d~LuS8jCY{0xwz5#;+olB8>Qj+{=C$D*~r z8i>zX9Z6>SBpV|sXCg_t3!Ipv-UQ?hfHD`gxwHP}EU|a(k1CY!OoHR@KOaf@PAWH} zz4#4qj?zb~X*YqKkJi2mQ5>!}$h~C!(>w1LS;w@bT$sK7oe13hOILeh5x0x$cLX67#4%HSWOZJQ7LD0ucXx z_mO11%=0O8diKNe&0*j3Tfix!R`&sU-aWTDr$9avAj3M(#c#3u^M3SQaPA7L;BoRk zAkRgR-vjcz^Kz}{j{}jv+xhoMBG!RTPBtUn_&acJzzTE)4i>f$fAuJ}R&qZNj(?Bd zdj2|)$9}!bz25?I)WwxYl4)N)&tSQ!~>omPX0GczF9Zgf}i9w0uZw$VQddRQzaJzMCS8RTFGClX+I6*-O&uc1mv3mBK*wK zlN(V#-vZ~SqxpOfNE7B$)LA**%#x=94RzRGL2@I0eg%+?sGmE5{Bh_skgG)n#v$fv?sLsN&z(J(`(iqnW(L{xo-Rt(;m^M3+)B+zHrS&ft zHD@JY5ONY-W}*8kWT_x3zQe>7VdpzM6u6+^L*eRY4v#^ZT!wp%n2~DuOWGP{}*ul znVr+&%tf?ltAD-?&Rt=2>Enk$9*aETm%Rnv2rCtw*8=e;BieIc;#~P_d;Vo`ULN(l z3`E9nIsDgvw4Rkb9Rm@$X>r~KGy&7lRl%yr+|Dd zn&Ibwygs7FKLdFh2%S5*_%@IyBAo97c`@qewznq9-8ccZQko{O0`f>S!=D3kBJ_h? z=&y^~_kaBEoCN2+(VpH7aIv~e+!8GwY>VV1CYmo{2*G_-vcSbx}^P=fPCmicZUB8{EEAwd^FYqkPk*Pe3L+;m0key-Dn3hApV?)(fI*`T^zf| zqtP31TK_rW@BKhtANtWIK(9sX`WQGH(R@A)L^!gg^A~}AL0DOIefpc(iEFBso;cYK6iri1zItje)Ux#ldftZwG79_v z)?ja6+O6e@y z5zoDxXDKA_Z$T}{Ak|$>pGqlfrrD(ED|9=b)djOscn{}_A+$p8O*Pdb9r~i09TLMf z!mQH0khW7Ygf=s&$;34WwU2r{+XxTqRC`CG4kZEVXHhVTCLa;uN>4?NcisyXmRU?j z?#aB)?H3jVk%i|E&k4(=l40aGwbZZ1Q^E@^TTe~Z@AP8Drs|C1D@KQ=a?|nEUR4pX z7{$nTclu%qqOWBF3=%C0HQk+TQ#G3!78>qU$FKzpAt!|`L(A>*rP`&9)Vt$LJ>RvT z7w$|;!27D(!+n7L^}cNM+|f-s=&oAFEk>J7v?hUeRt5iz%Btr!M7SyIm9`I5hDBZu zlu{6ldZ$=)%Eo_vNY&&~`!UrBP{>?b283lhqYDFv(WykEQ}-iMv=L2;Y$gEX(E#il zP1KDE*|aT+o|@O%wdJN9UubMA<$g8kXErtz&~(U9(HS7F?PRlwJ(7|afJwgNH(k%lUNS#EHdIUW?tlc{7=2O@Fh=VU>L3;ocgsfNNTUMP!N0Fw#jHMA_V4RWi-(_)8 zXYj^s($?|e0oh2~8Dv?+yE19LoDNXRo7rrXZ)dYQ3AIIG1eq(G%l=qnAqVk*GD)CM zHrW&0unwJ}lgJ?^8ifL1>x1I>m{zffv+W=sYuV>j0{${&HX#xtVdo*%DK$Y;iwP-(@Q5 zqM7Xpfj6$8f9m--mrxMt?pF}Hk1K`CWD4Mz5d6H*LowJv17PR)6>5E^MYcFEbCjLI zFdt9@-xodB7;~MMG5E(2R2=a0!gib&?@&&>JCG4$bgK0xu21XForiV%&MiBidM2=v zU;TMby6R2^fzOIE0<@L5G^zGl6Rkv&nd6QrI2co{DZ8CdjlS`s)gIcK13Az&sHbFr z9$99^Tc&`IDd0Nt4Y$g(b#wKkc&_BcWkGc=y-XKQq5XvsM=KSs;-pzvJiByU8{O0K zB=1k9tqguoimhDfxHJk_ivTDgGoGp!Go%zOtGY zy~fI(A`?7NjeEWR5Db|#bL$)##TQ8GlX%qS%F-7;hc7|b;Px^cG zn`Hd_O3`1Wo)998N*oi`!}hMEJ!VzpGYu$0O#(m%Vf!J_K-J)iFoToi6*HZv!mLDx zt8@xX!e?=9tasTV5l$tsvd4;OyQaYTX8MNIPG*QVHR>nXq`z6o5u{foD)bD#+Z;F0 zaiiLzbnt-1+*)d?t=ug20|XM37wP2?2dqf@5@@AK+cR5YhQoPUdEM8CHquG-T{aNk zNS!Yotlpb6*{&%-1wb8!gTRJdR+A9{x&o{L?(c+bwar?VW2F+Clx@mcS1I_5VqC;A zlQOrD)ZSiA=gsg8lj^MeYTC~Ws5^oV)hJzDICbL0De002Y=H>C*s6rY6vWd!lV!_gszcZ?ZiP&Fd!3YB|z&OnEjz1o=_0Jv;>kqKm+C*fEE7=aWxnh7ddZEZ+Knd?DeR2UiYTYqUecQv z<-mD}HSAL0m9c1&prRqbfgSrAxVaHeiOPTmbFAPDwl93dhfQy6MTzw%T`0XJmPt`) zlhjCoSAxq&;B)5KQbGk5*2)Rlw|5wE?WcLQK9O1be9Aj;@70be#H3dgg&_=6T4);I zC?!)+MX@T*gsN5$R@qj$s=RVZ2IP^Ncwf_o1{IoIdvk=)l@2`Dm0#+<(nB7!t5vp!4_%Bp%Mu; z;Ror-QZ(IOkLt=jE_(KH3N5e(W!if24&L`y9!oj!I( z+H6R`(Wpvx#onIV){T@xNFXY%xTZMkoidcu%V@-j{sBrPuAv^tuf&hh3zhi&+Lg5^ zd{su#NaO$@pqRcCwKlWRS|@Myuq^*rIWR0l#m2LmDe?K(HnYkG*Uj%ODXLFwTDs(@ zQnDlhUUw##V(jG3C+g?&t+t&NlbkCW(ysjHO9`W>0%D7dv zCQ^NUo?XWaF@HiC^m;lhNeGKHyDY6Bxay=fX4hSg;6k4cz^cYb@Itrh`09EpbCIdp z!!R?e+9WL^yWUBrT^IgwdD!b|F(@=Qc0I+PQy=6yYL;AphH5MYl~ZqCRX_4N>NxL< z#UtY}MZ+zeI=iSs`yhBk=elj;E10MFU|{hFC4AE)!h^!tcoM3Ju0WTnS7?BIMdeiq zc*O^Mu2yGsXyKoONa%;<^v~5SY-9f`b8)ZmW|IVqX;LHTtlh#Kbu28=$$!;4s}nu2 ze5YxfUZn|+wN!f$QWo^Kg>@iMt+$FPy{Wm?#Uew^tSS>x{6ncogSB+WC$ZLC=&VqA zIfX&yrNa_xcI)W1D3iJ-ws0RrOmtA)Yi5GY=86Ah_FQba`aC+Sq^W%Bz%?K%Wb>3Z z-5IoXuSVBW*-vkG);MG&2V{*!>SRfdUQ)Ha?*K3(;wkGy*mzk?NG`9%sS7u^{fiR? zVeOURoqYZp`Bk-AVFbkh=#ENUk0zSd2M@bdZO{=^?J}y1(vw+R^XNQ7w?}AQ%c}~EO*Z2wCuEQZma2#BUj&mSr2F@OxVl8d%M-c_96=gb#Q^E?n<)-zmx+R;V)~IY7#R5U8ma zPA;8U(h{_i$_a>0tS1l7o=K(#J*z2r)ohYvlVob{G~1vjx|TFE30DFL7Ve`Do}gJe zHSjvMNb9JGn1-RR%(8z@##}#=OxHtK#np}y9=RTg_u7gcr%;WEWcBudiighe=1I%@ zRG68DN75r@&FWd}0H(2KU=6Go@*mNMP;PN?Np?x;rFQ|;t5psb0y)RNsM1NLfk{Hq zUAIIUH2=*$i!np>N{l8&eM!QKsV1dq$v=QS+=DZV$*>hSI`^+a%0hKlWJLQ`Sy+EjC8F=)BM~8a z7dWjShEKIrYH+DVymaDBEpnzfaU~*HSCZQ*`jlH0gNlo>7|KrF%Bsc{D%lK!smGzP zA(7?GA&RGD#UTh`wt|<)2&QqXIxs_yr>ovG`+M@lV!|W$hKH6k1fm3E$h&-$yca`p zPz?1Voq+AqDzQ20zAV*Dsi-TnutqZ0WXxoC;vDX9f=*~!KoG)Mc1YaCtoRwj2DOXtnj2VkKB3b zXH$;OxEcd9aju~ideIc5F4r2Iwt1Y99d*Z#lDFHnr(AzmKD7_&=^VO6@;<3(Zkdku znT(980`vmSLvaP{e`2)xce5Ipk0eS61SQ?5{DYC8_US}mG zn?7cp^quCaw54SAn5ZzN#iY729B!DOMb&d$}a1B-O;ho)Q}!Hd+7#;AQxj~j>8jNsuVgIH?6N;w4g2} z@EC=jPc_G&CHwY8I-1O}MsCmc_lFN86iLZ-8B2Q7 zx$)#Vv4?+*>%qZ#3bjw2un7qQW*~InCu$8XINy(NDZ>Lz(v7us357HWA?Y^%#qPYEB(+hdy@b0N*=SUoo z^El+;ik{-f9k0r%wsdf9HOwkWFV*)}6X8fXq`fp*vD*WR5c;?St1v-VQ; zy8LBOburz=(3ie4io4#uXKFV{x!<@d8GV(e88JxziObLvFs%wMZ*0ky_SLjb7lQijN9@{XP_SoR0iR7^TgQIQjDf}}gr z^NZ(bjpRplbg!t_+C8>a9JmaH^1wnV&XD`8bq}R~P&7#d1+)Wli|IhyyH1!V`(rbj znwyaJw}ttAP2U!2t2;lc?K=gcIgmXz-a#O)7;XM++mc|8(vy94$=+iRbIiZr5%`h=Ms0Lp8+pKzT!%AFG`b3L zUQyn36=QIRtZLOZ8weYrNHVfrh}P1|Iy=STh*gkol!jF>C0qC{TuJ2`RGKbpUQfH2 zVv+2$0qNLAcZrD-6j_;{3E4W)p*DW8*z3Su5s&;N9=M6f^w>$F%ws1+7|ZVZc#qBD zOU&Vly+z;iAoPq3^*w4Gpd2?6!PzX#^R=>sA|g)i5t%*Y(c|^dDLehNKRqaH>ieYQ zUW%WBN4?w81U*gq$STgBO2)lfJHaV)I)g?Y;rOxBN!_gzU1NXvzECASPZPeDqGeog zQm7JwxggYiFguZ(jqWm}VyHgpeo|ZgDhc)WHB_cJ*xw+~iMat!Tt>V9uP#V>zTMHvKd@t&eoKTc=mzffYmyZ6SeB8QgpDv#AJhZi? zOq6>Qq9f)Wh+iJ=V_17VPr^X!s0Rq7FDt-kSYYwYe9woz?2x9deQ!}?_g-qqwFD!4 z_-xC))W#atU_mw(XOqghetKo280Y6|sFF*`MG?YrWmDI4GD6j?FPp>MrnS03WFus% zZZT{d#}DKnQAoBt|FIaW!8@9-(hVk36w{P(6K;ktRrG7!X^Fnmij0sPs7ojy#z?%- zqOzk4iZKqJk=$xkq;d8TMvH8KeM=_wd0XuON}y!qWh%H9VU-UCc}m*^&l62H`3h>Z zV3&fQraR@o$I=qI8wOeXq1s=^d2gHNq#ylI#lE3ZGMXc7os!CCQ@A&btuJx5c@NE1 zTwcu$qc2pqoZ^u59azI)o%-^S)zBA`0%~V|E0Ohr&Q&m6^l8&^&xMy@7Uw!{=skl= z680&}bu~(hb&WTD5P#4%${H|UG50_=&>)CR53vC%XM9C{AHA+%X$q0?jq2^i zAYYL{_?F7Y0wEN^8d2zcdJmZjiMrGWl~BJUm7brtr8JFL&NxQjce6#ZfL3k{Bu2AC zT4R5G-$}{x5)p zd09(d%ksKWxvy)}rKe5=8!%l=&z7uMy3QpMn0;+AIgTHphdTbEG7f)J%S}|%!zzRr z#2^Jh#Rl@A^*WR7di%GqNSDrWJ;G5^*Qf5BneNdz+F{uNKI~=V`7c=9+AJF`bRe+w zg0Z2OckKysi1yJWi449*MsLl+!PQ+2hr~KZ(_@kQJQeH7y;tqJby@y2jZ~*x4m`{m zU`e6}y5lf0%UdHq-N*=@YPp>BL$||my)DXK{B>CjUGPu4x!b(cgu*BJqOak3M((?D zUz$kbbBR|F*vqqv3aWo?(FQ$~p_O-VPB=*ptmfPDf9@N!lWB$D6pX!X=~iUlO|uG= zaQeB`y!OPu5^S}X(7-g8c5T8T-YV1dU0G{a-%Y2rZ(6#s-6txo=023O&ykQTPxf3b z=e2yMA?~D~tMbx>lWd?@{~J}X39cRcDhH?5iT@rBOw<-!xmqK22zaF#au$x@fNN$CfmIN`9;T2`3sdj7Yyasc2 z4$-ikJcvy7fREhnS=k%Q3nH_dTtI#g?YPYg)c$HT%{YTUBl z;%Bs3ZlOZgKVk;XQ$8Tiu=j!aNpt^YvLFG$>^lJw-ijNp$PQ0K|51$>|XES+eQ1D{|V2PL9%d{822?#S9PLmM(2 z;>8$wxxTUOmM_6^hL1VU$tXro4_9n{)iPMe*=T2Kvp|CMBV4%E8k-n$*C&$mGLC?T zWj3-9NLC_(r*4(5-p#5VvXc^21p9KGn2Swb1=>o-lF!>0GqNUm@!fk(xAJZ5yIi&a z_vKel(}Oyx<R=ReNqdUW5Q^z9B(SIJ|c ziEH9M(qx**MYjW-Z^ub3g(45b7GR%nb!EB9&>`rqd;p+rtzQ&4C~`$@pV~Zx6t{{# z5A#`NX&g+ltGDv@%%68twlu(jFumQvHXb`9m%*opZv gP^3pj^Ypa1{> literal 0 HcmV?d00001 diff --git a/src/external/lua/lib/liblua53.a b/src/external/lua/lib/liblua53.a deleted file mode 100644 index e51c0c805537bb7611ee9a5066d73c59a5670450..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 322424 zcmeFa4}4U`xj%e1S;Ios>?&J`Hr16b8YI#UMokpUCYygkgg`<-L6eYdNF-!qa#n%_ z2%bbZ9@nNVZEfrA<+fgHYi}>UrHIyB6F>s!?L|vlYW0c~uNxO_suTlK^ZPzC=ggjy zjqPoJ@B4c{@8`WIpOby&nP+C6dFGjC=FFLS&Qy?{#;|(|D)1TMt zXHn+=UhfSz`4K}`-4sc(`6X#u|Nq>7j|}P`mZbl;??>|`>3{crp;warckYvqO45k? zFW=`ENYa1vw$1vn^r`n<-;!*9%l*I}$ws$2MY8?w{9nFLKO))wyZ6VxkZgbBopRZa zrN4U5%9m1Zb^m?$Bi&Mpaep;UO8I)Dl=9S+#Qn5KO8Is9|7Y&htG^?quG}G|KKz`N zdZb87{nKlb{WHaqeftNJ{h3V3{%@~J_M-=CTO;+g4b7p3wViT(!&-@jyViy83vsYs zZm(}^Y2bnTLLHqg;Wj;Hb!SUkW2lRV)`Vm^+|J=n6WkG&>t#K!hH(1^PSGCeY`(9) zHKIqz8`@1!Tm3pc)Y93|6lrUaMVT!qQVy*Nb?|IjI@==aRwqK8az{(s8Y3>!8R}@P zm+N`Bqketp-bj5b57l?H$juyV2(N3e@6b!+ImlsizD7u|sT|gM5aHF~aBHYu7mFNj zHM45K0t_fZ%6*L_+z;6%WF3 z#W&Qqw(4E2-2}IWjizsmtTVDhO(LDV&^3BD40Uvbb){$vb?F>6gxebGby#Q|aot{6+g>j>G|S=Ukgj$*rnRNh$edA-W^xsxG8#jLMM1`f5#s%m zhq$x>TP+tI}U^&v!CMZKN4M=Km)d+jlT;H)KbYFdk zK@;j~pG%E|0`wdSQ{T2>B1D8Y`odbGK|7dIEEQbH;SMT5kLwJz^2UV}!!1p6hi+4O zu&KUPh=>{M5N|q2v?J8iVo0c^EdjTOI}-swtu1YakRbrk2DJz@hr?X1)PPBWb@iRr z*oJUK*AAjL4L8*MVe|u5CCb06i1mYYom{YGwH*;OhS4+1YH3h0 zhq)S>G2wPHndT(i-X`)0cQm4X%@iH=4WUq1i1)Yd$+BHaH4tF+V*fNd3#kDOM^z_lRxK>EExE75=_ChZZZDwnI4G&Tk z!mIDmQ-icI)R55AAh#FbxW2XJeq91V#uhc|>U+@8yjnrhKDh-Wt})vQ!jOb`e@2Q( zYpZU(SD$?&Pw}SXHjnSZ>{?HyVG7$EEMQtm3 zV|}wRdsvKOJC7|z99NT-a* zP5GftuKSC@yos~LwKV3Nrw<%snPM!4JR@yu_3>jdjS*akysav0!|m%}$hk-G+nkmvWOW_Gk2$O17)rRhE zZChisR8?(reJ7tkaJIczyh7k;SShfo-fCk19~c^ZCuLbG*lY3 zG6Lv)^?XXtid`Er0!WxBn9mNX6IHAxc4V$qI=p&=A&Tl+KxDi{FR!j8qf~u6%aI3G zx3r0{+_AwNBwA*-69jr@om|b9)ka`}^a)lC)R<59c_f8tR4|?~YRF!-bT)%wR=g25 zDp*t78tUwnoAv2G4<;ToYM?iG=rHP5W1bAvP(_WYT1{0Nqv*d&An0Z zVs2BAF-D8QlLjB2RZDFHiImqd4B6JMZjrC&7T|VNIlQ`s52Lpm z0~RN}oefs?kuFop#8kPWcD{LEK>+?ToZ?A%YgnTM$rM>$JIo z`uKR19O{%4T3<1KI#*FE)A&r*p9xSWz-&toV#I7;9cgM3iVRL08_my23}Lcs70j+# zSS3Tp5!P%HcC(_E3K4cb5i}*h{7Yvl(w2bf5rBlnXJ!>J>h+D3SE$2`vG51YBrzo( zS@c>b$w@qA>jc(nhudWv$4xKk{9Xi+VzwyQ!z24k{-0N@9*P$zHX%byuERduxGste6Bh!G8xQ<>S zNp_ng9s2^ut;3I3s;ryC#*hTvL{LET56oHJ**Q_18P`K}e91+id#KDSu|l55QMvdD zNOgfP=wXA<1EBgUBgB7EZr}^KH&~FZ8IsgYbT@Kz6@G}W?^Uhbv-z^YllIh0o~5W; zDxI#PBkH03(LEI0dj7Z1j*M-}-+KNye&v8Rc`pI8jw%}*)8vAhD(y0s%(bU8tzcx! zBz17`ExYZv>YVD<4SFP~bRl6@n=-k7~W=DxSBnP!Br+Tw%Pnlgg6mabsP>UQ|(5cEG&GI3I zJ6h>RW=_gbt#Y!&AkYG%$^q}nyK9vbuKkF!YiUN->Yx^I^bN>Q5ZNWlfLpB`(U#cN z$}`#$hgvzREpe)q7u4~2oQ*zz4RJOxzv@u#0C6lA>ijOYD~G}FVReB+TS(lwb)KV3 z+|j}ju*$fu@HrUE%37zFGrV8zHgl_0I{IFfe~4Vq7L5kvY%Sw#;YD`Yt96W=ExjmJ zp3bBOQ55^Kc;%~{5OJ2aU_^P>tva*?cD3BDEpVvifSoEDrpg)L5xq~+>!X~`0=-YG zw5!#6%h-YN8sbt8Wa*j_eSzv!3S-Z7W zKCe~*wosd3mbTF|>*(O9z2MN6;Or{z-awH{nsq4m?BIF3vhSjTeVeB!2i)oivV+c{ zG7yGi2#wx@Y@sGhE`0-$*C;n+3I+W+dYfcBQn1|Kc|cum7s;FYsctCUqshKZt=pGX z@S(hb+H`dAgnib&zA=bzbAeXs%sm{R#Pl0+|E>($2H&TkFV+@#Q10wYAR*gPh!`DFmoF=?(xU~O+NH`qH#M)ouHtb!%1V)po54z1l%dSn1q!)!CpUAb(aX z^=OhNoeiKXWoT2+7G0DYnZoTKDG_=?CUnSyF6%~^8!BDitavA?2Zht_cE)~mer!zH z@7COE)d+Q>sx#=aYSkzNtOhTrcRR^0GRw;Q4^ld)4Pu>0cq@rgo&yJ@hDlyvSmerz;@sHSbJR0HmnvTxB{4v?RNW}6`_!Y#fgGbcy8asZe-DXyMU+^oGHP>uos}c_ zRVbeLO=0|&eG0$4`w9I~kH;1uA=>vK!1(~Te!_%yC6^twQzqKUgZ_?pgOX&l*UH=h zv}991tVuSj;3}U#T66}C!S1iWLMtC3(_cQKm7h|}&uHZ_wR}`7Kdr)U1)b6I6H3gj zk1!~~2`lR$Q5eSBtsKZ+$=ZY4LMJm=)i7ACzHI1c4w(JQDENLCihew{4dB)>#`kA9 z-x1U*q10?(3CHyBZ^aw!i~46W<}hlKsUh>I zwvW>@%jLhdev{=@B5vcqNWOYydmu+4T{I~ z{_+OeC;q#{c$1X>TAu$@`8p$iG$pe!2A{dFs)M-$eTO5{Sy}00^ABjo1GC6RGPIZ%34N$=Hq6NJvrJXh zLFJ@NId7LsmGi0cG!%ZvP%1Sd#(EmOSb7qwn#ac&t<;Tf-#4(?Auz}k8E!*{>L4<> zShMwX+3oUWWFAsA8_NfZxIcFw{uCQeU3&tP;-?bwQcjbx@t}(CSb+1ToSd(mzet|F zd8%@Ll6;YJ-V?bD<}BcZzU&9Tk#tR>Y$(`IygE^3@QH?YGF_U`9{v7LsC2nQ-KU(J zCTAeoxu(cPS_-oL5Xpsp2>Jem=+U1^M9^Ze5=qlAE@YxEl)xCD4EvyfKKE5vmhwmn ztmRSNjEMXijQmi!tJi0a`MyS??nh2MS3N&uuCs3%KP#O>MSNJ=hv^(2h)m-hbP(gK z^Nq_vMGdF~oNj}^DmM5Q`ukrjBMPhfayckCtM9p$RID2|i>&>cotUdNBTsSwBfPy)YHU z`aF^m(bUrB+EZzdw!2~0lp~mOzN#*9kZHpNHaJ0vG{Wu&tv-&&kBu8|n7z=eHxXZ2 zl^ZjQzE?Lh^9Z?dMgVX#Lg_IFW8(R=^b4GQhd(Vnx2IXCZ9aOXA9IMjzTZV?#--+i z=V_2Mx|vc6X|8bg{SMiH3X@b}D0SFqHrP_pKh@WixD8J}YL`>n?40!*njvp?YB|$^ zR$JX}t#!H`zaIQL@SCYsOo!!nXMs-ncr5a3b<$9oqX`@gZ@@^+)e!Aw$J0tTOcqqk z^|e8D3bc$3qNHW?yra+WoGd1V^va}vEWXmIrXW>0Rj$%a(FH}_`anIdeYpNX7fA0Y zGf2q?*a1*tEuO9F_8t1A{t<)r@s)QEf9->@F=k&VJ?WAk9WM_<)9F8wnMAiNQ4h*< zp%}V;(X$nefoNE2M&8PpKNsP_%D3`vny>KrKh%zqP4I~IG)=f|YSD;RXjhBQXoU{7 zXcY5EwdjI5A4`8G{_Nn7&j2t92ao08Q8{22l{tj4F}`tq$w7($YE%qqltX7Kkm^#Z z85x`s^+mayYUWqF?9d_V+6YF=-70%DV--|ep(p5nnAq{U>JNZ9P%KmyvvzI(ffaQb)2i{K%c^Any(df%^@9iggOsBkL`cv2h zNN0r@S&0#htvN(aV3NlInekV2eKO5=QNrC+0>r(~jU=$?T^_Y#M7{qEhVwMno zb-^gw14^k6gIs_9W_xf0nrT9N@cMh0svOi;Gv-o#FmcdrLbM2r3N$lyqAAS_7icG= zf1m-C7}1#Q0iT5Z1evi#j2wLt!)GjFeD+foG1&9-h&@dtJJ zO=K@JQ3tcVD2G)4y1h7g8a00rHQ$7FocUDqx$6CPv?H?@RnF)F-CnpM2SW(D*?*3u3J(#TAn4Pf2r5^WkDlI`+jJU4;q)Cg;2G&P$CQ;x>N zkzSG!#nw~k88g{Fcf?8FplAIK{g00$ZVe(cv#4v$rNFZX_Q_b=Vmx?g{3hGPMb53n zxTNDq?ql z8pX?20xzc~V4`HgOU%nK*(SqgY9nT#I2ZI70|Tkv3Tmzu#dd3%*a>cCz-u4 z*MOGsdez&rw1unG+dXPAn?Ei=6WAXqls6U*uo(LRo?Ff3)Ze zY!6dsrYZ}Z%7)QW87l}_#oEo5ol%K-)FSw$o==s^qe^LoBQy>2B%a795!M&LFGgdB zk=}S-K{Ck6uZ&LC?smJjjiM@JzP_FKaqS7tHy%ow`VR)@W6qJKul6+cqa{cLppzK; zxdWiECFmhbOMD_Nucj7sK=B#m)pU442^{ryt6duLaxHh3y7Uc-G0k=DBRD*sj3TT=zD!K2Z!}n37<+Y#KRG)ydqVVSS4xV(bZZg88ekCs-Za%o^N~jCh1zz~_!I zmuv+ES)bxFTnDur3DmL%fXQ0Gc>FKL8>__Q|CT-6;286farL?D6q<$955uCVDuR2l zz6EpRz`Hf=Haj{8-VI>Eg{?A^enQvrRDhKbf*dN=Iv_}WJw(hGLFh9V!6pf+AJ0c+ zsF9gvENAJ80@kCYnKUwp_ebn)312+HDl81(w||co!7KtRLs-d4lfQ`NoXAQ{zn8oA z6s8p%+_HG^zwCQSTDCvZFqezTE+)C!y>_+ZjCQX>?HJW=bE*q2uxal8zO#5>-2B;F z+MQdbX@P)N{WQAh$f!1jUW(vhEAlhyO8fU7LWc2wZNmFRNYt(A!zsFCHh7vej;H&H zrx19m*Lk`FoPaIcFKB9q$2j~?(~8chrFJ~1s%XKY3wVFSxMow>*=*)EQ{w}@oJGo) zn8YT=-gpYFzp+tHw>P{#!&IMBRG)6WJ}%U!4E2$J0al`z^mjTj^sBjA#~JlryVfzP z-b+(o<-Y=W=ORB9UG6A&CGt2kd`wSFWj?}%@eF@Hr)~kAh^3xn?Lv#1tX(c68C-%W zCykvp!=AClJ9K(TdAoDm^CV0q6eMy_j-dkBho zT!&5A8*;oAbG+qqyp17mY0H{O2-`#&!#UpNbG*S2Hf(u)1}mTTTNVu7?9DD)v}~3) zZ%+Ok+O{Ck9tFB=_b-)f-45Glop$?nw67PqEZj8OZNV+21Tq{CrW9s4mDD@-XE+KE zX4vT^P5^f=ZWnI4ig8!t-huo3xTV4j$2Lm#U}`YKt=LO4{3%PPWVj3WXE>3Eqi`t0 zUYx$kia@eF++=u)!OKDXPLxm8xO@uJd3}z7+=Gb<6G$+_TbE&%upLD@jk_55rTCRf zG8}!x*S6Hc4EKZf!VHgcQ7|JLC=YmZgEuF5a}>UqVGn>j8+<&Dw3{hyqE1Mw*il3$ zSP7b{RFvLjMNoZOk%te%e1o1xQu!$>$CWHeB;&`CZU@p`O6hPBjwVXGfy-nVj(Zun zW5CTc;Z6W&M zjsbTDI72ob#KnN~q)F2CL>J8PhoKXcrv!Ob1Mejm7vVg>$-o(TlI~;!_c(Bii0CiN zhg3VLt2WEG5oymL?J7O3k^%-&YM@;E!G$Dsy!+8VfrHcFG??A@NG=SRQ72q2ezKo5n>?d(1kMB7#PkXEQ&Q?!!;=hp5QnNrtwe39d&+I7 zZLwZ?GHpy|yFkAif%;_ng`kIaFw@NFvp{nK^geVL3~wxd(mn46-Xat)K`$FWCB72T zUc^6+_#YB2_?tj4{r66&fWZl{!7t`Z{1hN)A~~aCQZ5x!;jE1D#L?*@Ho;jJu#Qz zuCbIs@(F%a}kufs{MPiJ};TN;%Zo+8GJU%G`lGcVIv@Y>jRo$pQouobtXi z0NPWaHS}SE@-g5h3M$seG^*PLq^*Xa8+G1AIsTM8%;gj#KHCAggLa)xtB>i%__t}? zP`n@=&2Jgxp^-kMZAU(Nmq^kbdOk`@N)V$3`fLUNp|Ws43c4MjyIH3*mnWOX6QVr; z+GC*oYdVnw+7ZxtFpwJUWva8;x|CCYqrAPaEyqAlutnd->B2ljSAf=z73f!W+6mes zkg{@|F3A$3>7rc2>VAh0+7N)OA1V{%DAf1dsF8Y_sy?cUk%aBvj z(82poCTy4;hRw)R@ZwJiTX?BT@Itn{66tmz-BY3tP+0|YKX1wgOS&Zpl?v0&=8X>{ zZSgco>eSPk+nh3hK^&)2tE>p5BOb^mA3#1E1P^T5iYzuJv0#iYWH4zAapSjmx+J}> zr|qLIXPqNfrZi6=%ffWjC`p(Y8M!>00r)T&?AP<%mQqS{V!i(`6JeP^mV%z_^G^Jp zK{{p&Fl|_dF|9m(ofy*w5MO+mBtZq(bsYbX0ap#&DjNcyVzXCIz-%zR4A}7#j9~g5 z6VhV#okUxfjy4iPFljmeU}n!7Xi@5y z2Y@>OTp?hpFB{`J#I&P~k9NErMnLQNY+~Lj^xAumNjFN;wwL><>oE=E_1#=lK zJZIvo9PtMbZ=N%(0`3%W#{7VIZ3oVdhAq|eNtC}aG1?=}kNYvuR)h8tD{aauSW11A z4<$fezoS$p(xmHcKfVurXJq$GhgHrAxE-cF-V8tbDR`Yyt2aC@XT@xPftf5!h71}#N>c)Ihg0SGUzm*<$%(pGl14H+h{rx4ph*tcU=~{ji0AUJfFcaH0^RdI2HgW_J%iwfL+51~+JJL)7a(5CZGbr4 zU0{ z0CBqAfOxD6s={%7fH>~gfas~%BVB_rnAQqB(no+e-9n6=ytUc^@f80AXf2~#j?s?C z-Uo=McoGngoq{o~htaJ9#Bu)uXe-0T1TG&PjMHra#OdAz)W+x}j06ub=pO-b+!;Wv z40ru>?D1jH*8nXClqUT%pk9WX0?W%|X8^j3#a09AW3jD(9%RrD0del%0JM$aZiEHi z&Y(6xJndtEREB#V&_fJz!(?z=CZP2U_kh6d5V)TK(pc;}fF5ShwXiNx2HgROmr)OB z1H=7afF5DcXR`RL!Xp&`;$>_D#8Vs>(5;^{a7}=?tX>1eYxK5=y&qPgpXE#(H8Cg; z{fMVHg+9~HaJ$hzIvDgaAR5;_(kVbZRzeTxVz@Vio=$@1aQ=$GJ%@%+8s`ASdK=jV zgifa8kckdKC3Of&qC;pH9YS?=$SWY9fU*UYBOt$k@&uGGpm_oc2&h;<K?Ku-$j zc>x_2&?y0p3dpICA0BC*fVu?qn1FT(=zxHZ3&0-_Z;UdD)k?C6(zxdO@&P(VP{0%{geuYh(7=#+r$=;u6VpMbgq^ss<- z3TU^0P6#Ly_JHS7ETBgPbU;9o!=TF%kSw6b1awG1X9VQKsLRW!6i~l_4hbj=7KzhU z3#eZ}#|1>IIh?LlKr~Ks+yMa{7tn5}5qn5LX9SdkF`1{W5Kx_fXkCQI?iA250XZ{_ zSg(NQ(0N<*2f98P!<@p#&SExjOyWNVA$Hj$uapYSpXiziWDjme!wCHNPZlD9xdovB z(sN906Fb~4(N>8BO)1e>Fg3vJ)G_$M)r8v%{ijqMLo=>^3x?(zyDS(D7_tLUd0NiJ z^-bJIEi~UJGzbzo{{#rH1@i(hbr#G^zzkS0zXFE(Od_9C!1P!!?*l{YbP1XZl#c~- zF{CwO!DIpBMz2Vux)zv93nm|!b_=E)80ue%R5ieiSTOaJ5BgDprj2MUmG#d5Kh$p%6zc zm}$U_STI)uLr?IDR5t+=uwcr8*=5130LF{Hm`HUGFm)EpMqqYYFi~JC(F+r)z5@(B z-z6|V1*YGEc@dZa3x?iSNa(qVR40MiX~B#DbJT)44@^Ji<%v{j(DxG-%v4}1-DVo< zTLTtME--$~xf1yVf$6tkmH~6rf}uAWZp`8nsXB1LWZFy2fv=1;(kSTM8+Cjg_!b7p=6 z*EC3#0t4Qpbl8Jkn1Lrsp9ai;1>*(Ajrpr7ANU057Z}Qi#`FOT<`!U1STGBKq2-4} zSu265v|!d!Dhp;KFe8|&CsI8Gj32XTjxnF3M>m7ze+hBxh$(TI&(M>CPBc20&(A|} z6VsT^&Vvci)T78;QH}w8n<8<+B!ULYHo^6TP6Oix8ag#!l|;1*G$(*1QsP^Zex|1) zm}6c}!n`3c#<=rd66T{M%p_u#T}CQT62_N=xhV;ATN0)=3DcH@*_?!lCSksrg!w@d zW^WSaU=rrnNtm~jFf^K3rSWkRW->J$y9|kCC1K_yVQxvnlq6vmCt+44VVaUKokon)6&^d zKgZA9p^SHEQ~OsvvFct;=FGk62JX$Lw*G(ova-QQ4qH5xTD{AVvp&P~3>?q=k6%_k zep~#YLS++9g_r{|uA>m0;SGz#2sq&&6#?#_s`md!epwTqt`ct8%#OZDcI1?-;s1Fz ztP`81R`_^M_-0M=yI0M8WinrT+&j{E7nRHl9cz5U3z?w+7SC};q~RNF0(XqX>}l8R zn{r~mnIb7?DA`M!#jV<6_!~3)IVXEyvp8t8x-=Z`?QNV>Lz53jR#EQA&gzqI0yl@r zjxkwki~l_)O|!2)coa)`*E1wo&iy@duW1u{qvQf*xtX1Jn!LaPZMY;gxljz&Ci}%S z`S!GWShP5>EaQ&e48N-;*Mpz#-HwSY;gF0KE<9~cX(jKyCg)ee_f>)Q8w|qt)%69} z!vz+ux+#Y5t7F$m(gHTHC;Ptg;yJ;Nne>y_@R1*nACh+h-&c6Nk$iYMFkb;F@OS&Z zqIJ}H$nQtlJjbQ@36M{#JaY-OT8sCPcm^?FjBcFoD_ScU1>K3+oN_LHh_0sZ)harQ z>5tm`H+!@d7ozPKa3=iZ{GR6+Vb^3W6T6rRgKgXAKQE_ZXSsTOFgAVbIV^Zd@|6XL zf`6cxV&~E*`G_XY)JdvinG-L99+D<7kyuSClMmaxL zg#vyl-@x`}tFJvv+2YjiY8-jc(!iPKd35mIjIB5VW|KfIJEN;Ex6$GAUt-HWZM@$@ zoa%e|tK#-(^(8imn^3A?4iXBOWb%a5!Tt z4s0Rwb7PTxbR3m&Y4|cxhiaE%94W!xb)QT^Tyz7eQAfVEz zG9>h&4mSD;(vh%iIyeFG^>?V1!aTSjza7~IW1lnpB2qHeh#wi``kC_KYe3YmzM@rn3M$=l8hO3ISsFL_{kRIJDkAUW zY@i&27!9A2;-u91PNv%MYUK;%PO7(c| zp;^aoC8gVPxt6wdkf6c0GG>mU_e>sCaUhJHLQENgys+{n4$R{0DD)BT;cx~BIu21f zqs@-UjQH}z*)1m|rcHu^z8l*Nk)fx^1?qollYWN47)0!+K4srE7|XbhY5nL}wAyb| zM_nbasUO7RI7@>% zduF1}_$7Vaf?s+=qw6c3NV7xjv_PJr8OU5M&5u99j`Wn0+oQjb-akS5g-Gvb%HGe! zd#FnNwQ{;reF;bOy)hN8w{Q|AJw6p`^2YIa${WY&1WP638Dgpfl|RGN>s$2jjw7o$qCeHucLF3x&kwm4ki%R5Y3H5@h4&L!~P+@HQUUl_3Kt8;b(x5-1VAzG? zp;USxSA#rvoO>F62nFD*;iYE}+T_W?MV@O<`LzW{y8qDAoP+Z^I6I8vz*Rp-USmJQ zDx4%&qe9L}a%SJzt{a~tjB*ljlq+1V{F;S--TjM|guvkXt}Xb_?wv#!|CZr< zf=<(s%dH&N{Z_bdS>f4?uA|-OkILVO3cQ`Wg4TmU|=qI(RKTavtY`nPu{Oy!E6nVL^A%Pci9SF+x&dNdDoX@ z2(dr@l+lpfw-C;f;hYn>mZIaK9%XDy{vyt`oulD4MQitKS&t0HGq&O!JH}I39#?eL zWi(jJY3gs|Cvmp38$ML_InZ~8--7qGel?%E5gN`oi}&0WJ!4y7-smv1U+aXg6Wx@= zwvtmj9G;SKuB_OX1&zw0-Vtj7pWr1+VW-N+pJh}JA~W*w<%T4Xr-y32PaPTjea7V1 zCLf8-rd(xm1Z7`&cf1D`qqAX7NM9MSDMzkm3EkTTFLyx#a@Qi!iIvF_XqL>=ztcGFBhk_!d>u^d?{IR>KkN6R}Nnev8XFN z$OPt*GI6dPevmpBo92-Gx$mn?9OT2`Hx^xClW*4227iw!7)`#kE`QYd4b3)_hNsEL zRU4l~+51ffU!IIP2ThV9$C&sNXCYbU#2%ADMmnkjCB*b?@{!5=m>ACElx(8CKyRT1 zAt(DKCo}k61)TxE5GyrfsT$ zP1e02Zl+9i!@~6ujZ4bt)uy=i6y>BA`+TlFcQ^`;Z=Q1NClKcr$M!-Tn8RUL2-xli zMk{iliP(IN@=u)ol+kufyX>*=L!;CYDVW2$hB3i>0jc$~w?6eP^(3+}9ciUzg^i27 z1fN~h;5wV+=K&*W6e3kmQX|v+4!@arKSQHBG??T^qZ%0re@tWP#aV2xC)@jUl0)jp>e`(!VDjN@?IE$mOs6V_tjl#R+J~(SV zN!?gEl1kPumIuFi@n<1FOyGrk0!Qq2j56`>z7fRph|l{5bWS~jtm#k|J(B$a9<$8U zSAu%@UgDl7z%gA=XX+}R%~Tw+hYj;FXGiEC@x7oe7mFk>1@TA9hx)VGNpMaoPe>aKG zP4)vWS(MR9k*lIL4rKge(t@C26EtVPdPq4jUm5+Zyd34QPEX?d28JZKY{*eRh?d*b zPEJD6u)1^eSJRBtH!{*mL`HpQolEg@SG$k8K7oish`gves?O9T*&*4zC6~ z2A-Qi7 zFnag!Zg9$;4_LkTpi$%d%=X`h(aFoERdD>Ujq<-`lKdG1aUWz2z2(CJe5Diw-SQvs zAOnwv*A@(RA6G} z=sAIW(eO$XZKNB19}Qt0|42T0kPUfx3mEJ^gEY!5Y3nCzsW2$JNX9f_M9nUym;-sV zYO?!k;NjGO`~XkbYv~bzdM-V*j!^%N{Q*v+U|eq{6Frnl&tzMkKyE!R+r%;q6akrK zv#bLF%C`hCD&UUqA$bGiB|}9-^viQskHo&p^NxR)C=eki;;)lXHJx9WCNfKuoQzWZ zg>mye_#RPz!5&bvs54@&s+(D7>=pD0rkWV#UySWX2&eKFIR@XJPV$A@6#UrnK*Th6 z_lJn4=6V;SDeTj6%!Hh=Psm?fg)eU?jg2#Kf{;qi9|QSnMgIki`Y^@gd|4a5P*%Z5 z0C+(w0g$TadD%58KdIzMH%i_AH# zu*~zt&cKu#W9ej??ol!qk`2>399fIeSP$rjX|~Ne5}$t=^=n1_Xu^*A8UDZiiL%_} zP&P@Ei-2=j^*#tg#OP)}Nhfjw<9MhHv*ozw!c z9yn+tIi(wN!uUoNIu7uJ$avfXxKEQ7QF-gmIT02fH4B{2L@A4JDKfHZXD&FuoSx5{XG#HBGK z^E6zpp*zH%$~~-p0G{qe>&3q_PG2XqZ0RtY`(b);tD#p2dAJ1uq8YEdeJXpk1)eH zc_@|Eq?%v~pn%E%DA6Q*K5FO#e3U}!5<9jV_$>p#Ow>RAq<`9WUZ!7w%n=yHVR{-4;#fWA6TUMo}n6s z!F!%Yb~d+K4paCt3c>K_>iuT`upxYe10z30L&KQo;5lT#w!IYN+d#A&&j7Iss3r{s z>&a*O2%BntHue!5$R)TV*IAfY!1+0pBsLpM$p{l4>If<2uTsT0JXLwmx(B~e{Y-XiftIQ%{v!x=6OxZ(SupZ$D3OizG#nu2sQ;p%w(o#Yu9 z*3_8qB1)mh+2QY?BS8|(YdgoBMyIr5zJ&o7?xc^${s}AW5aGp)&=?=Aw2xqnwT?f$ zy>npOilHQxXzKttD_6$IeOm=;mFe2H1vMP={aZCS>_>-CzG!Fo-W@=&cFOU^@+jv; z{K1~BDciMFXq+}pjm5Ijw#t~>)q4#RxE{C-|CO;zUE2ZxP-td!xeFQ6GkzA5@O~0w zzCGclW+)AN5Md_xjH=%#?{U_%^*+t}JGi)lWSq7f+b}vR0od1EiI9_h#kb-tl zZgEC3;nYu`{oDJo+Dxm@%DKO!m#aJ1C6JxHox==b0|8I#Ym(Pf4u+W5YL*cJpq(nW&=UHBp- zzSq}=Pxt|nJHoAA?8}KX;1i!AFFuLorH{Hv;dXjE*-7b)ZxMUL9bSB)6K`zkYslWV zP^ht!C0K_qO?mNQPkg8pJ9{KQ_O1>5pTS*1bEzME6O=9mTx@`#=Ad`vK6mBhQI$+HXobO#c>NJoyj@y~3r5?FQWZ96CE!9ZsD8 zye9$HB>W(FLB0ZaFYX|2p0=3IWOo}>UZCme{uu5G-24o!aW21<`Kp))^iJG9sPUI@ zo6dv6>xS+>rzE2?<;OS=I{pYT4p-BQy%V^1V_2!dFI^CYbOty1TPY+2JG;Aul}9sm zH_D-%#*6j1#97&h>8x&HI>~1qXm^9QOQ-GQzI_;PLGIhfpVFLsDm4%ET}Yb;;l8P- z-IfB`>SwdbU(xO3&dk!;Y)VJF-)YC^ckoNR>*-J?`8leq9ha<#3_i&rM!cc}8?VP{ z`R@X7v_tR_z?9d6DXfi}jYcg>XH8uKw@Y+Xot;(pLzazrF5jo8(d%sSXN1H09yk$k z7sH&$c-@(WpLNoHASTMzaM(7-_#;rzhm0Y`k( z<-uJHTrqIO3;e-&8*x(J3vd<7RvIkZjcYw+V&S+cG&Evo|0=E<}*AwOsi=F+CSjD-}T#6Uu9_Zx(q^17H z`9`H0#MyRM&wS9>Aq1aJljtX_EOI3IG=eq{w6lm7S%n}U!gmAT2z&v@`y;@Uj_&}T zPBwju@JwzQg*fBf5iKs#(Q4qxkID>&;r+WAxC6l1^m>c( z1MuV{qzeZ%#X39W?5&LZ{dyc}$sdYB`JoNXHiy|+GMJsocD5PhCx|~RzW!>0w7UN_ zKNM;LcLL<%iUt+9)e>IWxIZX{CgW!KkATMwl2rxlVzEb({^2i_l`@gzqGIw~I`EwjCkaLJm+H=S+ zpgaNP3y5atoGu`sVgXT~;jtA0suU0{&+yn40$L@YIsr8bs98X*0%{kKEFhZq^PIZ{ z)FYr?0c{u1!vg9T&<+7TDxk*%v{OKj3&^XtmWRy%hy#z*BXEYE!c&I887=LRJbEr3 zcHWw&HMsXkyG8720ZFhloGwp54-4p!fX)brPKoL%1XM1dIsx?xh@QN7ibDc=T|k+3 zBX*vEng!G&phpFCR6wT$MBWy88M1)L>T%p@0cFDKaa^&0RtTt7Ku-$jlz`}zG*A1a zfQ}2u;V@#!8y=^lXB`fW3aA<53CDE{Xo3^@Y=?LQ+Sq(yX@Ffe$vfeBN{YM&cMonx zgI`Iy0XJD3j-l^=uSLiU9Z1j=0<#NkoWN87<3=kbFpa=a`zA0lrLtfi0LG72NzgCvGXt1*3uZ1byDXR>Fm8;OiF}q&J{Ank!|E)UwZIHmFw{TkAvKZD zBf$7A7_u037R>j7*=fP-1t#D$=W~c?EST4UG0vc;O86#y`&=yE8K=p)#NwbaPKxU? zqTv_m$jVo!BapY=O$nR9y8`% zU`|*tJ;3x}9-TT;E*nK!%saw9oK2l z4M9V?K9`bMu0QECgybN5EyQRHO}Lng5;y}xt26vEFtd{|Hz#2#k}$MNlgOtTp@|QF zwb#oH&2k7!+aY}3z9Y0Qd|&9k`ql{6v~gT5)L6>`5>7$3Mb?En>RSoDrd|$VQM|E5 z#tJt-p_(t%Hnnu!6Is{J!v#_;%eob--8j|Cjvy_>vA0Hi+n%kgH-%dpTiVue>fBr; z?+As^$vEPMIXI0Z&$&^cJ30O)J)^c3FoJ_?lx15(JwF1qu$Iba`8RTiQFMfiXq-!H ztzR87lJdHTn?oI7ijfMI&EbaDaHl~)6(}qUin1wWuH0H9ra9EG7Bz1$5O^IB>cDZ_ z&>9Gql?9Qb{tNXGj(-^-j(36ONJpEX3_K5eIo`~y|!#J#5k3-G8 zUZGZgl5t_}ns7@K-kBJ}qhM2gs}LqT4;?bt#2XW6kPt@#ZVz`R0)Sdkz9>s31^X1; z20N9t;r4ax4Gl5J4$QHnx3dG-P)y?lq2?P3Wm*WAE`I@V`QrOp83T%l!I2yur~F?0u(qvN6gD?-SWKk@1rIbF>+U zj@^v8Z~)8pTh*oTLnvBG6q~YZJo0L-$f-%Qjt`F73kJ6o#KtTl=X*h_`y}<3I5IGtru=@sYtJ8} zI5c-|rfb`NP>f+C7=Dz4wgTDb+o@a;#{Luhb!{3|FA>AMF8-<@vzpa8qGw)~Xw^hhgOmG8wFuo?9nt^@L{f_$Wa z9HoSjZNmk?QEfA@0UF#QBepk$_7|YEEcz5p-qF6ZuHJfJl!I;{>1>Ke#l8f@$7sHZ z&ktYmLNT&^mSzMWK7j%=X-(1fjeV}K4CL>VX`@pny-h)qOtEud4-k@iX!tPRol~}` zI!?ABZ_bKQ!sRG|(%(37`lC38i9OTUHxET{?b%l_wCS5rY|rrTvG1d)ADPn5p>!00 zqX~U>kRmoqWnYFX%Q3#8XLt3HbkKe90UIjqI+RA=Y@K9bneP>VkPNb!#1v%YIl31U zJsg|E*C1UbgVtnJwzAJgyBo1oa&CC?a2CB_uCHHr3WV58Jt z?0-T3f4e8YA#x&q3ZENCMN=6G`z|9LZOg$oMp0-Mm2tLgMoQ#jwA5z=BOSwftEngh{! za2o1r*B;ttvBGmU2+NwLt@NlXGS$izYI&nt-mJE_)Amm6B|n?{Dt5PuvpUELN5@u( zvn@Q_J}%s74%5*Wd*49UG;N7T_9%mSaR)3kjxfkmaNzX}&U6A-@QQqvxKu0a=ur%x z@#1?`$@bAcKH6oN*R#=KbM=z_K|3tdYU=1b5OU8~Y5%6te6d5=R|GqFQ1&4%3tL^$ z;`q2$(FEUL#vwDxl+IS*1NEpfeYdk~v@|kI*&;_gAVajYt28h|AHvghm=dW6BZvF3 zhpK=!wCTwyJPTpAg_q2{;NRem6<3F<=1~b+C94DDKju#G4W5a0`p~Q!r+JF(I8IEb zSPJn8E~ko5N9%lJz~OwO+^3P;6#OoN@o(_GS`{d-4t=<}r;8-`5e9Ey8eMy&d0%w( zK1#uGofeU>8IyM3WMMO7?pfvJl{k0d>TN+Z4g&VRL}aUcjnU=y=wjM~O}&HE&IkE; z_4ZO?74v4fwvpR6?5Bh2uLe=ydwXGQ#^f1iOQ3668a}gpskQ*0T+N3mPi3}n30AAltzLmJf*8M=DEfiM~UIiTs;Y`@yo>m%w?XYQERoKJZe)GB>N zu#Sq%#3$lPkdDG&(oe#`Z$ACfr^~e(OcpZx1~%WS#?(Kl2X!mP4`aGD`_Gjj8{6Im zB^w;QlFYfeAg#oCOIK$1e*lLeq=H!?bVK5@1w~-vV%qjHFK2cY5MY)GE--0(*$f15 zObG;6F-f}mLNKGl|AK#g@40$^$I{amF}+B#z3lTkQGkfH6A=n20};>tR?3|!Q?A@! zF5z?GdwrBa$)L8tr!CD^%iMj3)y0|5<^ZcM&wB0}7W;~d-I`=9it(}O{WK^$=0P&5 z-i&&Y|BgXx_%nRT;?F%8Y;u2kg5u0aP@tcNZ-XjR?Spo$e#KsY8yrU z2mZkxFT-}|q8U%7Y{xcM`6rkxF7=SF11Bu4R_^DPR&##&ETY+|bXOnNB50bJLwoLq zajfww*S4pD!sO=yeh!v-C6suuYzFSD3}!wjheYbIVKGNk549^t##lDTru)}t6%JXMu&4$OYrfxb3**v%xPMD$6k5_h)4I54#Xea zi&ZUYxEn&-i#O!ba0eh%K8Gfnu}Q-X2%_Gr@MGPpis7RfbX_nT} zjun$920Joj6A@NY(D^J?DYeQQZ68sGKK$os*NFOSd}1Cg`?USTe}-u%4oTc7U2quR z!}KAMKgPant&{C$1&2P=gveQK&X&T=&ef)IE4v}TZ%oe7YCN--kp64c-?%_?1#L;W zocQRipanTlr-;@SQPNsjSB z!lUzzj@UwK5)6d;Szms3)`xj0Rq_W&pqz9m@20|`f~$1g&hs85HO5ccS)Q+Kbfn7H zq2lZ$7I8}w#Xj5O4^iGcc9a0Q0`{wDumIA(k&2@uneh|-x>|_(@U7}Nd5=t|$~RM{ z#1Um^7CUABF?N%V#9oEsQYH6NCE1sM9kDhDjgEt`&CL*FR{Yqwy|0P(0#}wsB0V`NT^-V^6`?)cOeIfn!Nxv8KPF)tcpHXf62pIq{%!2VM}sMAn{7}KZDYHu z@29BNM?+LQSMLw-Ukf&>!Db91GoB2%`kn!XDi3+FDk4{*ugW`iSML*?z)4Dpo%s@Z z+`!3$`~BL|e06ZvxxsTOIB|t3YVY$zk@FB-Z{X|8nFWXL`wU@e0?(+l>W3~A{7Rlq zr|U?VsFx@SIkIV0FjFp7^m8@+C|>@6^BI|n6j+c)@9zSmTtAf)FKjQJVUWZAGhYyl z(fHHk2SAc14F#Ktaiz^;?^!e>KvO&z(KITb^)g+LSpWJrlELt;BLC-D_%{6KyMwc@ zl|$>=!yWY<8)o5Sm00A$vfC_az65t&SR3OG(3q7vJ)`jrh$wp~SYj`y+ zpp`7Dp=!8M`@sK!`vht^Q8`C}r`sIYi!i;n^6U4{!5`f{2v_5mZUblh{suV7n?1AB zd(F(wYi3Ee&X?BJx3ozWk$UOYmBG8H`fzv1M9_r2&@I^QT#qF}sW}{8iya*w;!V|5 zyw#cLj$kEyBK+Tj`?PXi)XR^3N?Db_yK$>{V>BBIX#5hK^*7#^g5H6f(%NvJ*Yo@k zzo&7(t%oW88NhTCY}`LUcxLC#GaGOA&g_)xWzt3&o5>OK*3&<>I*%y63La|1!aV63 z*6LS>IuPGn-|59CRQWKt=voI92>&xu;h-d?dw_YEMrTN1_5$i z4|i(B(BHK8dIk8R2W}b;e}$Xx4`TZ_u}_u0{pn9xk+i=s1s@=EV-K0wF^Y|{z?e77 zVlyDk4ZCok!c8+9%3Ddn4kHxSgWwL_)cftwYt!B+l&kNz4rT;WpSMl03#u#~J1Ud* zMwO*c_~oi%Y%NYE#xCP*6id@D+JkEB!Djo>u>FgD(y=7{E@RVYC1{I5OZ!V{dCbIb zVs9GuQ&yv>@tf=LC8&Q*W`OT!eH3{XUzGH{qz%TtXl%t~`y2;Aw*z!Ee9%R!hsS_> zd>k$Y9PJt~)6o?A0B{8?CExc%cF&F%Wi(b$UBuoue+p`E`pzP4*+jdt?=fMAcRt7~ zkoEx5_9UmpSJ(t~Vfq3~i0xaXz1Q>|gbyIc31t|}s7oE3sLhMhQ~z}$d||p5S)HJK z(MKC~o~Rw$Nlo={a}o{d8GWZ@A(Tf^j@zQG$j+#_*vVu zgND9g;3pbnPJOHwI6L;^mh0&fGKc8~?s3FdBfegbxANy_G_?QZ0BAmqziOmC4Vpac z+r86lE#y-@P{S)+wBHHhq)UAS0LAD$2YW#Ynt@uyts%g?s1eA@Ecx(?K9(zzg zMQEFuEX6kg@z^H?^qhdm=R1$3H=`W-l7PM?p#K2GOZ!;hu7^JH6q^N<0-fi$sRFuM zKwkiK4Y=}1{!IpuGZmUO)o^Iv}7! z0(x0MM+J0DK*t62x`0jy=#+qB0y-_A5dobM(5Qee2uMQT=hC3@okR3A%^`X+;E-ED zwC|7OXt9z*D+EM~YaCZ6phf}FlLe1$6;Qi?WC3*vs9Qi}uXx&C0c{u1!vg9T&<+97 z*v->ECZL@HdR#zH3g|}y+9jaf0@^E}=LIw%paTLrB%qfCbW}jc1aw?LuM6mefKCZ0 zCZN*-8WGSL0gVdif`BC0Y%T+Oj^vO-K=h3%j-&Yohdcrzhcz6RB_OYWd;-cAP>z87 z0?HFmzJTb9Ry=2VuHsO!fXW3#GZ`LRDIj{f;y7AB=g=wv)d{FkK+OVb6;Qi?WC3*v zs9Qii0`ls;2R2qfhAr_(S-QkMQn`R06Of@B9?58Pk7Tr^hi!DCdSG|0UYbWT>g$mn z7PwOaa$sELDRKlQ!K?#j zmj$y0m;nnW3JeA>Q_kNe8VlwJzyvVcNR&?NGuGXY2Y{jP!6s;a35*+~asqP_m>vt} z17MC?Fm{q8#^Xe)&j3?t!CVc@fCY0CFn)~AJe7IR3uTvTd&r&mnko>ulJ^91y!rp% zwA^NtjoYFmESeK1#w&;*~+>lr!TQ8}Y1V zO}Eg@KxpC}iA~rR#+TP>JJ;8@)5f)Wz8esm1hIoJy!sy2?Px<6IY4L2N-TiLq`Vl z&ufeYDm`1)imi>|#6~)=*ZbG@(&ZP-724NBlXQA<>Qw3dqg@$v zD~AGj>8}=!stcV8+kry^3%z|sq*ghiE*a4(&!|hzXqBVtl2I*iK`p#s&}sp<*3%2} z_`gp44h7EI=pBkyPezDWjgu7a01vMe#k(3(Ds>)bli0?v!opXeMC&_C z!@rIU|2o*7rCp(=Ml0#1=~Vd+c&T9ywC%1v*;-AW^5@UWcc`P!-iFL#jmQZvRy=UH z%{CUyBc9yw5vUxb7gUTBUKQjDM6te8Xc&nTZ(*)Lw(5(>IP!gDTtpeCGohF=<$EjR z&+vCJ%hb2&Eo+GbFW-ks=;=&yJrihaQcIp7WWcYM?24A`Qj7f2lHE`qT}lzRR>IsD zf(Y2LWlpVRmv+0u^~|y-)Iz^ja;8aL(sp=1+oQ#Osxpsv*gQz@XI$FdUahUpwe1MX zgPe+)=X`pXNtGXb$If1q;guR*%dryi@;d95R?wAtx%d5i$EHi@)#MO$BuV$b4}~s{ zR_E_hYp@H(sV=J17Wro3QwSrrec0wuiiM9~y&JpQksYR%zE3 zc{$AysEy{<;j@7mDXJSgUMh9WD=HkS2ORLd{*tk43mV6`HN7*%8|6$58{WX0Pphii zdOlF(lD4eEdo0_lvx8pjR^_N@h3%rf6z5vBuV8TVl&$9&;Z*FNBu9$qJJc!JHV{%k zN6^Ju{U7iWlfsK21mm45g=yMC;Z1l=&l}qC*9?ZpL5~-%k+8c8HFs&{*dXO7IN~aL z1(o^Z>?$uD_H5l)M+`(eY{+JF0jt*5PZ&=#`p!m6C%JArI5?UbtxlW5*ygn$=7V)x zE>V~}d=djo7=IC&pbqxfdwAKYNAA9wT29CZyQYF!vyLjGS8kzqg>3FgH6RB^V3an2 z;eWy~>Gh%hw)OPG$Vq$5x08N0uD~nvjXfJ>NsiDf)P+v13d&|z56wDCJ!#gjv>m?3 zL5UZ!-K1a$K1o4%h1aUGW*ymjeld*t=8~<00sN|q@Vy6L*1@1G;RU1}RP^I01 zI9t?yEqrLfUYgrCDP!0gc9cV7 z@;wC~xgH^U^-sBn2j8}1PtYTGQIJZ3H}WipwrYx9UFERj7hTRlVJCjc))x#%ey4#@ zJ(v3`c0&FaeeuF}aHx2i1KI06?T^DMU}|4c!scuFo|k!3)OilA8`*aw`)*|4jqJOT zeYeOSnc7CM!3(c`*#_&o_UjenRqDfc4#slF;@Q|U^(++%{)=CE0Tqzo`rV-|u&Yqn z1rC*b7GtlN69&UJ%JZYO5H5SJ_RwZDfp|Mkv1kgkqBAx~%>e+rIflOnEo1zvf94V! z+x$abpS&q*o~@% z3}8WsokZFH?X+nRZEfr6;p_3Vw)LD^Ya>#`a1AJ)qR=*|C|29fIH(aVM7;1l&sux0 znMpz~-}(2PZ+=Ny-G>1f za%fZ?6%*7dA z=HiS@$n!yRz3{hfZ$LG4pT}6^HqJ#yXw*32k5PkRK&VtxaqlWYI?Wqmn;BuKK6aZ; zZsT_oPi{Yrp{>*ve$N4ox|G6UixvX;dZZAk?6`L{rW>V5>c8U+($5!hKOZtz_}@p# z-afxbq~0?xqwv)Fs8o^bWmmP@jr{H8$vXY1lI#j&jn}vi4aM7Nlyhd`F;;oZd3m_( z1Qn~?2@j3=UdVl=p&^BjI`pnTA*yyajVR;bfyn4-Z0ahjtK3~LrDnC=bgzY6D6*O{ zX>wBzZzJ5vm@M-eA?Q{tg{6B>>808z_8KPwtq!Bq85D9U$Sl!GBMPD)s6e@)JWv0Q z-4Sw+SF|*XZe`*Q)J&JumkSYQcw~t%k5m;zvaNpgn-Ca9{9@l_Z&~ib>a{Pn3${%A?JNaqQMH;%>ikU}S)pt- zG@xGks3+(SAAN5_;8LMUa6w~ujqh~u8WUPYISxokqSMeQi`j|1;-$3y%lS=MkFF z`CC{aU_GDBj~1anN#E_X*w6Uh5&eho4@N`Co$bIqMH64tpPIYkzEgehQ~%nN{NFRz z)%jAexdZZCT|WasjBze4y(WuNX~wysd!X18Gv|v;aqEjcMkCFx(=Wkm%U|XJJ~E`z zTjX*kDko<#$o*{iigt+0a$;#nL}Pa(P*AuhG&>xlu$}0p;Zl^%4&)s&1e!5i*ZD|Yw{t}z^F z7N?y=fL2SsjoA`j)-1zO^XDMO4$S)Xr)rwJdK*#u#_OHTe@@n!4x?;E{wolKt7tUt zXl5c93lA0nQAwlcL3KF}`GB0Ice1>3%tZg{eE{YiUSl_IOwr|lj{0_+3kM9=<6wa& z_<_03m%b*8)qJfjIQX{l5x%s(1$Dj9l6!|}B#p+*X7sTe%7P4wGOMz&AU3@4L&W59 zY&Oz1g8V_?A|_v3kEH5PRc4QG46j&$B)}U>?I)6&1-5l>h)+9w6(Y<_5vKgQk}j#*9u;Y`MWu1ZQ+jKmCPZI zV21ToBgXqZewV`>JE=k(TEn0iJePL|W$h&MTV(diaTxRYTzpf^@B~K#=5P?j3?Cid zvV8;T6>eiJ9f;-%-%mm>^N{%f<^t$og65h9<}xqjozF*wY;HupT!83S8G!|OR3z$S z32dCvSyl$Zka%3Xo zt!K4mUuy;yfShBI#YzVJ!u-IEZy>}8md+037Kps+NVGz!|6ACh8pDnPmwDh|`%DtN zOmM&#+v^a<&&Uk5tcu3FgRH@tGQ)Sy-&z{iKRGS4v)0@mf8|{IFJhgMJQcWyq`f!N5 zt+5%)bdXYP)&kI6ij&9*D#$BVv;-jz){aBn5D;5&WqYU{OLX-O^}Z!7Z7m_J{z0HI zg{!^+kw{o3$M2q{4b6z)lD3w1%B2OaWU#))SZS?i#I)hOjcqN~bhhp^>d$hW0I%b+FT#(v>J z@NiX;--66PC70w&Lsl!DZ>8gE5-*JVF1ULV?yj-i3BQ+1pP4sr!Tv+oQ}B62Ii#}j zn;dCh8zJ(6aqM!kk#5Se9fm(6x~FjBM{qt=8yW=ekiubdcu?^tWYD<#x)Dp!KR~{m z!C!y+hLL5>(jFbbW8^jK?IHL}dA%lJnUA85LHdh=Xeu8?-C-Zf<;N$%U#s{neUZL( zDeM)n&jYU){hZUvi=;C8MiO)RIMlVIkY*>n2_11h__Y>(Wn+i1-3nLMiDK2NShkzM z^9XpZO6FObDBE7xQ@(BTnajqX_Vx%xi`0AQC+dY0yNd$jH50}Qnin)t51DJw&q!^s zQ(#ApJdePR?fgt-mUjQ}s=$11hT9SZ#FZ3TE>=FbreEPmq!DppXQYU)d2Z`GPFB@CJWjx6zvEQ^Ute&1SF-V+^8ec1#9=!!gdi5+mKf~ z2*ef%DLdrvwF2>=pbscR!}VR3-lbZkh&v-*?dw3yAFuWz)(V;04DD6aZSF>RwRD&4 z@w{637@PJdg`B8+Qw84yg)Rm13121yu@!rTd^FEid$lywKx#MeYOgBvK9CPI=-vam zRM>v1Xin4-NgD$s`M85EXWhISj!je_=VMY{^MLHc(c zkaV#?(drfL6p(bg1$99B_YRQE=L@mlB+(5DEmG)x2Wp-O_n1nr7w@@(#xUuhSHwf2 zDn$zd$y9DswEYUX;j?tX-7blm73x-KuR>9UC=VlDbSTuX5Z8&MZGl2OIUs3|D6~r< z3^kT*ra}b@wJJ1{6i3VCB}h~1kF}6LN)DV!ii35#+u}jg@hcYpxtkAH0?)#KA5ty+ z5tLi;zaxcG4+>?0q?7`gz6{fyLWz(9FB3ff0*VjmN>F|V%Ht`Nt)L8~Q251_D*N#p zP`c6D68^jiiXSb96zHc4t$>R9W{sas7DdkPG=9=a3LFUinm*L~gg+mHx+#T1#SW=* z9p{6hp>`)+T>*+Gh4MvEHl_?l$g8~B2MwBI&S5tp$lVTu4i71MYn&5>3ciCbSg0g6FOB)-v z_>scj_flPrC?CSbQu(u8JvEHNIaMmpZ-!BhrcmlAZjlm0x_>8yhm=o-QO2ljwd0dH zjB?p93TLbGXS=#_7=_YhsXTSVC@sS%>xNM%o0jnBA-swDIytnWdFir-=6lW{X@Lw8 zpKXwFuw)l3@d(-Y>MW^^B~%B+k2dJDf?ljP=z_A?+ZL^Y#7Jvf3p8p4EnP?@(8Glf zsFo!O>68+ouPFJwy$OXxop5^Ry`n@Z}GAWTUe^e2hWK+0a=t*t@6LC$7r zds86EY6x7>BEIWHL=hu?DoVVxU05ty+-woVs}!?A07>4cbXjTsoAMOVoK*(}U&vGB ziB!-u7h1GB4hD))0DLH@3kSR-p;((r1rgbZ{l%bboR?I_}Suga3;pG-P z%Vlu4K;K!*;-%201-l_KJ*7fZS>PsNS6U~_!Fmlq^r=A>K{Z8gg3A}*V^@t*sMHGL z6Wd}PDjHOSn6W@+N#`}-Zdek+aV|!otWGK+Yi5L#q+)EDm}?>VB86Y%|NOkXFMjch zKHoLhOu5b{ehK|j9T*`dh^jtZCWeQ3IPb5<*#Q37FaA%+#MC1kCuWQHTj72V@BR^F zVmKqBPSE6^;2WY}sviv07+Q<8@`nyt_&3*hp1bR~oE*zLxCV%;I237tJOWPj2C#C> zJFc)vY43eo_fm4de@Vw`r!zQ<;w=zK_zXV66ZfiIbEXHYapQ0Xc2UsGHHQXj9o;%>jKmUv#bJonL2eqT;ms|2RD1nvTUqomSlVNuCr-z*bc%Q{g%y< zBRDekt`p2H#gQ2eN)D>E=-P+etI)d+N)~vCMy<*Wk_E*0YgB_ z7qKtI$a+OovO+5p(Z~|A1tKZ1jd;7@7HQ23&Eb{hU&k~K*~c=5@g~v9hB#L*oaPFm&*;fqc@5~6zQGR z;u#+FuJS;kiip!_gmSkGCA`}KsTOx=HR#`>8sX=^gB`x}%(4RGuvt@KIv+)3qd!Kx3qOU1odDFUpfaYLxECE#T5Ge5 z5RuO3P*h#LSckvq~7tvLZ*6d(zbql9-E4sL&o!MRBPd7OA7}V@nk-v1M*nUjdmMu;qn* znkZ)aAKecok<{;DuL{ZAhv=_xn`=DSX3XXG@+*im=L2kZyb7w(z~s zvGA@1a?Kpw3M<=ab3Rl>Aq9Q}S)zAcfy#nl(etw6`=hmt*v+2UIkI*i84Z;N709YC zM+##_^eT%nh8(uqzwqCxMqMw0o>Y3#)7YD$$4@8t5nz$U5=MSA{6hZ{lZl>EeT34`e@Hw3<-H~ z>RDYQb}%?JX@^HG#D5eRZm7(Ei2+1^%-Fz9c-IsRE#Q}(6RlPxd51<2`gyALEXx`; z-`@Ns_`8LlAi`7LrDsRP$!?lrB&n{?9?DWRj78jSY$ZqdLMa;hZ}*>`=<~d24jWfY zF*;ejYb;n)3K(MaQLy!f9E{5^XRT>qru=zJLr*9^rTgmoI6>up>aD}dqme$rYmwhEHh zZp+8bN?L&B!Y|#ehRH_vd58hP@8mrL>yDY$^vd)R7EepZ`QT(T3?&0U=71{VR)I|h zoQSv1IzNHD!_ooP&8`QRM2i(-eU-GIL>8{{m>ZlJlsOvRiV`-Dg;Pw;O6R#HW>%T?z`VTtebFa>wb2^IsT^p-znBT_^f@ zN)5LORb>P}C*~u4B@cN>3CA7bk57jNtZyr&uM(oY`L9qT7lMG0I27h(Xu;_icHGQ) zJQ;C5MVf8-{0P)j`NejZ0eM0ZfKl>&X#OqBfOfRP{`K3!Qoz64((eSHF>%N?%d;b^ zvM~?HHa&$0S6x*2a>x^}F3fE6+Okx^vPdgrAt~}5{cEu>&qX8{J%iEVs=a1p6t2%T zGSvYCb3TMHn~Yhx#+RF{DA^x=QZ`uTFT|ag0h9#`FnTv3ddJ%WW`)bRIUBOu_*5-| zSS(~=DHrP&aEG1WqvYWlUd^rCeODl zSsF63vE#|Fd?i2A=Vu44S$W>)7qzp`pCyTT@=+omtRvu@A|Ik5_4)nsO~hu8KSSH& z9}VLIUy-!&$w#()aA1HP`*V#VI^wQn%C@rt3r~=56xrNgUKpsSpn7pWPX)^_~ z6hpzt3?8%t=|k?w44KM@DI+uZB2K^JDH@pva)aqI6n`>X)2rFO3wtp$>Meu|3@DF036~fA-Wbx$Yeme%BE^3krV= zPlf()TYfK8Uz-km;Gos-{JZ2YSjsf4^P;H5`~sV?cgfiW3yY=5N`Wc1HTSXitE zZKn$NO<>swW6L)Tk*i3Xn<`f!Zu@!|{2#)61BUaPWH;Ov#!P33FvhG@0-Ui5zXe12 z-cCH}Ptu+__0-r`FmhUkJvS{iAZ>FMx<#S875auk|EZ7<{>wb^E7YveCWTmaC0{0DB~hM2JXI@cBh0bH z$h`#alYhx`tTebD={E^P)=N2mA_sS-yHhAL@ive`xr03LG2!YiP<+U(1mzx3dQ&I{ zDae&G&DC@?63z({zvP(#yc%()__v&ZrjKj|{IMmTX&&|?!C}wUm_nCDNj!e8puJzS zZ5ZW+6v`WT8*#=Z7rn9OAK=0_uH3ek!9l4^r3_i%FXJ+Ly;$*2Svgl8a!W!UfO`@4s{W9TgFu}Kdhw#Rwxtbib=uhGJCo;)iBqg+TCvZ+I`6uC zAAgAz`?2U6SocPnIW9yK< z`mwjGqCh~>Pw)+yVGd&ETMxe1IE}>bA{g?C_2`4)V>l)lVQRczI;fX+oKlpP7|7d#f$Hu`JMeT*RIm(+J7d>l6-!aJRXA3%KmpVrtdMP!I&`! zi|FfE*C_lT^m`1yN`tz%K*MR)E`*G>D}JGQA%wF(cOn2s9~v)1D4OdiB!=QLibGG| z$_pqw@E}rA0XApc4=vc~n86M*KBfZ`%JcP}s!bvhJ`3r_c3SXofrpVX z^Nf7+8Y9n0H+IJNM`{gU2H(ZD~7MZmW=Us@?3v(BmbNvR+^kCt+YLxL}_>Ger zDp=Ul!m+fDkJ4A^z(qKe8Ga*u%yS#Sf)zThVRL4~&JU9xOBxhQby!T|60)4KA+qDt z$)+Imrx%H}SX}B6)O(iQxTh?r?FrndQD~g!`aC$}i5277;uO$T5mD@yIobvm(X5Ni%&=(Tu2gSPi+I#Ap%Y>7+CWqQ}ysKIJSUwxK4t;pQ8$ zTGhD%1(`0~n2j6t!87hTTUP__`CIVin1xoBzBG_wSa zeuoY7d*jjkUdK!E_uzlhj9w%Og6q!g$n2wtmCSL@tCM!n<{R5_X6$^#Rk{fs)Obop2FAl``^S1d=j4?c#2vR zKkGyw(;vDgywg|s`pSSAz}I8&7}V<;QS?U93t4G;gLj??xcqcN|AGh2^rs0<_(!Fq zX1bxST{uUDa<6)((J{(V@}>Mp>2-qBy=2B_|pO&c<*D zPaIL~W-xkZD*`nqFhzQ&ICmb6F2TAsGl9Xz#M*KXkY<+F!bf^%glcUc8G+Ela)+d} zO4(Q0_VkC2W87ODQXbZoK)GgZB|1rG$IYXh;pnKMOIA(BVGV4MZDyczapKII9>|K6 zcyLD96LEI)IGML9;=IX$yHL^`?2vOs>X4sCS!KtX3}nfd5vuWe{yTBhk+~Vzt-?{p z!r$CG=|p*^A6Y(MR<$>c0d8cqVL@H6k!S6zRx}M>wSsS-_`_EFVpOuaUP2hbiTS5b zOwVxXov)%35SiDt0|33M<22#oU+-!| zIN?5Dc(uWvs)!X$OCgEN~o%eH(?xd}oan=^raS-3m`-e*YMi1!+3BZ@O6CKzU{$`e^l$ zZ^Fi`{uPgk#muph>8`@Cl+iHxO<&N_6TPw;nD*04K`f)4NvM{s^D`l|CIYF<*fDKnXJB zEVdx(kS;;`P_HTwAuAa%Mls;wCg%FHJi zjMxTUug7ymdl2s3_g-uU{HAvhp}i~88D-8pqMt$CI-`8LYT-9%3ZO42C3V;k&S;D{Npj=B02Vvv=St|8@t75h|$T#L$n9ssVHFJ z--3f3GCwlRvIRx})4Bz*I{1pnh<2GC@D&cOJR28GfQ11R4z4;5%c-~J>Rq?6PviQS z-Z`DHtjP%E8h13s3h;(#euY;lP<{Y-C9rJYv8&-fDD|WuJ+aBm#``zIe;o8;#L>dV zVx}C$=i(L~XbtK56eB<^4ZQN`*)qH$gI8*?XMn`S>?`PB8oOiv3LZAB%|7_U?qHeg z;L-ejjzJ{%?!r5=;+s3;zr^l6d`CfR!Hc;?e-=|%RxR?k zT3jZ<^y7eF{4vq!knL5mD3Zbaux~KSDtwMpA-(ha%#Pi9&nzoNb)JJqBTl(&CHkP; z{1e6pMs)j|&h$EL+PcgM(d$HH*bHUC;YPAmu2qN4I!__CR?T3xYt{JpRM~zoO1`%8 zD!4(CW-H`8G55q3Q=X31(;O==#N4?^@0mR+d^A1$`@t~>HWZJt z`_q_-6N4;BYd!^cJUR)r37(FHqdqogR2dan#`G$iU-*w1Df~9iq3`B7E7LyMDY}zE z*6*o9{G(s=)AI2XV}{?HQE#}6>GiyUO6?H9V;>lE@RfkcpxZc(@zS39GN%k{YXL)Y zk@0@`_v!d9*Z?ID)|Z4_=fwAyIL*mb@5pS3UEv^TXf#&13q8S6DEFP+oN_ZLv|Kd{ z!)LAXUL9+<^24eh#(!aQn9D?8%*-@)Fe{IzV=wwb9C?3lLv{8A#_sq8gnx9t&NVB@KLznk^BV6-`aVR>tWOwt+=-4;@0lq!P@Z4=hVcPfZIcbLmj~fYKe8bW1@YqKCsSanX5e=>!*#@A9xf4fZkI+4aK$}9+>3|kuPIA*5805 z^4Gv_Px-Xb;)JlAjzSs5{Iz}Mj0mm^s^o*q{^g#&a?vC7l`oK1)qJpB>0O^-W^jufbfM}-j(D@Un&Y}ZOKjFvJ?oCrp*k8e?CAz$5?>mS%K>WE#c?E8Dab`a)2Ipw> z1O{o*;M7MN3Mh4ZuY z2Uj5tj#*G9G7Y<)w!Rwsv!;BZj0rz@FjzGw1t#kAKy(aFTbnawej{t~sfZeh&xvy^ z`xtsutUqB&ble!Q$|3qB#eHh3am0Q=%-78tTv-U*%%P&JI{&5gJLIk`CQ9%WHs`#H zssi`Th^-dg#k{JiL|Kf7-Tfm4F;(c(WHM zjA+NoqIAR|dK+gG^YJO3jvK?~d+ky{Jv;jtrbtud^lB8aXwR`>^Sh^Ap3PA*IG)M<(_yrb{CpBio_8+hkT#KuE7JB zNVUU{r14H_-=SPsfw>mCkDy%%i)Sue^cWh8%)vrohBG+Ujy1lw?(atSp_6i=vU3W^ zuGgBf2K%vvJS`keD@x}|Wf^MG+{BoR@nA(s;gR5#W{n>^$FBHPQNBCOw8H+-AcT|C zAa{!ev^y&B&5M;Q*^EW^hBOa~@6p2D!FP?alK9q0jUVf5=$7V-bscQ$Ex@)O}h*c-Xk@tu>O>OYGY?$j$^FrM#NccT^> zAHPZVCzz&=4&I93+7aBuo%emb9nrlvCddJ!|2rqwQOCs6-n}dxl#(bKWTr95UNQCp zasu`&zYg3LY}<++Q^c37Lgzv3YP66>OS=Zw1TFn5<}y#vxu^672NpRT`u&>_4su%* z{NU(d*0UW9xIcOb(UQ5-*FIn|Y*~*K>i@Q*?UHASM0jBR@d&KY_5{ED(yt98GK>~M z1*r_?&SVC}4TFGNj+wD$Cb&QP8x&!z8iDr0OO8E$n1wK0Rm_7a{2R>=|3<#Q=AR$_ z;G&x44ejlV?rhMMQiQs?JC}fJ-zda;hbDqmdmQ@(k3$;eCOmyEOJ%8(}(OT4CnH_%J;FEvEeM;QfpK!JjIerwhWALA&Syn8h$1FxwHAqcDGuWMV7w zI17fu)H^V8H`>x<;Av0V)Sf=B@-Mul1(Ga_$IVN63yhne^oAqzIS8g3=0h0P7r7&k zFz=_9gRt{%Y-$%Y%jg~vU4$!*@&LJvunY8Z(uL%LNKYB_sbakE?$qSS)9>7~ z^P)geCB)Ci{}{FkK)ae4{!seVgK}{}W`HN+n?RoEf-c;e%7gBcgG;EQ{dzP+*8xRuYi-> zC*Smxm-ZjSoztxw`5DCYvPHQS=}dO(ORF31HW&OAaQhbA&bHhpOJk(noK(!PM^n^R zgTDkKvDcCxKhhoqtrN8K1x3;}fky2JqWmqsCqbh|gwI=iYzuoq`w%orBrx4c5-4TK zje*~`AA+|8;sn#li#mnUaN@!xp|OIJh#O%iPMM1QPvn8hf7bV*nlNxB)}KcpQx!xO zf@y-k1xTciVTyWIG2SyzO8PMGH^9Cc_NA76a{Fv#yC_rAEVGhxvmgAs;Pw%?-Hmj~ zG8b`9){K(ZHe!{b){$W~sbXB+2vlhLh>b|bon^zkm_Ck5WQOHY1$(?<%%$VfJ{W;q zEHsmBLOTdz6Md_dFUb}8}|wtb0w3S}$Ank8*n zCnaKjO2pieh$)naF_*}%P>Dhn3RNmprBJm(wF)gzXrV%^!!nE}g_;#=RVb*?YK7J+ z)S*zPLK_s?tk714dKKEG&|Zc1D|A4iLkjgP^r}Kf6?#jds6xjS8c^s%g$5P+L?O*# z=L>gzWe#!wSt4%fN#s$8a*mQlxjl)p6!IyQtx%3axeDbe#M#~@h);$#MWG^v{0ecm z?-IdBc}9sU6{=FGTA^BnC{1{YaJx{UdWD)4YF4OKp`b#m6n*ol%}%dZvt#eo29zzAVx$Y|uaRh@LWdOcpr@9$ zl?qW~m84N}N1{g*+N{uig$5Pk+*-Pz9w><(RA{e4yh&5qexgt=#tKQRRj5~?5#(AS zSGWYZmHM-1jt%dV&;9f#h4K(6ttphBf`Ue$EYXvlBk^i?Q3H z$Xsm#CC`%_!yqVCDU|h~Y)YY+ptO3EecnWWFuzKK^-H=+q4a@rAcgW0DBT#{rK{oE zcqmC~e^H36`3K&zbPRE6m4PJve;ri*&?wF*hy1q1gUSFNN{wDbCn>)VEgns?OL>$m zY;f6>vxiYWKa6tKFiP<-%B&R1$hS2uO5tHtmk*;*Q=t6WF-+A+L%V+&#`EYf$}fje z_M}j#_ibd!W}$QD9(E8?@rouoi^UDlMcTOH%ed630ZLqOzcemjY7hkIty$FAunO|l zi<*~yxuFdjR_a@V&~!tcqf`~tx+v5R!R@w&<1+yxtJlR)kt(&n3>D&*Y>i7-Tkey@zXfZ3!xHOOsrFR} zxp`?jZcajaksQ7wFZhs}VcLrXh%H_2dOnC6*4Hgmxk; zFcHfk0`fzJ?xi*z1P|@9g1#$>>u>0~~%jvm4(|PV^~zt*(YAjC}uq)0snM>^Grz+lZdu zma)GCaqw#k{Ue>?EVxiaUj6e!c7Et7&JGMi72w-@rDQt?5As0*g<5gWf#6*+1jdXs zT#z)w87X!c(;;^6Fd#ac$@!voo7}^}E*C!|v}6mp8xwh!bZqemK_ec-#8F9XuDCFo zi%l|G+q?aEsvQ~A`7fLcC6kEvD25GpP?RA2@p+*`mW(-sMJ$;N?j}`ZKc+I0j~^$_qNm8SSpf-43JOX{2xPV!P4DEjw$^J{>CD+not= z{=O|d(h+?VA)pu#K5LN2oMN1cwjgC@V2bI9%%HrDD|j~~>LW88xWhp2Ny|SG9-L;R z2Q%Z-&0=SGkAv4+&4vvW-hdv;-7<~I?2qQqo13SYV1O`}adzl{;m!uXEHmN9A>(*q z-^rJZ0ljpGT_<|rI+2TCm+`miw@cra2C>q!^=)$;`MrfN@>ng@JwZnCIRy9=(vlMI z^ONJ9T-Cenl8wit|1$YrGtcxVrMoKGeR%LJr24|};Mm}~xYP?8pQa&!>y3ajc!LyG zDja~wLvp@BG$N62MtXd&3ib&bf%*i>;u@J{^RS^U>H|gBSs-5A&2s8=@RH~&uu1Xz z^QnG6eHmH_#m%B;(~l(Y|G@fh<)0@?iOm#$E=%_3LwAE_jv8D=QIw;=v{@#j4jJ$kh4V; z^v=sbd-hJyVm=@f{-BL|jf~Cz#FDB(hbG$R)AW2xyL3AbBACMe@G{iWzHMAr_dvKNQpG#8j6Ce)JHyZUaoP%p(%`_x zJoFOYaU+I+W^wArxe-*uD&40!T;mp;{^(Y0$3viVG~jFmkem+O43m@w)WaPyF*Ni? zf5a3|h)qTD+djrJ@q%V!zsG-V_0JRF^GO7f;`8)mpSw<=S>~8?i#DT`oSrzy@!eT0 zVxNX0jFe2_fp=&04b(q_QcFStLIu>DQh(+dzp=XfBGX@F<&Swyq{b0GwO)VV8H|27 zlvj!5OJ`d!w_`l^w=b-()4adJjei(aX{oYlSau3Be z=5!ny#uB}+-uVC~PsuqD9=sCc%dS+W7Bn~uu1hwjIDatE-*&sPC;gll|Ecx z`5?{&rsUp_NAf{LhYMBV!5j3hmGDhO=NX8?BRUsbp4~w@WR!)}vcBPUO#N`T7m9Ej zN15owXj`%Chedf1Y^hPco_*ulD$4U^D4fzxz8pntU%{-T!<^-J%h{`2su1)=}gvOred?+o+zV5+~@N6H=H z!8OKI{ejPm`rpMhMXP3CSACMhd5=(Obex#1C-1M8~OjQAwQW61Th}v-F3E zEK~U&RMSOvp&h`2F}I&8~jBr(mSUiQlfTI z_Jet2e_Bbaom2u^OT} zOa~eKH_}%MY4>dg0o_{sy5!oYCT)7>0z?(v6GFD<*^a*Z5VA+pAGnZVaG2?)aB5QU zAvGC|Klv>7HnkYr|Fh$Ws)?{ls>NmyF@Ixzpc4Q16vu@K`6Uq4RH*AChFl=P!FxqLhlTTN*VtpvTj>8f)?g&T2j4c! z_BB|9r%u*8yO92EnPi(w59z~qEgr7>Zo80HQ)ty6-Oekz<`(s_vhp<7Jy)SOM}E@o z-zkJVK^%y(V-@4*VRtUE`}ne5%*OYz3koFWBC!?T5snLffV6@=udpu^N6vkY#cTD%F%AN@7qLr`8Tg(SeKgKM zCu$ItmMX4G@UrC{rm8>sC<`h*)`-@FM>7(}&fzjCKOJ!1w?@PS zDkOpv%>W{5y}~Zrz}22Oaf*9&ac(e>73T30F@8qoW+GpH%gRBO(jeQy|58hr?SEu$ z4*334@cE>3p{25}bY_iq`DIHk$G`T=waeOlE3oqIyR2QqLg!K}ulpLBu|~ck=!2GW zAFmD2L%Y`0uzC^Jr`vdJ zpa{)(S^Y$9=?W~-FSWR&FTVPQ=B3M*Vm&C_Zic z*WCQA_Vkaud*J_2HzU!=(}#F3g!uv7Zo>0#F)Jx}fBSvT|3a8& zO2b0r9dFZV#V+jMVw{+(*nG*@ru}!HkB<QX3Skm#)yDD|At_hKna~5Fx06sjZ>4VNno|V5n_{hMi6PYYR1?6T?27wyJ3< z?!UO|DsA#){7u%TP1A0erWH-oaB#Y)NW0+%?fUDrqK1~n8?++XsRAs;uHc;wZ6qyP z-hhYf1#iG0l=v0l)6@@B26Ge4Oqh8vUxKNFSpw4xb2m&7W);l6F!#Z9!EAu}8qBv~ zz6Y}j=7%tpss0(v6EHn6Jnps?=2@5>FuP&)!aNW2BFxJ$Z^6W2l7D~CIf5KG%!1+k zu7sWl*D>;9Co`3x?n7lxK!K zEJW9DmH#0x?*n-g48I4yho_Wx74oZ)?G8J6H6!CjKX!rV-c%lO_JAVpRYML5l#hdS z`;cP;1#s(zA0?P8e|H3b5LO!WHmA7aZGpMqErGkY;OjB5g7j!{%w z$mCLbq=cVE7QZF)jUd(}9jquG$Nb*}-b3K6RJ@Rpwr-{Lfz}IqDq*Ry>_ynCtgsOx z%jGTbbb^PnF2nOMFYU;Xbd`-uD;q)*^2eO)>Wp8kTDdvEkt@K#F>*1La#@oLNPpCz6lZe7e4wDtIZnLzjB zzqI`Z&=&-46aGuvSAnGMy9#k?e>sd-8-x6mwq77f3ji@4UhP((i2`x?Nb-GE@%>QI zD61sho&vf;xZp`)>Eb_tWI8CPClS|BB>JgBzf`Cf$ch!}rsTT`=u-Hcq16CQ5@FOU z+hst~#WM;W0+KGyMh%p<*+A0289;2IUeVu5TBqWBNTFVZ&PM&q7A{JFt`z7lpveMV ziM1ygMu9>z6q*Bcx!`*QNQU;LLZ3&?l(ZTk>C3l)Wb9ip@3U;tO-S2wFwRQb$qLl~ zNxl{!$rr%*DfvEA=yMojW&TYEk}leSB;Rg@F2we=^yLa5$u~>Uct@h71r_3HIZ5N$ zIf))o=t+fkDRfAow-owNAqTn@>5E69A1d?S>ii)e3PBmXD)f*-4=coRMuzr?LXRr+m_m;$^rS+Y z722v0$0h0CE`|0gv|phE3LR3YU!hkOI;zlH3PlwS)hpDbP_sg<3I!Eftq`RhWn4NG>QrchLJum`tC6!I&?nX0tq zSxJewMQ-o@LJukQutJ*@dPJc|6?#me#}#@~q0I_yRj5~?T?*}0Xum=S6gs3(ze2An zbX1|Y6pAWzOrZgVK2&H>p-&XjFyof_>{Q65kXs>-LSBV370Ob`rx0iV(&rq7auv!` zs6e493SmNL&Hs3oUCsnu3b_^XDCAWrQ=u${dNK7801kDyoi-JKT;`qNNI)PJSIWmikTmQBq$Gp!ZFG68JhLE6Xio>5cEru{olHCAz98}l#XK~(sK!NJ@v=+7XFa@GoFX?T0HOoJRQh!Bzwq@ zf@1bh=ISIxvGbX?x67YRDH%qYIgC;}jB?j73fokw&z-|4Vx>+n*`fd2FrJ?eqliNW zDX#XU@bF7;&hbwYU`;FIQvD z9+tSDxvdSm1a;}jvPDfiS2J=Z zAb_QHOM>^bHppX7w8AH0wrChJ*zGhY@C8D#3qe66Qz#(s2i~JM?ULQSa40DPy7;R zeKIb#^b6rsPjb6wRigeTC+f{woQCAD9Oi%GtPgw7Al9g+i^W|{y9?p^&v4e~N%Ty~ zKc3+kde(*%B!!KzkUly_t7ROHG*C&4mO{lNq z|Ec)f2DlspXP=56C7L*J{;BwHE%$@^&$jD7d(E-a*n9Gij+f)x5T+YpdU#9);ks;b zl=vf*B|M|;{g!_(T=MZHe}+QkXzXqXxpW&ZjQMzsd|xEr^FPj)@3Z-y-<$tZtQ^P^ z(Ma4+Q5pVdb#NiXX^JR00wr-#rW%qcMTNgTa&ho#y=Sc6vt0_FLGOQ+NvPs8AWov=vcRa)#b>z!E78o`X|QdQW+a_tHFa5CZ%h)#tE zFIx8#h%3c+K^6%42@To7T}S%kX-E3g5gX%Ec*)!Qawv0_heU+mczydHa1lrqszXtz zPTzL3qvIoF!ea=l@-T}Hnovu(J9a}LDGM=8JA4$EJiCr$CCWXP4&lY{J|A)<{O}(SH_abu@4K5%b$*R~xD9_U2 zY?}}O<2i#8oY0^U6En#^Lc-fNB)feBpgj50Dh_-hSxRoqK(+Eat$R`+6lEoBi0l)z z8ixnnIJlArGi6l}T5P8vGDrFkA4SvN+5OsfK3FLpU*^iQ z!#nhFuXFp`uv@?CIHZ}wr}UK*5FgYGRLK|L#`~%dK#xox+>Tpj_TpXtU5wh1bYz1syv~L9Kk_{TS(5{r%ZMUVe9WN9sDRLZk9Mvdx!At^CcMT4 zzup85HOq(Eh^aF=0CsX#oj~<(fyWc{u3y8(%rI-5u+Bkk%Eglv(Fg2CUT32s;P7%s7CK#Hv3m@B5CqS%{tJ zDe!n$JkZ@I`t&pP@;Yk4@LnFnK@mD=Y8i$Xs6ko!w!Nrmc-O+QJRxU|1aib@_wMC0 zvSRd!9q0~UU<`1Q4B5>A)&pIuczBl`AA9moj^hqc&xS2K@NMJJjp{w!^i??hR{(f_ z-`Z^N{{8#iZJSq(1@=6Tmz9s%e%^PScGu$H{xLg3&cfKbuUqNPKY_S7o8bwnj2QJ$ zbm#Ek=UxmF1L4nB=$%IxJDE+!`;>EyE{7;EjuhD)O7p*}w^e)P_D~Mw2#0}=nEMwde&MaWGac{tAYX)O(&8GjN>RQ!! zk}R%Bz;WL$mZGT6(Bta}|NixkQ?+{6J*a88uOTfGNJBJxUbG70#12oeg_DbTb~u{% z9Zr7au!sRs@9BY0+Q~gEBE7Q+5z-&o;pCN}zccpe+w9RRv|9`|+flXR&shCi^6>Hj z#uQ__=rTn07ieh7$6|<}m8mR&$w?((^x3&>70I-{uwC^f+)y(Qy`pIAvN$3Ovadt$ zz?Lh@Zqim!iv^ZNC1x-iN{X(7Nb6IO5=QBsJ+a@|nQqnht{V{#=v)3J9vnDqefnr0 zD1}UPh+g!~D{qX1M*r$Y#6nza5KqH_h!>$XKm5jx;e8$3-_Ce3zG0@L@MWB~S@qV* zgA+e>yfWtChTBJrVxhMi=8YEFAPFmlzTxn(1?X#o?DvA}kEBO}*%z^!WNxftZlDAB zCh8gAIbFcJ(I-;YvDSH!7R*IWX+@{xLZ_4%O)(`?qba)QT?<5r-NId@#bIa1Md7}* zJtesp<;9=2`XdI9ZiJz=S)rj%W%m-*Dfr$O|5{T1{Dtu!JJlLa>ZOkV_V^Oat`cL+ z+U#0{VcnM9DFiO=IFR+HENc?7Xz=27GwdS7**fN68azi$b)(^7 zt|Ja8*j^)lO#gr!jB!`h?K_|5a?!H}{>7#vIt-3IlFc7~M2&BtSUgF$*kp{ekmG2!=go3XF#G&HzN&HySHGg}cemUV1w|X^k89l%=uiizbIV zeWs&V#LQs|_zTcTF}W00VuFbafZm9db6PIu6XH5&si1vN$qlEKFB3oA%+MQ+jL7^? z5i~=KluUBcJCxQGluJR1x1Z|a8&JZG?z{X@P;rgT2U*DR^WREl4Gc^32QXZ9rs)Mf z3NrwMMM)tSbU9!ZOcRVB3xj1aRWOuc>VWBn`4-IMBbe(zo4mSq#Z2w8=H`0svdQ@c zcWPJWN;DZ4pD_iSLi zAIiRmDdD|&MAfrW2X8C9;=GU&DoK7O7LpYWvI zavfxqa{!ORaCiPXJd@-{A=kS+S$tH;x^hmMjRZeUUI-~mUCyOK_L=`n$4Ly4QiX34 z82u2ORKh)XVrS4jexxk~jk}tk7Zgbgf>sUMM2psp=LXOy1xa0VN%@kjceyGJGQ`6& z8@iNNj7%;Wfh^>m8LvUcVYDUxig!PZ8)Xs%?Q{GV5VE>M%DZg*rnK}uBMbY&Nd-(5 z{Md+L3uDX3ex#K^1GNW=+TFNM-BrAsS$WeC3Y-?fP!j1w_{C545#tjW-d5c?N&0($7m9;&BP0T0E`;P707e1>;et&RkY`Y2O;+oGC3H z2MP3HC0IIcB&E~E6mI-pC0Tb=@zD5em<7A1{&fguf{JrBed=haRCv2J^{v(Or@5a=2p z>GKOfR|;Ai>bs;-yE8wgyc+kTr9|m3fbs-wzoMOs+9~<&0Fp82R_F%`y`oUQ%jR1T zBtv@uC|~&ep0ceUWAineh z0Lgq=1SDNV6rUR-oeZN0Ncu7xNQQQgqV)h>A^iIcNan#xjHuGZR~7me&=&>YPZaIf zK+?bWf!HT{H8*OqbbAR97bv}2IgsSznIajhCxB#nM`K?{qB|5SgS$(GTgur?5@-`p zu0Zc7w zF@**c`cR=kg+5V;b7+|d{F0H#r4UC+N#opGBJP|^l&KJx?In#%brNypmncV}T!r!! zDo|*OLhRS1Tfagj3RNh?QCRX-DO9actwIYF;utMm)GO4aP_sg<3ULINE>ie~-7CHV>B1{y|0Sxo z{PSw76|(alHw!45#|q7>RV%bfp`!|M8$tR!1>>7UBS;-td+JLNo5b&LkvjS(u=@}z zhvw5LKhz4rgka<22+N}IBNE?`M-_$sbFB0^Z5~qmFh?y4qKw}yFqE;QKaz4QC{-zx zrJ(p=35N)sKk7*7Na48;lq!s@34gv0N^1&*E8E=|4--890m?uMWh*GQzG)es{{rPG zM#6-vH$ch5s39rIk_8Ufq&x1!I8qLj`2FJ~ia5u)D-n=|-m{*_qBBYqow9f^fdLP{ zPdpYS@o*wRKG-nlWo~?qNwj{FLe+HgXP4kr!zhI*6v}}FTk40n;t8{aKXuLZP+*Wu zA)b}OL&~CIl$I1qU26;1eyty4Sl0-F8Lr5RpQJ2Tu|ayRl&($jhswP*2S=VI^ds`GA{Ra2@}&MGds zS^lpTkLj~!RSGckrb?~6w0d4uO|byg#nb0ikpfUzs?8Mu6adL1DX^MZI^X80EYpfh zO0>E2rfav%tJH3pRiahRny;1IRHNO*f76R+mT1#w&C#aU;@{kgN|-s?yqULX(`U}A z)@UkAXKI02GXurd+KgMOw9?sHC5c*f>D+4Z58-No;>t>`y7;C_0p=h|b7pE~v*uLJ znpMST)tu5Qtr|cw+BR@nc@w+|RL+_^Z%(OJQ#_}5PPtZETRo?kAoa)bya48Um|~b2 zFmqsTgJEyJ9ER)Q>tQy)a0LDq%y(hF5Ay?WiSWzx-uf?SO%#s;;FK zLmV_l*>6-(0*zC+^r5|>%^p(zs&4(O^YgFES7Qq2kkDs=g%&v%9X_UXBe71z5gJp( zkNv#we?qrDvS?$T4AcI9rZJ^}%SuTUudk#HpAfE0Ec*P@~@r3F#DIzHMr-gj1NK}#8 z%AHYXq#2v#)*iOK<0~}wew_huXOzn8ECyR3OzkflFQ!#o(e=`XiYtPJ^X8kYvmp*r z>oRXEF(;Xs(Bx*;dg9PKT5*Nmvv1;yj*p<#Q-8Md7A@kw$yo4JXXq{N0e`Sl`8VI_ zgF5!-!^eE)-Oj0ZyY9WgJR7^>dB*$O-*7sf!=>8T$Tg-(qpi-~%rEP%)1gW5z=IqVlA5d)Yyx&hiINE@;b(4$lZDj^ERfmCg3C-%C4?{& zUgAH4{F^QRQOmN)F! z(oVivfPuyzkCcfVT!1i<0#>l~c(TWqIVctL!H48K2@nSa4za_GXHIT7#ri1WUP_v^@rY^y!>!6US? zUU%Vv&<9Ka(v^+8Le9nZLsUYLcJOT*-kxSWw(P|}NIg+kad%RCXNIU&n@LT%x5aJ; zk5#dxye`@kDlDXK^`6#AW)3bh=;<|YcTYPFKlRR6@xO5Ay2WOx-}oS0=+b*$(KnX# zJ0Z^G*L!A70^PiD!-Bn|tQW((*DA{CD9Qt;!kzbC2ziUboqZ**ajjMh zy^o0MJ#~{}6!j!924YtNKF#p9FfiQU{vtF~cF!|juyO=K*m@_I74)9kD~#WUX?!pWiz*Kje-V33;2T1>1vHL!74Yz}gSZa;Fh9j`umU z;jb3u`2n+3gS^dMky00IoY@dV9E?sx8TXaSp0rfrQ&3>V^g)TVAX|{A*hPpY z8;)Jy>=B?S+6!r2b6uWs7%8F$sG_?Oe@Zl(K|!Ki>zOGAkCJSk5Te3Z7nN}<67^8^*RuX|M9O7nb;PX7+x`b9>RKj* zmK;&^{O;><@MJ?}_Qh?BA$^p|o{-nDc(Yj%g{NkjCmcm}TkDJ$7{7r#RKCbOk6D@H zG2A(Lc#X;&C!U#jy70smC^>HBYQF*ZR{Jn#xXcU8yG!&Q1eiV}+dLOz5bDef)R~C) zTjn|89qh6_xat58x4fBUH8Z`}x)DL$tI}64*3BRzry|P!+1Neb_#In(7Se0_^UNAv zkbp5S{y7f&M!%^;5H!8aT_`143lFZ1+l3DIXwq)uWpkEu18Q3|`V5Pt#uGo>ZS`OD zpLZuPKjHZ;CENc<1;`X<%VIdQv(oQI6LA(Exc6G~OPNL=)IFQy|6ktD20p6l%>R>Q zfC!Npb=0&?b<|jcr8Uv0q(V)|tAZK@lrCs^7ZiaeGk}V`IEiw5jZLfFc6Z&b?YeDu zx7+pKS}WFS0!Y-hD~h#Hi=wsdjPWJDEJn2D|NWhF@12<>{P*Ag=f69j+}!6r=lwa) zd3(-top)gP_7Y%pS?@$!PWp!a z_{=2BMb#_ORrI_c+h3UL`xe>e3(!P@h<%Vbg43mfB+2RBakRM%|g=MSG! zMTyNnU*NpN$(r>wY9-`8JMTJNu<`laSW-JpsGeL;13k-nC{M96mWRJ5um3PZ9IX{L zDu#8?twe=-{N{~Ehaz2zsjbZ$Cjx09j`I8r#;jRqI`wpCC}}>9@0eTH;Jh{I*9GgD z*VQwx+gJRj-R7V(a6WK1HFRHIt&WYliFL0o?Y^u(@6mPyU98Q*O=4OeX9w5y~;|?fTn(7N?qvBn+Dad_)lkLik@}wn2ZhzzVXO-?r zKKlg4@fQYz>FwyT(&sWC;c(31!xu(w{{s2xJD`h4sGOLESQ1s{c9~9nWo{sBE=O)Z zB{y7Y5N=9-xG98_aptBnKgmes_CHWu2x^mzT8Jbk=LelkAWS#AO>sXcx&2oY)XQyI zkZN^)&}sr<3_9{ylcv@|>Egi$sZGrf!uZmJ8EG1N)2I6m6xqDNlY;PFoA0|;-e^zi zYa3y)s5`fWZlV}pro#QP!v7vPI?zQGp!I=Hh^=&6tLb1_!$p2FeHDHCGH3d#$WMB` zx&8*`D_q?(O}%fV^Bv?DkvqQy0j3>e5Ka8|=2Le*%uIgT2?l+b|I^|I{50G=?N|ez zOlW5>iqpo3lmPqFqBqfnMZ&Qwo4Wd)|(SiC% z*BZEw=7Ao5g>6I}mrTDZ?P;ua4}CUy3})@$NgwyNk4U^#^<--3bCJ%Y$tbJcTHId~ zd3P79G@1|P9SsmlEzldE%!NLwp$j5i_d=8`n|>8 z^e-vGHr3(7npump_NG73se`@gLYAeQHz382W zx%>qY`81=0i~^f3(;sZNi4z|ltHSM79hIqYgXu<_?_fO4JV0-x`PQ@vc(tpFX}SwI z(xof7C`HvlQ@AZRN5wVCNaj3PYFV~?dv!_1MrBG@Jar9v+%h?_-!Sz`eA5Zm!hxZx zC&e{li+7~6e-v3VAL+vc&zxz~GpV_=qHafJ_m@7>BRGjSL2ZTu79ECH# z!>E{9NJe_56&fPU1mTm}6mW@-E^Gp;LTQSxB8h)#3+eM=9rYGt2%C6gn#LL1X*heg ziM~{Xsgm@a_KZTUYR#{)%p|3iWzjR=;FHV8Dp{z*JZ^nMcWbG;ycBk4I22dJ+}bkt z3Z}3d&vTwZtOEm-6=W``igaE_S+x@FUU_ts6`$tQnbhOa3zCD8&P#FQv}eusnrjuk)EDq~4%l@v(5&=$v`&3X+H&sjBF3X;A-cl2{2ZS-pbX&NxH(c{SD98cRUz{)+JiI=(?|3p${53AHT zyzrXxBPnDpy|V3Xe$5W1t~k;uCqx7FmFcfhPST8tKE@$tyIpW)EV<}N%^a$AZX{bVHG9;pP(4#;P_xeg(TB$Nb9&8jDVr1(*@@pL$Z9ab|#CQ^T z_;QPQ76d7Y49(Q4fAQr6$^%L^9v+^o{OnB+WenX>C_xgB$f&UmOWX93BRqL5&bhpShrC~K?^vEMe>papB3z*^>>GK{$f=*xNHh9<| zGlh9MNzXc#+`UUbtNv0%RHr72`Q08vaUr<|pOm3MzqQYaDD3ZBF&7h7$O1eie z%EHB-=faIRN|3VU%EzuM?w@XF(6MZ#U@#&1Z8O>e%s`S+ENDm!LM7allfSE}r*F&4 z8c7nrO6?5KyJiRfWr`y6J1tSI{8;nD4eoNTGp(l6wGz-*&a_hf@b&t4U5Jr{oVO}n-m|^;Tva(im$>Gl z8OeF&yg=_|%z&0Vtu4E1iwhZ^h~@K&YO4NC;|3uFE$U7x<(DX`AFdF9IR#j)k~g+L z(&c}kavI9ZkshA(@IF=S-fbdY`lqHLc&*|^`MSQc>ad#(?P?mQu_rY&DRJ4fkExQU zPAlgX=^9e><^rHMfA6)e|NP_O!<#pb3nk0dVOa`gSq@tnfC?j3`8{(^}zn8lu~w#Wdefg%2%CEN`$AkuTA7*mo(Q32Q+dG)Z?>bvK>)R;K2uog2)oU$N=t zDZe;Gsrij$0dX^e``iaEv!8sASPyCSDvqB?E7VNFolzb6$ro33U&)f_a+XBTZaMS> z`G|b^0QEzAN*%)V$bX9Pcj^d!>d?kW=f?rI9MT5KqhjDl*Y$v8$-Uloz}rkobRE?l zu$9Qog`s9DmY{Tg7FD@KmeOkL%X>tkA(C34&pTZuHS~Fe+J8q1kuSeszR%+OV%)hO z@=DX5PCJn@Uh*?Z%;GWc>(;n48 z9_joVx!ZCmW&(^?v|pC~$Cg9m4CW=1(9OVG4w>a&=Z9dn9GWQCu9tz4)2glaH(N=% zf`K!vs`;(g-e9_eHQS1Gj+Oh1{M&NqRO3Np?}^;0O^_{zPBW-Y{NHj&H=1!>B>!D*s-m&_ z@~z>dFui$mu`zEmtpNXzGNhB#-_edTDqL#lbgve+3Z)H#M_H7FGB@)1sD`}EYM|7i zn9)*0j0O861Dfw@a;F6 z;aOHIaL954SsCs|x_-@?N_>6)nl2tWj5fNop+?C zzf1<8_7LRvTfwp(|6b;pUjfcLRZr4KJiz2gJxNY4lG@2cc;3T0Rd-FM`X#0pv~TV2 zN#re?409{DY&4n+oVS;K7G%GObtfYn_=Gcu z$v@7d{2VeMM?b5khlPn;Izd-EhB&A=szD7BY2Ngdq=n?zH{YDnQqQhSO+sqkBekbPU0xy zY7m}xi}#+Q2%t5nsU|L#g`Sg{UzlP%d^0F2;pzS4{Sq@tn8z*3Ak7Q`iI&%knKh#W z9-?XP{%7i4-bt^3e=`dtnd?d^Hb2D8(OVK5AtKhe68~hXcdDJwF+ZMpHrX=SNqz}0 zEqs-nt-#QP?^;paki(9Gq=XMs^3>2gu7p+5_IA&-^D}ezw8=Zd!CP>W%&ap3KvZSh zRK$mGQRIeW8|?gPCb>F?o{0{X5B*Z5kwU-M5#}zRNrcT_egZ>5&2qgOsOguf*yD5aP#*oiE-e4G}$R;jA z&dezPz5|7~tBkA%Lo&Q*>z$Cw+#D8WSn$&uN!Slf1Kxyo2R4 zH$g%Lx|6)-=vDay&%5UTQD?|(9X%-T*4~(HpU-&BmHB^x> z%jMJP<$ONz-{fQxV-X&yS0)e6Q<_ty8_Bx_GdU#C#Lnc?*=whllgqbNkdO3=S51{y zxYrbSx4xS?RIm=Sc>`DY^54>2mLgfAG>wFJ&_c|>#bn#BhiqJHA7EeYCU#LLPuk1s zpjdVx%>K0$2gSHjgD@NXHgDSN#(h{r)__3cHD0#1(S6v74)X(V%JevW>A-D#6PpSZ z%A5cNm(v?&aY9O2K<==#JUo}nC6b3 zOSDGr?8d>=*uTiL8R|R#!Qg0dcPf;+XpaM_pV!ip)N}eWY@anve98O$YBfvh-hHEZ zoXJF1U5VsFnIwf2{VvSm46(~8lB>%|)86z?i6nE0h+(+SS0T#H6^vrz)Z8I+3V!`; zcs$(vp5c%Z!!MS3Os8e7*iZ*L)sG0KbuwkLg7R=VYHQG? zlA?${)!sX<$pHhO-G}hGNK@@};q=L8lG4`clLvm_m)`OggIqlQD=4FG&)hNnEn-2k zLd1wCHK;XBjy(8;GqiPP`6rjr%uX5@>qxdeDXbXDvqmpD$;ouep82vlfR2R z))Kv7W_e|DU*sqFRy-7sWo}D!U>ChuDPe0R1}rAY%E;GxyThCDWQIX zj8E>WJx<~kldG*Q$7Y(KpQkopscpC?SVpPa^9gVAlKB?#=1gs_rAn2*T!D%g-<4HQ zn!c}^yp@uz-)gPNo^C`blzK=#S(coT;q}!T8g|P0d5@&IVgY0q)i)&bN70o}jvvgio|Iz4Y z8rkP8XO}t=6andX@%z>12{LGQS<>J6m1#h;rD7#{5yU9@GrM!$uMT^W_9Fsu_Od!;5lePEimnn~n~@ zM+zSFM_!Jc$1{I|d4|V&Moz2)-^=M=4D%rTi<*54H{ucFGRD48;f+YJV--%GVYxHsMTTT>y^s25T&8yp)Z+RcqkW^*I4-fziR zD4Uj_oV%fX>JgJ1HMvH~^#{{G*l&{ijCu+-u-2YtX7JwDq2C|k?>77epPsYf8#){& zP9`@4ru}Jud&}$6o5axKpvN=n&D;mdKgy{z_RZkcDVPgu%EkJ8NJHx^@0Cko|McR< zQM@?lVM(2()$J?~kw6}UKTy6?K^j|dlyt7Ysf_=;OrO~=!%j?)9w^_;i-aEGg-=m| z7`0?!|GUL>GN##-;P{@r`ejALsRXK?rG_^s=>2>F-yCwkU;c!JZ=wUAUB2GEJWR0J z-D-o@AMwt`C80(OUoXJBTGkTpy&M)0zpwPZ*XZqB*RpFm(#{oSD6Ejsc}lH1L>)|~ zd#N;Yy_x0nc~8ONTrJ@XC3Gd83NM}(FJ4V!75|iC9C+8toj%RIyZjeG>DQivHT*gr zOn(A-=$1!}a8Y|~N%?yKf8Dk)>6>8h={27p>&%L~@NWa^69%LQ|Cro<5%wWBj`04Qo0Gj0@Kz#5)$R=1%L?%eY}%5t+-s z?OnE5N6F?pUV;C`D_3_c)h*n)cW*15VM%b6EeUk2Sh6&}ka#(P7~*={_}Ud6E68Kq zkieuA=UUvj$z^U9L-p~MOV>iBP=(xAtm5?TBnuk?cyLEz=^78bb}45S7baG>2TltU zOFfu_i;4EtSRp%O+8J@8J7dMFGqTkY%E`>al`@ZiBR7Y0?KpRiW1dXL^dWZ08p)5_ z1Cf3`b%Z*Wu3YBbs%xU=O5WVK7cX2TQY0bT8OCXKGT~8$3gfEq(dxeaTFmpWN@PjT z)xZAr>G6&mZ&6nz>;KrX;qaI-GSPKZv8;UgzrsRE(?xjeE9WbSPRl-m@Z1|FR^kbNocuf?2CC=};& zHji4ohEp334_9&TC>N~ClUnV1p1XN;u1|h$(>&e&CXcBqujeLTL$igV;U#6t{Z7b$ebHIKoG4jO;~ON?kY4koEj!ZZws5St4G>eswRx)g9)B4V5NDx z@^@R2xv!TiUNQ5PcU>&Ev)Zz^5=I+MHw59b_skN`&_?kl@FR(7PI>ZeTdf$y+7Y&` z7LS6K9UaxxFNp6wW|60PX`A|*HL-76zpQZKC<$OCYdJwC zlV{oPx-tlF?yk)ZUs?F;QNq_v*f1*gno+Tax4uDIy1C?buPk1@85()_>|+0GWTmT| z&k?qKTqyKLe%Ne28!0Cj{*JIb1#c>R3>wB5LFNYGN0#%3QG%-;S_w0o@Cm|87;oup z!e{d?I)8x(Xb*XoznUhjpBQTzhNRymn(q;3HB#eMqr~a8fy%-b;-s?k;%uB?Ec~Pi ze;?sDdEs;KzJ@OgSKHf;u|rmj9kQ@#+hy=dIWo=fuSDB=L>;J%aMb2p9>rD7p34b@j`zI*> z5z^mWQ22{cYP5NR`hs$Jeo3jd8=~;H6*k$vD%zfR7dEv_jTS@0aHy7W^9lC=;j|NU zgmilfioQMEu$r}uMi7<#UgEg#6P&K(of8Lj;PqdP6BiWC9=+`9XAcnWxwwtX=AB%c zes-zNZIg0q-Aib1u~R~!@A7Ta8o{?~3hx|+O!c;&XA*uV;lDgedA&Bfrsxx+7q^lm zW$SEqxg9^0zSrma{8l(Uzt1)F=_SkqgwYPrsCgEBK0O+J8VqlQ=qIW_6$;G>!e?## z1^rBVlrnpLMJ?g)K7(;Ezsz~{Q+U_t;Z;AI3I6~CrRqAberng`jf3+0ef++M-_MNj zyD-mh9QVEWEoXh&?D^Gw-f_mh;yMNca7ynZ{3P&`rJX6e$$OJGt`?m$8tv@8?^EgH z-utw*Zl=6zyooNhNz5kx`M8%)wss(g*NxX_Ehsu}^!P6xon)q6JwUt(h;VE^&9nVU z)5O7oqW4FSn0(O{c(&e70IK2{Yb*q6t`RfeH3pi=f6Y&-{x$$z zWN>!?*$}eVYoR_Mo4@CPZ2pRlww5Zmn-6G)37ZI@e-EJ70_c-4rS&%>fNlVqX~NzD zbcuof0c{0K)3<;wHMlzD;1M93gXaS1Om@31?sgzc@q2(SHt{_MWNCU5d;B(*PXpNy-v_ekw#0l~ z2T&DZ$A)eOvNY`sTwe@aKMbIfpC-lW(Te> z1-P*v^IPa#pgAVB(?9Nqb%AWI{yu=V1KHf4%G}{f6XGHuTQf_5Y`QCfJn913o}sYJ zkM9hit4!GSKsJOMK;I1f{V$-o#^1KU^^ZVbFu0wc^yB;Ill)#~{>fNwFs@&V`>yu` z*)+BX&{IG*fBOS}?*q*XiL>XQ!Wd(qWB~mwkd66+09tseU-B;jU2Q@<0`xfpJs-Fh zpN2Mp!QB-={|eM*aK8wk_kk=WOUwP5z5vLET?b@iz75Fw`z??y+p9pfM6U<_PCng_ zWggH4CbdmKHkO|P*%G}7WZQWeGZq{3-vUiFA$|m8d+HrPHtcVK78uuqKsE<|2C_M* zJj0LWVjvr01JFVf;*1Kve`x`-uKx*S^D<_V&ta>87MT!RfNYQC0@>95K7jrS$fo-u z&|(uJa;BeyM}aJ#MnCPxd?wIE#^2RIHr*S5EDanW8{!_II^*yAf$Jkcw$FJf@OR#1 zzZ@%omY5Jv16hB2fo!hM|BRpRl|a^Y8PHM_;%=a22KpDEYYp^6pydYoWq|t?kZr4P z1JxVXD?W>5d;@*%EI%)wU}Un?jpIUQ;cV5Yh19Mrv>|}L7eKEDkTlt>zu5t_K7e)y z&|m;n7WyG%SK5Z%8$hK+K5lLReLsL+51@G1_qRNNbSJcpPq!~yNcS9DXh8r;Z^+_a z4WQ^)AJ-Z{x{=lT+ZjONaXzjgfI0){{s8)I0LgTZjiok#76i~k0W^voAJ0zBVyK<{ zear(3Lh(`U@5mWO57qJ*KfGCM@GRiTV(R(o$-}4(?asr93*yvVHq;t0($dRfZUZCz zz%1r(l;rwZ0H$YRE=EeS3m8FdJZ+0sFS(H% z-k-&EBo`rWZNHasFPoNDLJOc61PNht^hP6-4(*QT`jONwdP*+lD`0v9OdHXzT+xwe zEzkAyP5j)Shxs0u%1`C``7xNDGki=N6740*Gfd=_f|%8-4rVcn5a(YX3dQL?JwJ%j zRoFEFh5(^HVjhI~tsh~e6C0<;%VG|ISwl}HOyMY&s&1vn`mKTnzyCf+NR`Nas#^Ld!x z^Ob8qZt3#2W$oCA3$>Z8ICZH@7blitC3Uf`!Pe#4ScFcrd!NRqbur+w6-!qxVbdB6;3?O%bpoWTeBCb26^u@x8FnAq>@NG{{P?xn^~vX==jRxT=E#TKv< z3biGcb|ko@d+Dk+FHcwj{6d?ZMjfG|@sWQAx=i!t+!JMN2hMF9?HY421HosABcS^X z?+d0md*P}Z+m~LOw6<|)U?`WIi;eJpi7{_W{aC}e^=*q5wzscX+HOB}+j($3x`}*^ zD!>vh`)#VzM3=q3d5vz$d57|6cC}%aYb0nnbKM?Qpf{F28lt?Y-_Z;4^mG{SR(&58yScJF*`(OnpuY zXgK72U12jam*(i-J@3^zWib3q5iX;O1Jltkgf{N2uO%xw7B7d1MGC)GxD9?a8U-Fj zXVB&_%G{m|h{NZyg)2M!?;P96ro=N<`$?~6@~kkoh#)3mICg1b#i}*Q1U8gSD-6tC zX6;>`J^KCf)m2lfQt@yi@GU&$?J|ureudNg{9W-`IHsgu6iH^4!Cerd<^=yCr zf(ii6?$^ir8;&tvu$i^xkisP2=-#3wEe2A$>!Qw#>MecRi$_(k8@o>RQx!#jeXU-* z>aPs-Z+QsSJAFAbreOKSXgd0KuF&(6dgJ`^R`j3aT=>4%?TDu5pj+gt_VqVaHYzN} zRr*nZlFFYlulSUC@?q^FIQCqd=dJ_aayS0a5T_L76)k~ZUo9{{jN%HypkAjiO4|^{ z&(HApuBHn)@LG;H&);pE0euC;VdoTQp%hl^&PO@4wHRAI-8v_=x#s7QOMX7-DF>uoarUR&~I<5Tb8OHTaZg=PcL26j*)(x z0PggX{^^E3=+YMtd{*j@&L9S%h&&*#67{HVsIV+`{n&!8gURPP7KE;>JS$ca1g%CtR<|YI9qSfS z+R9jG$n(E9H4si;Ek2rG9`=LqE}p{VP*!)s<%dtOg~-wS^zCktp@3 zB5J6=mKCyIOZ0NqRQA`J#@=5$-{KSYwOp@Vwd)J|YgbxKga#!fs=*36 z5I|1^P;UV33?Kyb38Mq?Q&86B9)xf8b)^OlLTotKjqnvJbpK2cKW(y>#b?(uDasl z)PbU{bw{~PwN4$!-b$Q}wMGlKg}@v!s4s~wbLz%d_42>naB6>@VQ0SAxb