--!strict
--!optimize 2
--!native

local ffi = zune.ffi;

local raylib = require("./raylib");

local structs = raylib.structs;

local void = ffi.types.void;
local int = ffi.types.i32;
local bool = ffi.types.u8;
local float = ffi.types.float;
local cstring = ffi.types.pointer;
type int = number;
type uint = number;
type bool = number;
type float = number;
type cstring = string | buffer | FFIPointer;

local Vector2 = structs.Vector2;
local Vector3 = structs.Vector3;
local Matrix = structs.Matrix;
local Color = structs.Color;
local Rectangle = structs.Rectangle;
local Image = structs.Image;
local Texture2D = structs.Texture2D;
local Ray = structs.Ray;
local RayCollision = structs.RayCollision;
local BoundingBox = structs.BoundingBox;
local Mesh = structs.Mesh;
local Material = structs.Material;
local Model = structs.Model;
local ModelAnimation = structs.ModelAnimation;
type Vector2 = raylib.Vector2;
type Vector3 = raylib.Vector3;
type Vector4 = raylib.Vector4;
type Matrix = raylib.Matrix;
type Color = raylib.Color;
type Rectangle = raylib.Rectangle;
type Image = raylib.Image;
type Texture2D = raylib.Texture2D;
type Ray = raylib.Ray;
type RayCollision = raylib.RayCollision;
type BoundingBox = raylib.BoundingBox;
type Mesh = raylib.Mesh;
type Material = raylib.Material;
type Model = raylib.Model;
type ModelAnimation = raylib.ModelAnimation;
type BoneInfo = raylib.BoneInfo;
type Transform = raylib.Transform;

local function fn(returns: any, args: { any })
    return {
        returns = returns,
        args = args,
    };
end

export type Fns = {
    DrawLine3D: (startPos: Vector3, endPos: Vector3, color: Color) -> (),
    DrawPoint3D: (position: Vector3, color: Color) -> (),
    DrawCircle3D: (center: Vector3, radius: float, rotationAxis: Vector3, rotationAngle: float, color: Color) -> (),
    DrawTriangle3D: (v1: Vector3, v2: Vector3, v3: Vector3, color: Color) -> (),
    DrawTriangleStrip3D: (points: FFIPointer, pointCount: int, color: Color) -> (),
    DrawCube: (position: Vector3, width: float, height: float, length: float, color: Color) -> (),
    DrawCubeV: (position: Vector3, size: Vector3, color: Color) -> (),
    DrawCubeWires: (position: Vector3, width: float, height: float, length: float, color: Color) -> (),
    DrawCubeWiresV: (position: Vector3, size: Vector3, color: Color) -> (),
    DrawSphere: (centerPos: Vector3, radius: float, color: Color) -> (),
    DrawSphereEx: (centerPos: Vector3, radius: float, rings: int, slices: int, color: Color) -> (),
    DrawSphereWires: (centerPos: Vector3, radius: float, rings: int, slices: int, color: Color) -> (),
    DrawCylinder: (position: Vector3, radiusTop: float, radiusBottom: float, height: float, slices: int, color: Color) -> (),
    DrawCylinderEx: (startPos: Vector3, endPos: Vector3, startRadius: float, endRadius: float, sides: int, color: Color) -> (),
    DrawCylinderWires: (position: Vector3, radiusTop: float, radiusBottom: float, height: float, slices: int, color: Color) -> (),
    DrawCylinderWiresEx: (startPos: Vector3, endPos: Vector3, startRadius: float, endRadius: float, sides: int, color: Color) -> (),
    DrawCapsule: (startPos: Vector3, endPos: Vector3, radius: float, slices: int, rings: int, color: Color) -> (),
    DrawCapsuleWires: (startPos: Vector3, endPos: Vector3, radius: float, slices: int, rings: int, color: Color) -> (),
    DrawPlane: (centerPos: Vector3, size: Vector2, color: Color) -> (),
    DrawRay: (ray: Ray, color: Color) -> (),
    DrawGrid: (slices: int, spacing: float) -> (),
    LoadModel: (fileName: cstring) -> Model,
    LoadModelFromMesh: (mesh: Mesh) -> Model,
    IsModelValid: (model: Model) -> bool,
    UnloadModel: (model: Model) -> (),
    GetModelBoundingBox: (model: Model) -> BoundingBox,
    DrawModel: (model: Model, position: Vector3, scale: float, tint: Color) -> (),
    DrawModelEx: (model: Model, position: Vector3, rotationAxis: Vector3, rotationAngle: float, scale: Vector3, tint: Color) -> (),
    DrawModelWires: (model: Model, position: Vector3, scale: float, tint: Color) -> (),
    DrawModelWiresEx: (model: Model, position: Vector3, rotationAxis: Vector3, rotationAngle: float, scale: Vector3, tint: Color) -> (),
    DrawModelPoints: (model: Model, position: Vector3, scale: float, tint: Color) -> (),
    DrawModelPointsEx: (model: Model, position: Vector3, rotationAxis: Vector3, rotationAngle: float, scale: Vector3, tint: Color) -> (),
    DrawBoundingBox: (box: BoundingBox, color: Color) -> (),
    DrawBillboard: (camera: FFIPointer, texture: Texture2D, position: Vector3, scale: float, tint: Color) -> (),
    DrawBillboardRec: (camera: FFIPointer, texture: Texture2D, source: Rectangle, position: Vector3, size: Vector2, tint: Color) -> (),
    DrawBillboardPro: (camera: FFIPointer, texture: Texture2D, source: Rectangle, position: Vector3, up: Vector3, size: Vector2, origin: Vector2, rotation: float, tint: Color) -> (),
    UploadMesh: (mesh: FFIPointer, dynamic: bool) -> (),
    UpdateMeshBuffer: (mesh: Mesh, index: int, data: FFIPointer, dataSize: int, offset: int) -> (),
    UnloadMesh: (mesh: Mesh) -> (),
    DrawMesh: (mesh: Mesh, material: Material, transform: Matrix) -> (),
    DrawMeshInstanced: (mesh: Mesh, material: Material, transforms: FFIPointer, instances: int) -> (),
    GetMeshBoundingBox: (mesh: Mesh) -> BoundingBox,
    GenMeshTangents: (mesh: FFIPointer) -> (),
    ExportMesh: (mesh: Mesh, fileName: cstring) -> bool,
    ExportMeshAsCode: (mesh: Mesh, fileName: cstring) -> bool,
    GenMeshPoly: (sides: int, radius: float) -> Mesh,
    GenMeshPlane: (width: float, length: float, resX: int, resZ: int) -> Mesh,
    GenMeshCube: (width: float, height: float, length: float) -> Mesh,
    GenMeshSphere: (radius: float, rings: int, slices: int) -> Mesh,
    GenMeshHemiSphere: (radius: float, rings: int, slices: int) -> Mesh,
    GenMeshCylinder: (radius: float, height: float, slices: int) -> Mesh,
    GenMeshCone: (radius: float, height: float, slices: int) -> Mesh,
    GenMeshTorus: (radius: float, size: float, radSeg: int, sides: int) -> Mesh,
    GenMeshKnot: (radius: float, size: float, radSeg: int, sides: int) -> Mesh,
    GenMeshHeightmap: (heightmap: Image, size: Vector3) -> Mesh,
    GenMeshCubicmap: (cubicmap: Image, cubeSize: Vector3) -> Mesh,
    LoadMaterials: (fileName: cstring, materialCount: FFIPointer) -> FFIPointer,
    LoadMaterialDefault: () -> Material,
    IsMaterialValid: (material: Material) -> bool,
    UnloadMaterial: (material: Material) -> (),
    SetMaterialTexture: (material: FFIPointer, mapType: int, texture: Texture2D) -> (),
    SetModelMeshMaterial: (model: FFIPointer, meshId: int, materialId: int) -> (),
    LoadModelAnimations: (fileName: cstring, animCount: FFIPointer) -> FFIPointer,
    UpdateModelAnimation: (model: Model, anim: ModelAnimation, frame: int) -> (),
    UpdateModelAnimationBones: (model: Model, anim: ModelAnimation, frame: int) -> (),
    UnloadModelAnimation: (anim: ModelAnimation) -> (),
    UnloadModelAnimations: (animations: FFIPointer, animCount: int) -> (),
    IsModelAnimationValid: (model: Model, anim: ModelAnimation) -> bool,
    CheckCollisionSpheres: (center1: Vector3, radius1: float, center2: Vector3, radius2: float) -> bool,
    CheckCollisionBoxes: (box1: BoundingBox, box2: BoundingBox) -> bool,
    CheckCollisionBoxSphere: (box: BoundingBox, center: Vector3, radius: float) -> bool,
    GetRayCollisionSphere: (ray: Ray, center: Vector3, radius: float) -> RayCollision,
    GetRayCollisionBox: (ray: Ray, box: BoundingBox) -> RayCollision,
    GetRayCollisionMesh: (ray: Ray, mesh: Mesh, transform: Matrix) -> RayCollision,
    GetRayCollisionTriangle: (ray: Ray, p1: Vector3, p2: Vector3, p3: Vector3) -> RayCollision,
    GetRayCollisionQuad: (ray: Ray, p1: Vector3, p2: Vector3, p3: Vector3, p4: Vector3) -> RayCollision,
};

return {
    def = {
        -- void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color);
        DrawLine3D = fn(void, { Vector3, Vector3, Color }),
        -- void DrawPoint3D(Vector3 position, Color color);
        DrawPoint3D = fn(void, { Vector3, Color }),
        -- void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color);
        DrawCircle3D = fn(void, { Vector3, float, Vector3, float, Color }),
        -- void DrawTriangle3D(Vector3 v1, Vector3 v2, Vector3 v3, Color color);
        DrawTriangle3D = fn(void, { Vector3, Vector3, Vector3, Color }),
        -- void DrawTriangleStrip3D(const Vector3 *points, int pointCount, Color color);
        DrawTriangleStrip3D = fn(void, { ffi.types.pointer, int, Color }),
        -- void DrawCube(Vector3 position, float width, float height, float length, Color color);
        DrawCube = fn(void, { Vector3, float, float, float, Color }),
        -- void DrawCubeV(Vector3 position, Vector3 size, Color color);
        DrawCubeV = fn(void, { Vector3, Vector3, Color }),
        -- void DrawCubeWires(Vector3 position, float width, float height, float length, Color color);
        DrawCubeWires = fn(void, { Vector3, float, float, float, Color }),
        -- void DrawCubeWiresV(Vector3 position, Vector3 size, Color color);
        DrawCubeWiresV = fn(void, { Vector3, Vector3, Color }),
        -- void DrawSphere(Vector3 centerPos, float radius, Color color);
        DrawSphere = fn(void, { Vector3, float, Color }),
        -- void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color);
        DrawSphereEx = fn(void, { Vector3, float, int, int, Color }),
        -- void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color);
        DrawSphereWires = fn(void, { Vector3, float, int, int, Color }),
        -- void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color);
        DrawCylinder = fn(void, { Vector3, float, float, float, int, Color }),
        -- void DrawCylinderEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color);
        DrawCylinderEx = fn(void, { Vector3, Vector3, float, float, int, Color }),
        -- void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color);
        DrawCylinderWires = fn(void, { Vector3, float, float, float, int, Color }),
        -- void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color);
        DrawCylinderWiresEx = fn(void, { Vector3, Vector3, float, float, int, Color }),
        -- void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color);
        DrawCapsule = fn(void, { Vector3, Vector3, float, int, int, Color }),
        -- void DrawCapsuleWires(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color);
        DrawCapsuleWires = fn(void, { Vector3, Vector3, float, int, int, Color }),
        -- void DrawPlane(Vector3 centerPos, Vector2 size, Color color);
        DrawPlane = fn(void, { Vector3, Vector2, Color }),
        -- void DrawRay(Ray ray, Color color);
        DrawRay = fn(void, { Ray, Color }),
        -- void DrawGrid(int slices, float spacing);
        DrawGrid = fn(void, { int, float }),
        -- Model LoadModel(const char *fileName);
        LoadModel = fn(Model, { cstring }),
        -- Model LoadModelFromMesh(Mesh mesh);
        LoadModelFromMesh = fn(Model, { Mesh }),
        -- bool IsModelValid(Model model);
        IsModelValid = fn(bool, { Model }),
        -- void UnloadModel(Model model);
        UnloadModel = fn(void, { Model }),
        -- BoundingBox GetModelBoundingBox(Model model);
        GetModelBoundingBox = fn(BoundingBox, { Model }),
        -- void DrawModel(Model model, Vector3 position, float scale, Color tint);
        DrawModel = fn(void, { Model, Vector3, float, Color }),
        -- void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint);
        DrawModelEx = fn(void, { Model, Vector3, Vector3, float, Vector3, Color }),
        -- void DrawModelWires(Model model, Vector3 position, float scale, Color tint);
        DrawModelWires = fn(void, { Model, Vector3, float, Color }),
        -- void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint);
        DrawModelWiresEx = fn(void, { Model, Vector3, Vector3, float, Vector3, Color }),
        -- void DrawModelPoints(Model model, Vector3 position, float scale, Color tint);
        DrawModelPoints = fn(void, { Model, Vector3, float, Color }),
        -- void DrawModelPointsEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint);
        DrawModelPointsEx = fn(void, { Model, Vector3, Vector3, float, Vector3, Color }),
        -- void DrawBoundingBox(BoundingBox box, Color color);
        DrawBoundingBox = fn(void, { BoundingBox, Color }),
        -- void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, Color tint);
        DrawBillboard = fn(void, { raylib.ptrs.Camera, Texture2D, Vector3, float, Color }),
        -- void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint);
        DrawBillboardRec = fn(void, { raylib.ptrs.Camera, Texture2D, Rectangle, Vector3, Vector2, Color }),
        -- void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint);
        DrawBillboardPro = fn(void, { raylib.ptrs.Camera, Texture2D, Rectangle, Vector3, Vector3, Vector2, Vector2, float, Color }),
        -- void UploadMesh(Mesh *mesh, bool dynamic);
        UploadMesh = fn(void, { ffi.types.pointer, bool }),
        -- void UpdateMeshBuffer(Mesh mesh, int index, const void *data, int dataSize, int offset);
        UpdateMeshBuffer = fn(void, { Mesh, int, ffi.types.pointer, int, int }),
        -- void UnloadMesh(Mesh mesh);
        UnloadMesh = fn(void, { Mesh }),
        -- void DrawMesh(Mesh mesh, Material material, Matrix transform);
        DrawMesh = fn(void, { Mesh, Material, Matrix }),
        -- void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, int instances);
        DrawMeshInstanced = fn(void, { Mesh, Material, ffi.types.pointer, int }),
        -- BoundingBox GetMeshBoundingBox(Mesh mesh);
        GetMeshBoundingBox = fn(BoundingBox, { Mesh }),
        -- void GenMeshTangents(Mesh *mesh);
        GenMeshTangents = fn(void, { ffi.types.pointer }),
        -- bool ExportMesh(Mesh mesh, const char *fileName);
        ExportMesh = fn(bool, { Mesh, cstring }),
        -- bool ExportMeshAsCode(Mesh mesh, const char *fileName);
        ExportMeshAsCode = fn(bool, { Mesh, cstring }),
        -- Mesh GenMeshPoly(int sides, float radius);
        GenMeshPoly = fn(Mesh, { int, float }),
        -- Mesh GenMeshPlane(float width, float length, int resX, int resZ);
        GenMeshPlane = fn(Mesh, { float, float, int, int }),
        -- Mesh GenMeshCube(float width, float height, float length);
        GenMeshCube = fn(Mesh, { float, float, float }),
        -- Mesh GenMeshSphere(float radius, int rings, int slices);
        GenMeshSphere = fn(Mesh, { float, int, int }),
        -- Mesh GenMeshHemiSphere(float radius, int rings, int slices);
        GenMeshHemiSphere = fn(Mesh, { float, int, int }),
        -- Mesh GenMeshCylinder(float radius, float height, int slices);
        GenMeshCylinder = fn(Mesh, { float, float, int }),
        -- Mesh GenMeshCone(float radius, float height, int slices);
        GenMeshCone = fn(Mesh, { float, float, int }),
        -- Mesh GenMeshTorus(float radius, float size, int radSeg, int sides);
        GenMeshTorus = fn(Mesh, { float, float, int, int }),
        -- Mesh GenMeshKnot(float radius, float size, int radSeg, int sides);
        GenMeshKnot = fn(Mesh, { float, float, int, int }),
        -- Mesh GenMeshHeightmap(Image heightmap, Vector3 size);
        GenMeshHeightmap = fn(Mesh, { Image, Vector3 }),
        -- Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize);
        GenMeshCubicmap = fn(Mesh, { Image, Vector3 }),
        -- Material *LoadMaterials(const char *fileName, int *materialCount);
        LoadMaterials = fn(ffi.types.pointer, { cstring, ffi.types.pointer }),
        -- Material LoadMaterialDefault(void);
        LoadMaterialDefault = fn(Material, {}),
        -- bool IsMaterialValid(Material material);
        IsMaterialValid = fn(bool, { Material }),
        -- void UnloadMaterial(Material material);
        UnloadMaterial = fn(void, { Material }),
        -- void SetMaterialTexture(Material *material, int mapType, Texture2D texture);
        SetMaterialTexture = fn(void, { ffi.types.pointer, int, Texture2D }),
        -- void SetModelMeshMaterial(Model *model, int meshId, int materialId);
        SetModelMeshMaterial = fn(void, { ffi.types.pointer, int, int }),
        -- ModelAnimation *LoadModelAnimations(const char *fileName, int *animCount);
        LoadModelAnimations = fn(ffi.types.pointer, { cstring, ffi.types.pointer }),
        -- void UpdateModelAnimation(Model model, ModelAnimation anim, int frame);
        UpdateModelAnimation = fn(void, { Model, ModelAnimation, int }),
        -- void UpdateModelAnimationBones(Model model, ModelAnimation anim, int frame);
        UpdateModelAnimationBones = fn(void, { Model, ModelAnimation, int }),
        -- void UnloadModelAnimation(ModelAnimation anim);
        UnloadModelAnimation = fn(void, { ModelAnimation }),
        -- void UnloadModelAnimations(ModelAnimation *animations, int animCount);
        UnloadModelAnimations = fn(void, { ffi.types.pointer, int }),
        -- bool IsModelAnimationValid(Model model, ModelAnimation anim);
        IsModelAnimationValid = fn(bool, { Model, ModelAnimation }),
        -- bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2);
        CheckCollisionSpheres = fn(bool, { Vector3, float, Vector3, float }),
        -- bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2);
        CheckCollisionBoxes = fn(bool, { BoundingBox, BoundingBox }),
        -- bool CheckCollisionBoxSphere(BoundingBox box, Vector3 center, float radius);
        CheckCollisionBoxSphere = fn(bool, { BoundingBox, Vector3, float }),
        -- RayCollision GetRayCollisionSphere(Ray ray, Vector3 center, float radius);
        GetRayCollisionSphere = fn(RayCollision, { Ray, Vector3, float }),
        -- RayCollision GetRayCollisionBox(Ray ray, BoundingBox box);
        GetRayCollisionBox = fn(RayCollision, { Ray, BoundingBox }),
        -- RayCollision GetRayCollisionMesh(Ray ray, Mesh mesh, Matrix transform);
        GetRayCollisionMesh = fn(RayCollision, { Ray, Mesh, Matrix }),
        -- RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3);
        GetRayCollisionTriangle = fn(RayCollision, { Ray, Vector3, Vector3, Vector3 }),
        -- RayCollision GetRayCollisionQuad(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4);
        GetRayCollisionQuad = fn(RayCollision, { Ray, Vector3, Vector3, Vector3, Vector3 }),
    }
}


--!strict
--!optimize 2
--!native

local ffi = zune.ffi;

local int = ffi.types.i32;
local uint = ffi.types.u32;
local bool = ffi.types.u8;
local float = ffi.types.float;

local Vector2 = ffi.types.vector2_32;
export type Vector2 = vector;

local Vector3 = ffi.types.vector3_32;
export type Vector3 = vector;

local Vector4 = ffi.struct({
    { x = float },
    { y = float },
    { z = float },
    { w = float },
});
export type Vector4 = typeof(Vector4:new({}))

local Quaternion = Vector4;
export type Quaternion = typeof(Quaternion:new({}))

local Matrix = ffi.struct({
    { m0 = float }, { m4 = float }, { m8 = float }, { m12 = float },
    { m1 = float }, { m5 = float }, { m9 = float }, { m13 = float },
    { m2 = float }, { m6 = float }, { m10 = float }, { m14 = float },
    { m3 = float }, { m7 = float }, { m11 = float }, { m15 = float },
});
export type Matrix = typeof(Matrix:new({}))

local Color = ffi.struct({
    { r = ffi.types.u8 },
    { g = ffi.types.u8 },
    { b = ffi.types.u8 },
    { a = ffi.types.u8 },
});
export type Color = typeof(Color:new({}))

local Rectangle = ffi.struct({
    { x = float },
    { y = float },
    { width = float },
    { height = float },
});
export type Rectangle = typeof(Rectangle:new({}))

local Image = ffi.struct({
    { data = ffi.types.pointer },
    { width = int },
    { height = int },
    { mipmaps = int },
    { format = int },
});
export type Image = typeof(Image:new({}))

local Texture = ffi.struct({
    { id = uint },
    { width = int },
    { height = int },
    { mipmaps = int },
    { format = int },
});
export type Texture = typeof(Texture:new({}))

local Texture2D = Texture;
export type Texture2D = typeof(Texture2D:new({}))

local TextureCubemap = Texture;
export type TextureCubemap = typeof(TextureCubemap:new({}))

local RenderTexture = ffi.struct({
    { id = uint },
    { texture = Texture },
    { depth = Texture },
});
export type RenderTexture = typeof(RenderTexture:new({}))

local RenderTexture2D = RenderTexture;
export type RenderTexture2D = typeof(RenderTexture2D:new({}))

local NPatchInfo = ffi.struct({
    { source = Rectangle },
    { left = int },
    { top = int },
    { right = int },
    { bottom = int },
    { layout = int },
});
export type NPatchInfo = typeof(NPatchInfo:new({}))

local GlyphInfo = ffi.struct({
    { value = int },
    { offsetX = int },
    { offsetY = int },
    { advanceX = int },
    { image = Image },
});
export type GlyphInfo = typeof(GlyphInfo:new({}))

local Font = ffi.struct({
    { baseSize = int },
    { glyphCount = int },
    { glyphPadding = int },
    { texture = Texture2D },
    { recs = ffi.types.pointer },
    { glyphs = ffi.types.pointer },
});
export type Font = typeof(Font:new({}))

local Camera3D = ffi.struct({
    { position = Vector3 },
    { target = Vector3 },
    { up = Vector3 },
    { fovy = float },
    { projection = int },
});
export type Camera3D = typeof(Camera3D:new({}))

local Camera = Camera3D;

local Camera2D = ffi.struct({
    { offset = Vector2 },
    { target = Vector2 },
    { rotation = float },
    { zoom = float },
});
export type Camera2D = typeof(Camera2D:new({}))

local Mesh = ffi.struct({
    { vertexCount = int },
    { triangleCount = int },
    { vertices = ffi.types.pointer },
    { texcoords = ffi.types.pointer },
    { texcoords2 = ffi.types.pointer },
    { normals = ffi.types.pointer },
    { tangents = ffi.types.pointer },
    { colors = ffi.types.pointer },
    { indices = ffi.types.pointer },
    { animVertices = ffi.types.pointer },
    { animNormals = ffi.types.pointer },
    { boneIds = ffi.types.pointer },
    { boneWeights = ffi.types.pointer },
    { vaoId = uint },
    { vboId = ffi.types.pointer },
});
export type Mesh = typeof(Mesh:new({}))

local Shader = ffi.struct({
    { id = uint },
    { locs = ffi.types.pointer },
});
export type Shader = typeof(Shader:new({}))

local MaterialMap = ffi.struct({
    { texture = Texture2D },
    { color = Color },
    { value = float },
});
export type MaterialMap = typeof(MaterialMap:new({}))

local float2 = ffi.struct({{_1 = float}, {_2 = float}});
local float4 = ffi.struct({{_1 = float}, {_2 = float}, {_3 = float}, {_4 = float}});

local Material = ffi.struct({
    { shader = Shader },
    { maps = ffi.types.pointer },
    { params = float4},
});
export type Material = typeof(Material:new({}))

local Transform = ffi.struct({
    { translation = Vector3 },
    { rotation = Quaternion },
    { scale = Vector3 },
});
export type Transform = typeof(Transform:new({}))

local BoneInfo = ffi.struct({
    { name = ffi.types.u8:array(32) },
    { parent = int },
});
export type BoneInfo = typeof(BoneInfo:new({}))

local Model = ffi.struct({
    { transform = Matrix },
    { meshCount = int },
    { materialCount = int },
    { meshes = ffi.types.pointer },
    { materials = ffi.types.pointer },
    { meshMaterial = ffi.types.pointer },
    { boneCount = int },
    { bones = ffi.types.pointer },
    { bindPose = ffi.types.pointer },
});
export type Model = typeof(Model:new({}))

local ModelAnimation = ffi.struct({
    { boneCount = int },
    { frameCount = int },
    { bones = ffi.types.pointer },
    { framePoses = ffi.types.pointer },
    { name = ffi.types.u8:array(32) },
});
export type ModelAnimation = typeof(ModelAnimation:new({}))

local Ray = ffi.struct({
    { position = Vector3 },
    { direction = Vector3 },
});
export type Ray = typeof(Ray:new({}))

local RayCollision = ffi.struct({
    { hit = bool },
    { distance = float },
    { point = Vector3 },
    { normal = Vector3 },
});
export type RayCollision = typeof(RayCollision:new({}))

local BoundingBox = ffi.struct({
    { min = Vector3 },
    { max = Vector3 },
});
export type BoundingBox = typeof(BoundingBox:new({}))

local Wave = ffi.struct({
    { frameCount = uint },
    { sampleRate = uint },
    { sampleSize = uint },
    { channels = uint },
    { data = ffi.types.pointer },
});
export type Wave = typeof(Wave:new({}))

local rAudioBuffer = ffi.struct({}); -- opaque
export type rAudioBuffer = typeof(rAudioBuffer:new({}))
local rAudioProcessor = ffi.struct({}); -- opaque
export type rAudioProcessor = typeof(rAudioProcessor:new({}))

local AudioStream = ffi.struct({
    { buffer = ffi.types.pointer },
    { processor = ffi.types.pointer },
    { sampleRate = uint },
    { sampleSize = uint },
    { channels = uint },
});
export type AudioStream = typeof(AudioStream:new({}))

local Sound = ffi.struct({
    { stream = AudioStream },
    { frameCount = uint },
});
export type Sound = typeof(Sound:new({}))

local Music = ffi.struct({
    { stream = AudioStream },
    { frameCount = uint },
    { looping = bool },
    { ctxType = int },
    { ctxData = ffi.types.pointer },
});
export type Music = typeof(Music:new({}))

local VrDeviceInfo = ffi.struct({
    { hResolution = int },
    { vResolution = int },
    { hScreenSize = float },
    { vScreenSize = float },
    { eyeToScreenDistance = float },
    { lensSeparationDistance = float },
    { interpupillaryDistance = float },
    { lensDistortionValues = float4 },
    { chromaAbCorrection = float4 },
});
export type VrDeviceInfo = typeof(VrDeviceInfo:new({}))

local VrStereoConfig = ffi.struct({
    { projection = ffi.struct({{_1 = Matrix}, {_2 = Matrix}}) },
    { viewOffset = ffi.struct({{_1 = Matrix}, {_2 = Matrix}}) },
    { leftLensCenter = float2 },
    { rightLensCenter = float2 },
    { leftScreenCenter = float2 },
    { rightScreenCenter = float2 },
    { scale = float2 },
    { scaleIn = float2 },
});
export type VrStereoConfig = typeof(VrStereoConfig:new({}))

local FilePathList = ffi.struct({
    { capacity = uint },
    { count = uint },
    { paths = ffi.types.pointer },
});
export type FilePathList = typeof(FilePathList:new({}))

local AutomationEvent = ffi.struct({
    { frame = uint },
    { type = uint },
    { params = ffi.struct({{_1 = int}, {_2 = int}, {_3 = int}, {_4 = int}}) },
});
export type AutomationEvent = typeof(AutomationEvent:new({}))

local AutomationEventList = ffi.struct({
    { capacity = uint },
    { count = uint },
    { events = ffi.types.pointer },
});
export type AutomationEventList = typeof(AutomationEventList:new({}))

local export = {
    structs = {
        Vector2 = Vector2,
        Vector3 = Vector3,
        Vector4 = Vector4,
        Quaternion = Quaternion,
        Matrix = Matrix,
        Color = Color,
        Rectangle = Rectangle,
        Image = Image,
        Texture = Texture,
        Texture2D = Texture2D,
        TextureCubemap = TextureCubemap,
        RenderTexture = RenderTexture,
        RenderTexture2D = RenderTexture2D,
        NPatchInfo = NPatchInfo,
        GlyphInfo = GlyphInfo,
        Font = Font,
        Camera3D = Camera3D,
        Camera = Camera,
        Camera2D = Camera2D,
        Mesh = Mesh,
        Shader = Shader,
        MaterialMap = MaterialMap,
        Material = Material,
        Transform = Transform,
        BoneInfo = BoneInfo,
        Model = Model,
        ModelAnimation = ModelAnimation,
        Ray = Ray,
        RayCollision = RayCollision,
        BoundingBox = BoundingBox,
        Wave = Wave,
        rAudioBuffer = rAudioBuffer,
        rAudioProcessor = rAudioProcessor,
        AudioStream = AudioStream,
        Sound = Sound,
        Music = Music,
        VrDeviceInfo = VrDeviceInfo,
        VrStereoConfig = VrStereoConfig,
        FilePathList = FilePathList,
        AutomationEvent = AutomationEvent,
        AutomationEventList = AutomationEventList,
    },
    ptrs = {
        Camera = ffi.types.pointer:newTag("Camera"),
    },

    LIGHTGRAY = Color:new{ r = 200, g = 200, b = 200, a = 255 },
    GRAY = Color:new{ r = 130, g = 130, b = 130, a = 255 },
    DARKGRAY = Color:new{ r = 80, g = 80, b = 80, a = 255 },
    YELLOW = Color:new{ r = 253, g = 249, b = 0, a = 255 },
    GOLD = Color:new{ r = 255, g = 203, b = 0, a = 255 },
    ORANGE = Color:new{ r = 255, g = 161, b = 0, a = 255 },
    PINK = Color:new{ r = 255, g = 109, b = 194, a = 255 },
    RED = Color:new{ r = 230, g = 41, b = 55, a = 255 },
    MAROON = Color:new{ r = 190, g = 33, b = 55, a = 255 },
    GREEN = Color:new{ r = 0, g = 228, b = 48, a = 255 },
    LIME = Color:new{ r = 0, g = 158, b = 47, a = 255 },
    DARKGREEN = Color:new{ r = 0, g = 117, b = 44, a = 255 },
    SKYBLUE = Color:new{ r = 102, g = 191, b = 255, a = 255 },
    BLUE = Color:new{ r = 0, g = 121, b = 241, a = 255 },
    DARKBLUE = Color:new{ r = 0, g = 82, b = 172, a = 255 },
    PURPLE = Color:new{ r = 200, g = 122, b = 255, a = 255 },
    VIOLET = Color:new{ r = 135, g = 60, b = 190, a = 255 },
    DARKPURPLE = Color:new{ r = 112, g = 31, b = 126, a = 255 },
    BEIGE = Color:new{ r = 211, g = 176, b = 131, a = 255 },
    BROWN = Color:new{ r = 127, g = 106, b = 79, a = 255 },
    DARKBROWN = Color:new{ r = 76, g = 63, b = 47, a = 255 },

    WHITE = Color:new{ r = 255, g = 255, b = 255, a = 255 },
    BLACK = Color:new{ r = 0, g = 0, b = 0, a = 255 },
    BLANK = Color:new{ r = 0, g = 0, b = 0, a = 0 },
    MAGENTA = Color:new{ r = 255, g = 0, b = 255, a = 255 },
    RAYWHITE = Color:new{ r = 245, g = 245, b = 245, a = 255 },

    ConfigFlags = {
        FLAG_VSYNC_HINT         = 0x00000040,   -- Set to try enabling V-Sync on GPU
        FLAG_FULLSCREEN_MODE    = 0x00000002,   -- Set to run program in fullscreen
        FLAG_WINDOW_RESIZABLE   = 0x00000004,   -- Set to allow resizable window
        FLAG_WINDOW_UNDECORATED = 0x00000008,   -- Set to disable window decoration (frame and buttons)
        FLAG_WINDOW_HIDDEN      = 0x00000080,   -- Set to hide window
        FLAG_WINDOW_MINIMIZED   = 0x00000200,   -- Set to minimize window (iconify)
        FLAG_WINDOW_MAXIMIZED   = 0x00000400,   -- Set to maximize window (expanded to monitor)
        FLAG_WINDOW_UNFOCUSED   = 0x00000800,   -- Set to window non focused
        FLAG_WINDOW_TOPMOST     = 0x00001000,   -- Set to window always on top
        FLAG_WINDOW_ALWAYS_RUN  = 0x00000100,   -- Set to allow windows running while minimized
        FLAG_WINDOW_TRANSPARENT = 0x00000010,   -- Set to allow transparent framebuffer
        FLAG_WINDOW_HIGHDPI     = 0x00002000,   -- Set to support HighDPI
        FLAG_WINDOW_MOUSE_PASSTHROUGH = 0x00004000, -- Set to support mouse passthrough, only supported when FLAG_WINDOW_UNDECORATED
        FLAG_BORDERLESS_WINDOWED_MODE = 0x00008000, -- Set to run program in borderless windowed mode
        FLAG_MSAA_4X_HINT       = 0x00000020,   -- Set to try enabling MSAA 4X
        FLAG_INTERLACED_HINT    = 0x00010000    -- Set to try enabling interlaced video format (for V3D)
    },

    TraceLogLevel = {
        LOG_ALL = 0,        -- Display all logs
        LOG_TRACE = 1,      -- Trace logging, intended for internal use only
        LOG_DEBUG = 2,      -- Debug logging, used for internal debugging, it should be disabled on release builds
        LOG_INFO = 3,       -- Info logging, used for program execution info
        LOG_WARNING = 4,    -- Warning logging, used on recoverable failures
        LOG_ERROR = 5,      -- Error logging, used on unrecoverable failures
        LOG_FATAL = 6,      -- Fatal logging, used to abort program: exit(EXIT_FAILURE)
        LOG_NONE = 7        -- Disable logging
    },

    KeyboardKey = {
        KEY_NULL            = 0,        -- Key: NULL, used for no key pressed
        -- Alphanumeric keys
        KEY_APOSTROPHE      = 39,       -- Key: '
        KEY_COMMA           = 44,       -- Key: ,
        KEY_MINUS           = 45,       -- Key: -
        KEY_PERIOD          = 46,       -- Key: .
        KEY_SLASH           = 47,       -- Key: /
        KEY_ZERO            = 48,       -- Key: 0
        KEY_ONE             = 49,       -- Key: 1
        KEY_TWO             = 50,       -- Key: 2
        KEY_THREE           = 51,       -- Key: 3
        KEY_FOUR            = 52,       -- Key: 4
        KEY_FIVE            = 53,       -- Key: 5
        KEY_SIX             = 54,       -- Key: 6
        KEY_SEVEN           = 55,       -- Key: 7
        KEY_EIGHT           = 56,       -- Key: 8
        KEY_NINE            = 57,       -- Key: 9
        KEY_SEMICOLON       = 59,       -- Key: ;
        KEY_EQUAL           = 61,       -- Key: =
        KEY_A               = 65,       -- Key: A | a
        KEY_B               = 66,       -- Key: B | b
        KEY_C               = 67,       -- Key: C | c
        KEY_D               = 68,       -- Key: D | d
        KEY_E               = 69,       -- Key: E | e
        KEY_F               = 70,       -- Key: F | f
        KEY_G               = 71,       -- Key: G | g
        KEY_H               = 72,       -- Key: H | h
        KEY_I               = 73,       -- Key: I | i
        KEY_J               = 74,       -- Key: J | j
        KEY_K               = 75,       -- Key: K | k
        KEY_L               = 76,       -- Key: L | l
        KEY_M               = 77,       -- Key: M | m
        KEY_N               = 78,       -- Key: N | n
        KEY_O               = 79,       -- Key: O | o
        KEY_P               = 80,       -- Key: P | p
        KEY_Q               = 81,       -- Key: Q | q
        KEY_R               = 82,       -- Key: R | r
        KEY_S               = 83,       -- Key: S | s
        KEY_T               = 84,       -- Key: T | t
        KEY_U               = 85,       -- Key: U | u
        KEY_V               = 86,       -- Key: V | v
        KEY_W               = 87,       -- Key: W | w
        KEY_X               = 88,       -- Key: X | x
        KEY_Y               = 89,       -- Key: Y | y
        KEY_Z               = 90,       -- Key: Z | z
        KEY_LEFT_BRACKET    = 91,       -- Key: [
        KEY_BACKSLASH       = 92,       -- Key: '\'
        KEY_RIGHT_BRACKET   = 93,       -- Key: ]
        KEY_GRAVE           = 96,       -- Key: `
        -- Function keys
        KEY_SPACE           = 32,       -- Key: Space
        KEY_ESCAPE          = 256,      -- Key: Esc
        KEY_ENTER           = 257,      -- Key: Enter
        KEY_TAB             = 258,      -- Key: Tab
        KEY_BACKSPACE       = 259,      -- Key: Backspace
        KEY_INSERT          = 260,      -- Key: Ins
        KEY_DELETE          = 261,      -- Key: Del
        KEY_RIGHT           = 262,      -- Key: Cursor right
        KEY_LEFT            = 263,      -- Key: Cursor left
        KEY_DOWN            = 264,      -- Key: Cursor down
        KEY_UP              = 265,      -- Key: Cursor up
        KEY_PAGE_UP         = 266,      -- Key: Page up
        KEY_PAGE_DOWN       = 267,      -- Key: Page down
        KEY_HOME            = 268,      -- Key: Home
        KEY_END             = 269,      -- Key: End
        KEY_CAPS_LOCK       = 280,      -- Key: Caps lock
        KEY_SCROLL_LOCK     = 281,      -- Key: Scroll down
        KEY_NUM_LOCK        = 282,      -- Key: Num lock
        KEY_PRINT_SCREEN    = 283,      -- Key: Print screen
        KEY_PAUSE           = 284,      -- Key: Pause
        KEY_F1              = 290,      -- Key: F1
        KEY_F2              = 291,      -- Key: F2
        KEY_F3              = 292,      -- Key: F3
        KEY_F4              = 293,      -- Key: F4
        KEY_F5              = 294,      -- Key: F5
        KEY_F6              = 295,      -- Key: F6
        KEY_F7              = 296,      -- Key: F7
        KEY_F8              = 297,      -- Key: F8
        KEY_F9              = 298,      -- Key: F9
        KEY_F10             = 299,      -- Key: F10
        KEY_F11             = 300,      -- Key: F11
        KEY_F12             = 301,      -- Key: F12
        KEY_LEFT_SHIFT      = 340,      -- Key: Shift left
        KEY_LEFT_CONTROL    = 341,      -- Key: Control left
        KEY_LEFT_ALT        = 342,      -- Key: Alt left
        KEY_LEFT_SUPER      = 343,      -- Key: Super left
        KEY_RIGHT_SHIFT     = 344,      -- Key: Shift right
        KEY_RIGHT_CONTROL   = 345,      -- Key: Control right
        KEY_RIGHT_ALT       = 346,      -- Key: Alt right
        KEY_RIGHT_SUPER     = 347,      -- Key: Super right
        KEY_KB_MENU         = 348,      -- Key: KB menu
        -- Keypad keys
        KEY_KP_0            = 320,      -- Key: Keypad 0
        KEY_KP_1            = 321,      -- Key: Keypad 1
        KEY_KP_2            = 322,      -- Key: Keypad 2
        KEY_KP_3            = 323,      -- Key: Keypad 3
        KEY_KP_4            = 324,      -- Key: Keypad 4
        KEY_KP_5            = 325,      -- Key: Keypad 5
        KEY_KP_6            = 326,      -- Key: Keypad 6
        KEY_KP_7            = 327,      -- Key: Keypad 7
        KEY_KP_8            = 328,      -- Key: Keypad 8
        KEY_KP_9            = 329,      -- Key: Keypad 9
        KEY_KP_DECIMAL      = 330,      -- Key: Keypad .
        KEY_KP_DIVIDE       = 331,      -- Key: Keypad /
        KEY_KP_MULTIPLY     = 332,      -- Key: Keypad *
        KEY_KP_SUBTRACT     = 333,      -- Key: Keypad -
        KEY_KP_ADD          = 334,      -- Key: Keypad +
        KEY_KP_ENTER        = 335,      -- Key: Keypad Enter
        KEY_KP_EQUAL        = 336,      -- Key: Keypad =
        -- Android key buttons
        KEY_BACK            = 4,        -- Key: Android back button
        KEY_MENU            = 5,        -- Key: Android menu button
        KEY_VOLUME_UP       = 24,       -- Key: Android volume up button
        KEY_VOLUME_DOWN     = 25        -- Key: Android volume down button
    },

    MouseButton = {
        MOUSE_BUTTON_LEFT    = 0,       -- Mouse button left
        MOUSE_BUTTON_RIGHT   = 1,       -- Mouse button right
        MOUSE_BUTTON_MIDDLE  = 2,       -- Mouse button middle (pressed wheel)
        MOUSE_BUTTON_SIDE    = 3,       -- Mouse button side (advanced mouse device)
        MOUSE_BUTTON_EXTRA   = 4,       -- Mouse button extra (advanced mouse device)
        MOUSE_BUTTON_FORWARD = 5,       -- Mouse button forward (advanced mouse device)
        MOUSE_BUTTON_BACK    = 6,       -- Mouse button back (advanced mouse device)
    },

    MouseCursor = {
        MOUSE_CURSOR_DEFAULT       = 0,     -- Default pointer shape
        MOUSE_CURSOR_ARROW         = 1,     -- Arrow shape
        MOUSE_CURSOR_IBEAM         = 2,     -- Text writing cursor shape
        MOUSE_CURSOR_CROSSHAIR     = 3,     -- Cross shape
        MOUSE_CURSOR_POINTING_HAND = 4,     -- Pointing hand cursor
        MOUSE_CURSOR_RESIZE_EW     = 5,     -- Horizontal resize/move arrow shape
        MOUSE_CURSOR_RESIZE_NS     = 6,     -- Vertical resize/move arrow shape
        MOUSE_CURSOR_RESIZE_NWSE   = 7,     -- Top-left to bottom-right diagonal resize/move arrow shape
        MOUSE_CURSOR_RESIZE_NESW   = 8,     -- The top-right to bottom-left diagonal resize/move arrow shape
        MOUSE_CURSOR_RESIZE_ALL    = 9,     -- The omnidirectional resize/move cursor shape
        MOUSE_CURSOR_NOT_ALLOWED   = 10     -- The operation-not-allowed shape
    },

    GamepadButton = {
        GAMEPAD_BUTTON_UNKNOWN = 0,              -- Unknown button, just for error checking
        GAMEPAD_BUTTON_LEFT_FACE_UP = 1,         -- Gamepad left DPAD up button
        GAMEPAD_BUTTON_LEFT_FACE_RIGHT = 2,      -- Gamepad left DPAD right button
        GAMEPAD_BUTTON_LEFT_FACE_DOWN = 3,       -- Gamepad left DPAD down button
        GAMEPAD_BUTTON_LEFT_FACE_LEFT = 4,       -- Gamepad left DPAD left button
        GAMEPAD_BUTTON_RIGHT_FACE_UP = 5,        -- Gamepad right button up (i.e. PS3: Triangle, Xbox: Y)
        GAMEPAD_BUTTON_RIGHT_FACE_RIGHT = 6,     -- Gamepad right button right (i.e. PS3: Circle, Xbox: B)
        GAMEPAD_BUTTON_RIGHT_FACE_DOWN = 7,      -- Gamepad right button down (i.e. PS3: Cross, Xbox: A)
        GAMEPAD_BUTTON_RIGHT_FACE_LEFT = 8,      -- Gamepad right button left (i.e. PS3: Square, Xbox: X)
        GAMEPAD_BUTTON_LEFT_TRIGGER_1 = 9,       -- Gamepad top/back trigger left (first), it could be a trailing button
        GAMEPAD_BUTTON_LEFT_TRIGGER_2 = 10,      -- Gamepad top/back trigger left (second), it could be a trailing button
        GAMEPAD_BUTTON_RIGHT_TRIGGER_1 = 11,     -- Gamepad top/back trigger right (first), it could be a trailing button
        GAMEPAD_BUTTON_RIGHT_TRIGGER_2 = 12,     -- Gamepad top/back trigger right (second), it could be a trailing button
        GAMEPAD_BUTTON_MIDDLE_LEFT = 13,         -- Gamepad center buttons, left one (i.e. PS3: Select)
        GAMEPAD_BUTTON_MIDDLE = 14,              -- Gamepad center buttons, middle one (i.e. PS3: PS, Xbox: XBOX)
        GAMEPAD_BUTTON_MIDDLE_RIGHT = 15,        -- Gamepad center buttons, right one (i.e. PS3: Start)
        GAMEPAD_BUTTON_LEFT_THUMB = 16,          -- Gamepad joystick pressed button left
        GAMEPAD_BUTTON_RIGHT_THUMB = 17          -- Gamepad joystick pressed button right
    },

    GamepadAxis = {
        GAMEPAD_AXIS_LEFT_X        = 0,     -- Gamepad left stick X axis
        GAMEPAD_AXIS_LEFT_Y        = 1,     -- Gamepad left stick Y axis
        GAMEPAD_AXIS_RIGHT_X       = 2,     -- Gamepad right stick X axis
        GAMEPAD_AXIS_RIGHT_Y       = 3,     -- Gamepad right stick Y axis
        GAMEPAD_AXIS_LEFT_TRIGGER  = 4,     -- Gamepad back trigger left, pressure level: [1..-1]
        GAMEPAD_AXIS_RIGHT_TRIGGER = 5      -- Gamepad back trigger right, pressure level: [1..-1]
    },

    MaterialMapIndex = {
        MATERIAL_MAP_ALBEDO = 0,            -- Albedo material (same as: MATERIAL_MAP_DIFFUSE)
        MATERIAL_MAP_METALNESS = 1,         -- Metalness material (same as: MATERIAL_MAP_SPECULAR)
        MATERIAL_MAP_NORMAL = 2,            -- Normal material
        MATERIAL_MAP_ROUGHNESS = 3,         -- Roughness material
        MATERIAL_MAP_OCCLUSION = 4,         -- Ambient occlusion material
        MATERIAL_MAP_EMISSION = 5,          -- Emission material
        MATERIAL_MAP_HEIGHT = 6,            -- Heightmap material
        MATERIAL_MAP_CUBEMAP = 7,           -- Cubemap material (NOTE: Uses GL_TEXTURE_CUBE_MAP)
        MATERIAL_MAP_IRRADIANCE = 8,        -- Irradiance material (NOTE: Uses GL_TEXTURE_CUBE_MAP)
        MATERIAL_MAP_PREFILTER = 9,         -- Prefilter material (NOTE: Uses GL_TEXTURE_CUBE_MAP)
        MATERIAL_MAP_BRDF = 10,             -- Brdf material

        MATERIAL_MAP_DIFFUSE = 0, -- =MATERIAL_MAP_ALBEDO
        MATERIAL_MAP_SPECULAR = 1, -- =MATERIAL_MAP_METALNESS
    },

    ShaderLocationIndex = {
        SHADER_LOC_VERTEX_POSITION = 0,      -- Shader location: vertex attribute: position
        SHADER_LOC_VERTEX_TEXCOORD01 = 1,    -- Shader location: vertex attribute: texcoord01
        SHADER_LOC_VERTEX_TEXCOORD02 = 2,    -- Shader location: vertex attribute: texcoord02
        SHADER_LOC_VERTEX_NORMAL = 3,        -- Shader location: vertex attribute: normal
        SHADER_LOC_VERTEX_TANGENT = 4,       -- Shader location: vertex attribute: tangent
        SHADER_LOC_VERTEX_COLOR = 5,         -- Shader location: vertex attribute: color
        SHADER_LOC_MATRIX_MVP = 6,           -- Shader location: matrix uniform: model-view-projection
        SHADER_LOC_MATRIX_VIEW = 7,          -- Shader location: matrix uniform: view (camera transform)
        SHADER_LOC_MATRIX_PROJECTION = 8,    -- Shader location: matrix uniform: projection
        SHADER_LOC_MATRIX_MODEL = 9,         -- Shader location: matrix uniform: model (transform)
        SHADER_LOC_MATRIX_NORMAL = 10,       -- Shader location: matrix uniform: normal
        SHADER_LOC_VECTOR_VIEW = 11,         -- Shader location: vector uniform: view
        SHADER_LOC_COLOR_DIFFUSE = 12,       -- Shader location: vector uniform: diffuse color
        SHADER_LOC_COLOR_SPECULAR = 13,      -- Shader location: vector uniform: specular color
        SHADER_LOC_COLOR_AMBIENT = 14,       -- Shader location: vector uniform: ambient color
        SHADER_LOC_MAP_ALBEDO = 15,          -- Shader location: sampler2d texture: albedo (same as: SHADER_LOC_MAP_DIFFUSE)
        SHADER_LOC_MAP_METALNESS = 16,       -- Shader location: sampler2d texture: metalness (same as: SHADER_LOC_MAP_SPECULAR)
        SHADER_LOC_MAP_NORMAL = 17,          -- Shader location: sampler2d texture: normal
        SHADER_LOC_MAP_ROUGHNESS = 18,       -- Shader location: sampler2d texture: roughness
        SHADER_LOC_MAP_OCCLUSION = 19,       -- Shader location: sampler2d texture: occlusion
        SHADER_LOC_MAP_EMISSION = 20,        -- Shader location: sampler2d texture: emission
        SHADER_LOC_MAP_HEIGHT = 21,          -- Shader location: sampler2d texture: height
        SHADER_LOC_MAP_CUBEMAP = 22,         -- Shader location: samplerCube texture: cubemap
        SHADER_LOC_MAP_IRRADIANCE = 23,      -- Shader location: samplerCube texture: irradiance
        SHADER_LOC_MAP_PREFILTER = 24,       -- Shader location: samplerCube texture: prefilter
        SHADER_LOC_MAP_BRDF = 25,            -- Shader location: sampler2d texture: brdf
        SHADER_LOC_VERTEX_BONEIDS = 26,      -- Shader location: vertex attribute: boneIds
        SHADER_LOC_VERTEX_BONEWEIGHTS = 27,  -- Shader location: vertex attribute: boneWeights
        SHADER_LOC_BONE_MATRICES = 28,       -- Shader location: array of matrices uniform: boneMatrices

        SHADER_LOC_MAP_DIFFUSE = 15,    -- =SHADER_LOC_MAP_ALBEDO
        SHADER_LOC_MAP_SPECULAR = 16    -- =SHADER_LOC_MAP_METALNESS
    },

    ShaderUniformDataType = {
        SHADER_UNIFORM_FLOAT = 0,           -- Shader uniform type: float
        SHADER_UNIFORM_VEC2 = 1,            -- Shader uniform type: vec2 (2 float)
        SHADER_UNIFORM_VEC3 = 2,            -- Shader uniform type: vec3 (3 float)
        SHADER_UNIFORM_VEC4 = 3,            -- Shader uniform type: vec4 (4 float)
        SHADER_UNIFORM_INT = 4,             -- Shader uniform type: int
        SHADER_UNIFORM_IVEC2 = 5,           -- Shader uniform type: ivec2 (2 int)
        SHADER_UNIFORM_IVEC3 = 6,           -- Shader uniform type: ivec3 (3 int)
        SHADER_UNIFORM_IVEC4 = 7,           -- Shader uniform type: ivec4 (4 int)
        SHADER_UNIFORM_SAMPLER2D = 8        -- Shader uniform type: sampler2d
    },

    ShaderAttributeDataType = {
        SHADER_ATTRIB_FLOAT = 0,            -- Shader attribute type: float
        SHADER_ATTRIB_VEC2 = 1,             -- Shader attribute type: vec2 (2 float)
        SHADER_ATTRIB_VEC3 = 2,             -- Shader attribute type: vec3 (3 float)
        SHADER_ATTRIB_VEC4 = 3              -- Shader attribute type: vec4 (4 float)
    },

    PixelFormat = {
        PIXELFORMAT_UNCOMPRESSED_GRAYSCALE = 1,      -- 8 bit per pixel (no alpha)
        PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA = 2,     -- 8*2 bpp (2 channels)
        PIXELFORMAT_UNCOMPRESSED_R5G6B5 = 3,         -- 16 bpp
        PIXELFORMAT_UNCOMPRESSED_R8G8B8 = 4,         -- 24 bpp
        PIXELFORMAT_UNCOMPRESSED_R5G5B5A1 = 5,       -- 16 bpp (1 bit alpha)
        PIXELFORMAT_UNCOMPRESSED_R4G4B4A4 = 6,       -- 16 bpp (4 bit alpha)
        PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 = 7,       -- 32 bpp
        PIXELFORMAT_UNCOMPRESSED_R32 = 8,            -- 32 bpp (1 channel - float)
        PIXELFORMAT_UNCOMPRESSED_R32G32B32 = 9,      -- 32*3 bpp (3 channels - float)
        PIXELFORMAT_UNCOMPRESSED_R32G32B32A32 = 10,  -- 32*4 bpp (4 channels - float)
        PIXELFORMAT_UNCOMPRESSED_R16 = 11,           -- 16 bpp (1 channel - half float)
        PIXELFORMAT_UNCOMPRESSED_R16G16B16 = 12,     -- 16*3 bpp (3 channels - half float)
        PIXELFORMAT_UNCOMPRESSED_R16G16B16A16 = 13,  -- 16*4 bpp (4 channels - half float)
        PIXELFORMAT_COMPRESSED_DXT1_RGB = 14,        -- 4 bpp (no alpha)
        PIXELFORMAT_COMPRESSED_DXT1_RGBA = 15,       -- 4 bpp (1 bit alpha)
        PIXELFORMAT_COMPRESSED_DXT3_RGBA = 16,       -- 8 bpp
        PIXELFORMAT_COMPRESSED_DXT5_RGBA = 17,       -- 8 bpp
        PIXELFORMAT_COMPRESSED_ETC1_RGB = 18,        -- 4 bpp
        PIXELFORMAT_COMPRESSED_ETC2_RGB = 19,        -- 4 bpp
        PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA = 20,   -- 8 bpp
        PIXELFORMAT_COMPRESSED_PVRT_RGB = 21,        -- 4 bpp
        PIXELFORMAT_COMPRESSED_PVRT_RGBA = 22,       -- 4 bpp
        PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA = 23,   -- 8 bpp
        PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA = 24    -- 2 bpp
    },

    TextureFilter = {
        TEXTURE_FILTER_POINT = 0,                   -- No filter, just pixel approximation
        TEXTURE_FILTER_BILINEAR = 1,                -- Linear filtering
        TEXTURE_FILTER_TRILINEAR = 2,               -- Trilinear filtering (linear with mipmaps)
        TEXTURE_FILTER_ANISOTROPIC_4X = 3,          -- Anisotropic filtering 4x
        TEXTURE_FILTER_ANISOTROPIC_8X = 4,          -- Anisotropic filtering 8x
        TEXTURE_FILTER_ANISOTROPIC_16X = 5,         -- Anisotropic filtering 16x
    },

    TextureWrap = {
        TEXTURE_WRAP_REPEAT = 0,                    -- Repeats texture in tiled mode
        TEXTURE_WRAP_CLAMP = 1,                     -- Clamps texture to edge pixel in tiled mode
        TEXTURE_WRAP_MIRROR_REPEAT = 2,             -- Mirrors and repeats the texture in tiled mode
        TEXTURE_WRAP_MIRROR_CLAMP = 3               -- Mirrors and clamps to border the texture in tiled mode
    },

    CubemapLayout = {
        CUBEMAP_LAYOUT_AUTO_DETECT = 0,             -- Automatically detect layout type
        CUBEMAP_LAYOUT_LINE_VERTICAL = 1,           -- Layout is defined by a vertical line with faces
        CUBEMAP_LAYOUT_LINE_HORIZONTAL = 2,         -- Layout is defined by a horizontal line with faces
        CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR = 3,     -- Layout is defined by a 3x4 cross with cubemap faces
        CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE = 4      -- Layout is defined by a 4x3 cross with cubemap faces
    },

    FontType = {
        FONT_DEFAULT = 0,                   -- Default font generation, anti-aliased
        FONT_BITMAP = 1,                    -- Bitmap font generation, no anti-aliasing
        FONT_SDF = 2                        -- SDF font generation, requires external shader
    },

    BlendMode = {
        BLEND_ALPHA = 0,                    -- Blend textures considering alpha (default)
        BLEND_ADDITIVE = 1,                 -- Blend textures adding colors
        BLEND_MULTIPLIED = 2,               -- Blend textures multiplying colors
        BLEND_ADD_COLORS = 3,               -- Blend textures adding colors (alternative)
        BLEND_SUBTRACT_COLORS = 4,          -- Blend textures subtracting colors (alternative)
        BLEND_ALPHA_PREMULTIPLY = 5,        -- Blend premultiplied textures considering alpha
        BLEND_CUSTOM = 6,                   -- Blend textures using custom src/dst factors (use rlSetBlendFactors())
        BLEND_CUSTOM_SEPARATE = 7           -- Blend textures using custom rgb/alpha separate src/dst factors (use rlSetBlendFactorsSeparate())
    },

    Gesture = {
        GESTURE_NONE        = 0,        -- No gesture
        GESTURE_TAP         = 1,        -- Tap gesture
        GESTURE_DOUBLETAP   = 2,        -- Double tap gesture
        GESTURE_HOLD        = 4,        -- Hold gesture
        GESTURE_DRAG        = 8,        -- Drag gesture
        GESTURE_SWIPE_RIGHT = 16,       -- Swipe right gesture
        GESTURE_SWIPE_LEFT  = 32,       -- Swipe left gesture
        GESTURE_SWIPE_UP    = 64,       -- Swipe up gesture
        GESTURE_SWIPE_DOWN  = 128,      -- Swipe down gesture
        GESTURE_PINCH_IN    = 256,      -- Pinch in gesture
        GESTURE_PINCH_OUT   = 512       -- Pinch out gesture
    },

    CameraMode = {
        CAMERA_CUSTOM       = 0,          -- Camera custom, controlled by user (UpdateCamera() does nothing)
        CAMERA_FREE         = 1,          -- Camera free mode
        CAMERA_ORBITAL      = 2,          -- Camera orbital, around target, zoom supported
        CAMERA_FIRST_PERSON = 3,          -- Camera first person
        CAMERA_THIRD_PERSON = 4           -- Camera third person
    },

    CameraProjection = {
        CAMERA_PERSPECTIVE  = 0,          -- Perspective projection
        CAMERA_ORTHOGRAPHIC = 1           -- Orthographic projection
    },

    NPatchLayout = {
        NPATCH_NINE_PATCH = 0,              -- Npatch layout: 3x3 tiles
        NPATCH_THREE_PATCH_VERTICAL = 1,    -- Npatch layout: 1x3 tiles
        NPATCH_THREE_PATCH_HORIZONTAL = 2   -- Npatch layout: 3x1 tiles
    },
}

return export;


--!strict
--!optimize 2
--!native

local ffi = zune.ffi;

local raylib = require("./raylib");

local structs = raylib.structs;

local void = ffi.types.void;
local int = ffi.types.i32;
local bool = ffi.types.u8;
local float = ffi.types.float;
type int = number;
type bool = number;
type float = number;
type cstring = string | buffer | FFIPointer;

local Vector2 = structs.Vector2;
local Color = structs.Color;
local Rectangle = structs.Rectangle;
local Texture2D = structs.Texture2D;
type Vector2 = raylib.Vector2;
type Color = raylib.Color;
type Rectangle = raylib.Rectangle;
type Texture2D = raylib.Texture2D;

local function fn(returns: any, args: { any })
    return {
        returns = returns,
        args = args,
    };
end

export type Fns = {
    SetShapesTexture: (texture: Texture2D, source: Rectangle) -> (),
    GetShapesTexture: () -> Texture2D,
    GetShapesTextureRectangle: () -> Rectangle,
    DrawPixel: (posX: int, posY: int, color: Color) -> (),
    DrawPixelV: (position: Vector2, color: Color) -> (),
    DrawLine: (startPosX: int, startPosY: int, endPosX: int, endPosY: int, color: Color) -> (),
    DrawLineV: (startPos: Vector2, endPos: Vector2, color: Color) -> (),
    DrawLineEx: (startPos: Vector2, endPos: Vector2, thick: float, color: Color) -> (),
    DrawLineStrip: (points: FFIPointer, pointCount: int, color: Color) -> (),
    DrawLineBezier: (startPos: Vector2, endPos: Vector2, thick: float, color: Color) -> (),
    DrawCircle: (centerX: int, centerY: int, radius: float, color: Color) -> (),
    DrawCircleSector: (center: Vector2, radius: float, startAngle: float, endAngle: float, segments: int, color: Color) -> (),
    DrawCircleSectorLines: (center: Vector2, radius: float, startAngle: float, endAngle: float, segments: int, color: Color) -> (),
    DrawCircleGradient: (centerX: int, centerY: int, radius: float, inner: Color, outer: Color) -> (),
    DrawCircleV: (center: Vector2, radius: float, color: Color) -> (),
    DrawCircleLines: (centerX: int, centerY: int, radius: float, color: Color) -> (),
    DrawCircleLinesV: (center: Vector2, radius: float, color: Color) -> (),
    DrawEllipse: (centerX: int, centerY: int, radiusH: float, radiusV: float, color: Color) -> (),
    DrawEllipseLines: (centerX: int, centerY: int, radiusH: float, radiusV: float, color: Color) -> (),
    DrawRing: (center: Vector2, innerRadius: float, outerRadius: float, startAngle: float, endAngle: float, segments: int, color: Color) -> (),
    DrawRingLines: (center: Vector2, innerRadius: float, outerRadius: float, startAngle: float, endAngle: float, segments: int, color: Color) -> (),
    DrawRectangle: (posX: int, posY: int, width: int, height: int, color: Color) -> (),
    DrawRectangleV: (position: Vector2, size: Vector2, color: Color) -> (),
    DrawRectangleRec: (rec: Rectangle, color: Color) -> (),
    DrawRectanglePro: (rec: Rectangle, origin: Vector2, rotation: float, color: Color) -> (),
    DrawRectangleGradientV: (posX: int, posY: int, width: int, height: int, top: Color, bottom: Color) -> (),
    DrawRectangleGradientH: (posX: int, posY: int, width: int, height: int, left: Color, right: Color) -> (),
    DrawRectangleGradientEx: (rec: Rectangle, topLeft: Color, bottomLeft: Color, topRight: Color, bottomRight: Color) -> (),
    DrawRectangleLines: (posX: int, posY: int, width: int, height: int, color: Color) -> (),
    DrawRectangleLinesEx: (rec: Rectangle, lineThick: float, color: Color) -> (),
    DrawRectangleRounded: (rec: Rectangle, roundness: float, segments: int, color: Color) -> (),
    DrawRectangleRoundedLines: (rec: Rectangle, roundness: float, segments: int, color: Color) -> (),
    DrawRectangleRoundedLinesEx: (rec: Rectangle, roundness: float, segments: int, lineThick: float, color: Color) -> (),
    DrawTriangle: (v1: Vector2, v2: Vector2, v3: Vector2, color: Color) -> (),
    DrawTriangleLines: (v1: Vector2, v2: Vector2, v3: Vector2, color: Color) -> (),
    DrawTriangleFan: (points: FFIPointer, pointCount: int, color: Color) -> (),
    DrawTriangleStrip: (points: FFIPointer, pointCount: int, color: Color) -> (),
    DrawPoly: (center: Vector2, sides: int, radius: float, rotation: float, color: Color) -> (),
    DrawPolyLines: (center: Vector2, sides: int, radius: float, rotation: float, color: Color) -> (),
    DrawPolyLinesEx: (center: Vector2, sides: int, radius: float, rotation: float, lineThick: float, color: Color) -> (),
    DrawSplineLinear: (points: FFIPointer, pointCount: int, thick: float, color: Color) -> (),
    DrawSplineBasis: (points: FFIPointer, pointCount: int, thick: float, color: Color) -> (),
    DrawSplineCatmullRom: (points: FFIPointer, pointCount: int, thick: float, color: Color) -> (),
    DrawSplineBezierQuadratic: (points: FFIPointer, pointCount: int, thick: float, color: Color) -> (),
    DrawSplineBezierCubic: (points: FFIPointer, pointCount: int, thick: float, color: Color) -> (),
    DrawSplineSegmentLinear: (p1: Vector2, p2: Vector2, thick: float, color: Color) -> (),
    DrawSplineSegmentBasis: (p1: Vector2, p2: Vector2, p3: Vector2, p4: Vector2, thick: float, color: Color) -> (),
    DrawSplineSegmentCatmullRom: (p1: Vector2, p2: Vector2, p3: Vector2, p4: Vector2, thick: float, color: Color) -> (),
    DrawSplineSegmentBezierQuadratic: (p1: Vector2, c2: Vector2, p3: Vector2, thick: float, color: Color) -> (),
    DrawSplineSegmentBezierCubic: (p1: Vector2, c2: Vector2, c3: Vector2, p4: Vector2, thick: float, color: Color) -> (),
    GetSplinePointLinear: (startPos: Vector2, endPos: Vector2, t: float) -> Vector2,
    GetSplinePointBasis: (p1: Vector2, p2: Vector2, p3: Vector2, p4: Vector2, t: float) -> Vector2,
    GetSplinePointCatmullRom: (p1: Vector2, p2: Vector2, p3: Vector2, p4: Vector2, t: float) -> Vector2,
    GetSplinePointBezierQuad: (p1: Vector2, c2: Vector2, p3: Vector2, t: float) -> Vector2,
    GetSplinePointBezierCubic: (p1: Vector2, c2: Vector2, c3: Vector2, p4: Vector2, t: float) -> Vector2,
    CheckCollisionRecs: (rec1: Rectangle, rec2: Rectangle) -> bool,
    CheckCollisionCircles: (center1: Vector2, radius1: float, center2: Vector2, radius2: float) -> bool,
    CheckCollisionCircleRec: (center: Vector2, radius: float, rec: Rectangle) -> bool,
    CheckCollisionCircleLine: (center: Vector2, radius: float, p1: Vector2, p2: Vector2) -> bool,
    CheckCollisionPointRec: (point: Vector2, rec: Rectangle) -> bool,
    CheckCollisionPointCircle: (point: Vector2, center: Vector2, radius: float) -> bool,
    CheckCollisionPointTriangle: (point: Vector2, p1: Vector2, p2: Vector2, p3: Vector2) -> bool,
    CheckCollisionPointLine: (point: Vector2, p1: Vector2, p2: Vector2, threshold: int) -> bool,
    CheckCollisionPointPoly: (point: Vector2, points: FFIPointer, pointCount: int) -> bool,
    CheckCollisionLines: (startPos1: Vector2, endPos1: Vector2, startPos2: Vector2, endPos2: Vector2, collisionPoint: FFIPointer) -> bool,
    GetCollisionRec: (rec1: Rectangle, rec2: Rectangle) -> Rectangle,
};

return {
    def = {
        -- void SetShapesTexture(Texture2D texture, Rectangle source);
        SetShapesTexture = fn(void, { Texture2D, Rectangle }),
        -- Texture2D GetShapesTexture(void);
        GetShapesTexture = fn(Texture2D, { }),
        -- Rectangle GetShapesTextureRectangle(void);
        GetShapesTextureRectangle = fn(Rectangle, { }),

        -- void DrawPixel(int posX, int posY, Color color);
        DrawPixel = fn(void, { int, int, Color }),
        -- void DrawPixelV(Vector2 position, Color color);
        DrawPixelV = fn(void, { Vector2, Color }),
        -- void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color);
        DrawLine = fn(void, { int, int, int, int, Color }),
        -- void DrawLineV(Vector2 startPos, Vector2 endPos, Color color);
        DrawLineV = fn(void, { Vector2, Vector2, Color }),
        -- void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color);
        DrawLineEx = fn(void, { Vector2, Vector2, float, Color }),
        -- void DrawLineStrip(const Vector2 *points, int pointCount, Color color);
        DrawLineStrip = fn(void, { ffi.types.pointer, int, Color }),
        -- void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color);
        DrawLineBezier = fn(void, { Vector2, Vector2, float, Color }),
        -- void DrawCircle(int centerX, int centerY, float radius, Color color
        DrawCircle = fn(void, { int, int, float, Color }),
        -- void DrawCircleSector(Vector2 center, float radius, float startAngle, float end
        DrawCircleSector = fn(void, { Vector2, float, float, float, int, Color }),
        -- void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color);
        DrawCircleSectorLines = fn(void, { Vector2, float, float, float, int, Color }),
        -- void DrawCircleGradient(int centerX, int centerY, float radius, Color inner, Color outer);
        DrawCircleGradient = fn(void, { int, int, float, Color, Color }),
        -- void DrawCircleV(Vector2 center, float radius, Color color);
        DrawCircleV = fn(void, { Vector2, float, Color }),
        -- void DrawCircleLines(int centerX, int centerY, float radius, Color color);
        DrawCircleLines = fn(void, { int, int, float, Color }),
        -- void DrawCircleLinesV(Vector2 center, float radius, Color color);
        DrawCircleLinesV = fn(void, { Vector2, float, Color }),
        -- void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color);
        DrawEllipse = fn(void, { int, int, float, float, Color }),
        -- void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color);
        DrawEllipseLines = fn(void, { int, int, float, float, Color }),
        -- void DrawRing(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color);
        DrawRing = fn(void, { Vector2, float, float, float, float, int, Color }),
        -- void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color);
        DrawRingLines = fn(void, { Vector2, float, float, float, float, int, Color }),
        -- void DrawRectangle(int posX, int posY, int width, int height, Color color);
        DrawRectangle = fn(void, { int, int, int, int, Color }),
        -- void DrawRectangleV(Vector2 position, Vector2 size, Color color);
        DrawRectangleV = fn(void, { Vector2, Vector2, Color }),
        -- void DrawRectangleRec(Rectangle rec, Color color);
        DrawRectangleRec = fn(void, { Rectangle, Color }),
        -- void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color);
        DrawRectanglePro = fn(void, { Rectangle, Vector2, float, Color }),
        -- void DrawRectangleGradientV(int posX, int posY, int width, int height, Color top, Color bottom);
        DrawRectangleGradientV = fn(void, { int, int, int, int, Color, Color }),
        -- void DrawRectangleGradientH(int posX, int posY, int width, int height, Color left, Color right);
        DrawRectangleGradientH = fn(void, { int, int, int, int, Color, Color }),
        -- void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color topRight, Color bottomRight);
        DrawRectangleGradientEx = fn(void, { Rectangle, Color, Color, Color, Color }),
        -- void DrawRectangleLines(int posX, int posY, int width, int height, Color color);
        DrawRectangleLines = fn(void, { int, int, int, int, Color }),
        -- void DrawRectangleLinesEx(Rectangle rec, float lineThick, Color color);
        DrawRectangleLinesEx = fn(void, { Rectangle, float, Color }),
        -- void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color);
        DrawRectangleRounded = fn(void, { Rectangle, float, int, Color }),
        -- void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, Color color);
        DrawRectangleRoundedLines = fn(void, { Rectangle, float, int, Color }),
        -- void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, float lineThick, Color color);
        DrawRectangleRoundedLinesEx = fn(void, { Rectangle, float, int, float, Color }),
        -- void DrawTriangle(Vector2 v1, Vector v2, Vector2 v3, Color color);
        DrawTriangle = fn(void, { Vector2, Vector2, Vector2, Color }),
        -- void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color);
        DrawTriangleLines = fn(void, { Vector2, Vector2, Vector2, Color }),
        -- void DrawTriangleFan(const Vector2 *points, int pointCount, Color color);
        DrawTriangleFan = fn(void, { ffi.types.pointer, int, Color }),
        -- void DrawTriangleStrip(const Vector2 *points, int pointCount, Color color);
        DrawTriangleStrip = fn(void, { ffi.types.pointer, int, Color }),
        -- void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color);
        DrawPoly = fn(void, { Vector2, int, float, float, Color }),
        -- void DrawPolyLines(Vector2 center, int sides, float radius, float rotation, Color color);
        DrawPolyLines = fn(void, { Vector2, int, float, float, Color }),
        -- void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, float lineThick, Color color);
        DrawPolyLinesEx = fn(void, { Vector2, int, float, float, float, Color }),

        -- void DrawSplineLinear(const Vector2 *points, int pointCount, float thick, Color color);
        DrawSplineLinear = fn(void, { ffi.types.pointer, int, float, Color }),
        -- void DrawSplineBasis(const Vector2 *points, int pointCount, float thick, Color color);
        DrawSplineBasis = fn(void, { ffi.types.pointer, int, float, Color }),
        -- void DrawSplineCatmullRom(const Vector2 *points, int pointCount, float thick, Color color);
        DrawSplineCatmullRom = fn(void, { ffi.types.pointer, int, float, Color }),
        -- void DrawSplineBezierQuadratic(const Vector2 *points, int pointCount, float thick, Color color);
        DrawSplineBezierQuadratic = fn(void, { ffi.types.pointer, int, float, Color }),
        -- void DrawSplineBezierCubic(const Vector2 *points, int pointCount, float thick, Color color);
        DrawSplineBezierCubic = fn(void, { ffi.types.pointer, int, float, Color }),
        -- void DrawSplineSegmentLinear(Vector2 p1, Vector2 p2, float thick, Color color);
        DrawSplineSegmentLinear = fn(void, { Vector2, Vector2, float, Color }),
        -- void DrawSplineSegmentBasis(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, Color color);
        DrawSplineSegmentBasis = fn(void, { Vector2, Vector2, Vector2, Vector2, float, Color }),
        -- void DrawSplineSegmentCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, Color color);
        DrawSplineSegmentCatmullRom = fn(void, { Vector2, Vector2, Vector2, Vector2, float, Color }),
        -- void DrawSplineSegmentBezierQuadratic(Vector2 p1, Vector2 c2, Vector2 p3, float thick, Color color);
        DrawSplineSegmentBezierQuadratic = fn(void, { Vector2, Vector2, Vector2, float, Color }),
        -- void DrawSplineSegmentBezierCubic(Vector2 p1, Vector2 c2, Vector2 c3, Vector2 p4, float thick, Color color);
        DrawSplineSegmentBezierCubic = fn(void, { Vector2, Vector2, Vector2, Vector2, float, Color }),

        -- Vector2 GetSplinePointLinear(Vector2 startPos, Vector2 endPos, float t);
        GetSplinePointLinear = fn(Vector2, { Vector2, Vector2, float }),
        -- Vector2 GetSplinePointBasis(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float t);
        GetSplinePointBasis = fn(Vector2, { Vector2, Vector2, Vector2, Vector2, float }),
        -- Vector2 GetSplinePointCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float t);
        GetSplinePointCatmullRom = fn(Vector2, { Vector2, Vector2, Vector2, Vector2, float }),
        -- Vector2 GetSplinePointBezierQuad(Vector2 p1, Vector2 c2, Vector2 p3, float t);
        GetSplinePointBezierQuad = fn(Vector2, { Vector2, Vector2, Vector2, float }),
        -- Vector2 GetSplinePointBezierCubic(Vector2 p1, Vector2 c2, Vector2 c3, Vector2 p4, float t);
        GetSplinePointBezierCubic = fn(Vector2, { Vector2, Vector2, Vector2, Vector2, float }),

        -- bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2);
        CheckCollisionRecs = fn(bool, { Rectangle, Rectangle }),
        -- bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, float radius2);
        CheckCollisionCircles = fn(bool, { Vector2, float, Vector2, float }),
        -- bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec);
        CheckCollisionCircleRec = fn(bool, { Vector2, float, Rectangle }),
        -- bool CheckCollisionCircleLine(Vector2 center, float radius, Vector2 p1, Vector2 p2);
        CheckCollisionCircleLine = fn(bool, { Vector2, float, Vector2, Vector2 }),
        -- bool CheckCollisionPointRec(Vector2 point, Rectangle rec);
        CheckCollisionPointRec = fn(bool, { Vector2, Rectangle }),
        -- bool CheckCollisionPointCircle(Vector2 point, Vector2 center, float radius);
        CheckCollisionPointCircle = fn(bool, { Vector2, Vector2, float }),
        -- bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 p3);
        CheckCollisionPointTriangle = fn(bool, { Vector2, Vector2, Vector2, Vector2 }),
        -- bool CheckCollisionPointLine(Vector2 point, Vector2 p1, Vector2 p2, int threshold);
        CheckCollisionPointLine = fn(bool, { Vector2, Vector2, Vector2, int }),
        -- bool CheckCollisionPointPoly(Vector2 point, const Vector2 *points, int pointCount);
        CheckCollisionPointPoly = fn(bool, { Vector2, ffi.types.pointer, int }),
        -- bool CheckCollisionLines(Vector2 startPos1, Vector2 endPos1, Vector2 startPos2, Vector2 endPos2, Vector2 *collisionPoint);
        CheckCollisionLines = fn(bool, { Vector2, Vector2, Vector2, Vector2, ffi.types.pointer }),
        -- Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2);
        GetCollisionRec = fn(Rectangle, { Rectangle, Rectangle }),
    }
}


--!strict
--!optimize 2
--!native

local ffi = zune.ffi;

local raylib = require("./raylib");

local structs = raylib.structs;

local void = ffi.types.void;
local int = ffi.types.i32;
local uint = ffi.types.u32;
local bool = ffi.types.u8;
local float = ffi.types.float;
local cstring = ffi.types.pointer;
type int = number;
type uint = number;
type bool = number;
type float = number;
type cstring = string | buffer | FFIPointer;

local Vector2 = structs.Vector2;
local Vector3 = structs.Vector3;
local Vector4 = structs.Vector4;
local Color = structs.Color;
local Rectangle = structs.Rectangle;
local Image = structs.Image;
local Texture2D = structs.Texture2D;
local TextureCubemap = structs.TextureCubemap;
local RenderTexture2D = structs.RenderTexture2D;
local NPatchInfo = structs.NPatchInfo;
local Font = structs.Font;
type Vector2 = raylib.Vector2;
type Vector3 = raylib.Vector3;
type Vector4 = raylib.Vector4;
type Color = raylib.Color;
type Rectangle = raylib.Rectangle;
type Image = raylib.Image;
type Texture2D = raylib.Texture2D;
type TextureCubemap = raylib.TextureCubemap;
type RenderTexture2D = raylib.RenderTexture2D;
type NPatchInfo = raylib.NPatchInfo;
type Font = raylib.Font;

local function fn(returns: any, args: { any })
    return {
        returns = returns,
        args = args,
    };
end

export type Fns = {
    LoadImage: (fileName: cstring) -> Image,
    LoadImageRaw: (fileName: cstring, width: int, height: int, format: int, headerSize: int) -> Image,
    LoadImageAnim: (fileName: cstring, frames: FFIPointer) -> Image,
    LoadImageAnimFromMemory: (fileType: cstring, fileData: FFIPointer, dataSize: int, frames: FFIPointer) -> Image,
    LoadImageFromMemory: (fileType: cstring, fileData: FFIPointer, dataSize: int) -> Image,
    LoadImageFromTexture: (texture: Texture2D) -> Image,
    LoadImageFromScreen: () -> Image,
    IsImageValid: (image: Image) -> bool,
    UnloadImage: (image: Image) -> (),
    ExportImage: (image: Image, fileName: cstring) -> bool,
    ExportImageToMemory: (image: Image, fileType: cstring, fileSize: FFIPointer) -> FFIPointer,
    ExportImageAsCode: (image: Image, fileName: cstring) -> bool,
    GenImageColor: (width: int, height: int, color: Color) -> Image,
    GenImageGradientLinear: (width: int, height: int, direction: int, start: Color, endColor: Color) -> Image,
    GenImageGradientRadial: (width: int, height: int, density: float, inner: Color, outer: Color) -> Image,
    GenImageGradientSquare: (width: int, height: int, density: float, inner: Color, outer: Color) -> Image,
    GenImageChecked: (width: int, height: int, checksX: int, checksY: int, col1: Color, col2: Color) -> Image,
    GenImageWhiteNoise: (width: int, height: int, factor: float) -> Image,
    GenImagePerlinNoise: (width: int, height: int, offsetX: int, offsetY: int, scale: float) -> Image,
    GenImageCellular: (width: int, height: int, tileSize: int) -> Image,
    GenImageText: (width: int, height: int, text: cstring) -> Image,
    ImageCopy: (image: Image) -> Image,
    ImageFromImage: (image: Image, rec: Rectangle) -> Image,
    ImageFromChannel: (image: Image, selectedChannel: int) -> Image,
    ImageText: (text: cstring, fontSize: int, color: Color) -> Image,
    ImageTextEx: (font: Font, text: cstring, fontSize: float, spacing: float, tint: Color) -> Image,
    ImageFormat: (image: FFIPointer, newFormat: int) -> (),
    ImageToPOT: (image: FFIPointer, fill: Color) -> (),
    ImageCrop: (image: FFIPointer, crop: Rectangle) -> (),
    ImageAlphaCrop: (image: FFIPointer, threshold: float) -> (),
    ImageAlphaClear: (image: FFIPointer, color: Color, threshold: float) -> (),
    ImageAlphaMask: (image: FFIPointer, alphaMask: Image) -> (),
    ImageAlphaPremultiply: (image: FFIPointer) -> (),
    ImageBlurGaussian: (image: FFIPointer, blurSize: int) -> (),
    ImageKernelConvolution: (image: FFIPointer, kernel: FFIPointer, kernelSize: int) -> (),
    ImageResize: (image: FFIPointer, newWidth: int, newHeight: int) -> (),
    ImageResizeNN: (image: FFIPointer, newWidth: int, newHeight: int) -> (),
    ImageResizeCanvas: (image: FFIPointer, newWidth: int, newHeight: int, offsetX: int, offsetY: int, fill: Color) -> (),
    ImageMipmaps: (image: FFIPointer) -> (),
    ImageDither: (image: FFIPointer, rBpp: int, gBpp: int, bBpp: int, aBpp: int) -> (),
    ImageFlipVertical: (image: FFIPointer) -> (),
    ImageFlipHorizontal: (image: FFIPointer) -> (),
    ImageRotate: (image: FFIPointer, degrees: int) -> (),
    ImageRotateCW: (image: FFIPointer) -> (),
    ImageRotateCCW: (image: FFIPointer) -> (),
    ImageColorTint: (image: FFIPointer, color: Color) -> (),
    ImageColorInvert: (image: FFIPointer) -> (),
    ImageColorGrayscale: (image: FFIPointer) -> (),
    ImageColorContrast: (image: FFIPointer, contrast: float) -> (),
    ImageColorBrightness: (image: FFIPointer, brightness: int) -> (),
    ImageColorReplace: (image: FFIPointer, color: Color, replace: Color) -> (),
    LoadImageColors: (image: Image) -> FFIPointer,
    LoadImagePalette: (image: Image, maxPaletteSize: int, colorCount: FFIPointer) -> FFIPointer,
    UnloadImageColors: (colors: FFIPointer) -> (),
    UnloadImagePalette: (colors: FFIPointer) -> (),
    GetImageAlphaBorder: (image: Image, threshold: float) -> Rectangle,
    GetImageColor: (image: Image, x: int, y: int) -> Color,
    ImageClearBackground: (dst: FFIPointer, color: Color) -> (),
    ImageDrawPixel: (dst: FFIPointer, posX: int, posY: int, color: Color) -> (),
    ImageDrawPixelV: (dst: FFIPointer, position: Vector2, color: Color) -> (),
    ImageDrawLine: (dst: FFIPointer, startPosX: int, startPosY: int, endPosX: int, endPosY: int, color: Color) -> (),
    ImageDrawLineV: (dst: FFIPointer, start: Vector2, endPos: Vector2, color: Color) -> (),
    ImageDrawLineEx: (dst: FFIPointer, start: Vector2, endPos: Vector2, thick: int, color: Color) -> (),
    ImageDrawCircle: (dst: FFIPointer, centerX: int, centerY: int, radius: int, color: Color) -> (),
    ImageDrawCircleV: (dst: FFIPointer, center: Vector2, radius: int, color: Color) -> (),
    ImageDrawCircleLines: (dst: FFIPointer, centerX: int, centerY: int, radius: int, color: Color) -> (),
    ImageDrawCircleLinesV: (dst: FFIPointer, center: Vector2, radius: int, color: Color) -> (),
    ImageDrawRectangle: (dst: FFIPointer, posX: int, posY: int, width: int, height: int, color: Color) -> (),
    ImageDrawRectangleV: (dst: FFIPointer, position: Vector2, size: Vector2, color: Color) -> (),
    ImageDrawRectangleRec: (dst: FFIPointer, rec: Rectangle, color: Color) -> (),
    ImageDrawRectangleLines: (dst: FFIPointer, rec: Rectangle, thick: int, color: Color) -> (),
    ImageDrawTriangle: (dst: FFIPointer, v1: Vector2, v2: Vector2, v3: Vector2, color: Color) -> (),
    ImageDrawTriangleEx: (dst: FFIPointer, v1: Vector2, v2: Vector2, v3: Vector2, c1: Color, c2: Color, c3: Color) -> (),
    ImageDrawTriangleLines: (dst: FFIPointer, v1: Vector2, v2: Vector2, v3: Vector2, color: Color) -> (),
    ImageDrawTriangleFan: (dst: FFIPointer, points: FFIPointer, pointCount: int, color: Color) -> (),
    ImageDrawTriangleStrip: (dst: FFIPointer, points: FFIPointer, pointCount: int, color: Color) -> (),
    ImageDraw: (dst: FFIPointer, src: Image, srcRec: Rectangle, dstRec: Rectangle, tint: Color) -> (),
    ImageDrawText: (dst: FFIPointer, text: cstring, posX: int, posY: int, fontSize: int, color: Color) -> (),
    ImageDrawTextEx: (dst: FFIPointer, font: Font, text: cstring, position: Vector2, fontSize: float, spacing: float, tint: Color) -> (),
    LoadTexture: (fileName: cstring) -> Texture2D,
    LoadTextureFromImage: (image: Image) -> Texture2D,
    LoadTextureCubemap: (image: Image, layout: int) -> TextureCubemap,
    LoadRenderTexture: (width: int, height: int) -> RenderTexture2D,
    IsTextureValid: (texture: Texture2D) -> bool,
    UnloadTexture: (texture: Texture2D) -> (),
    IsRenderTextureValid: (target: RenderTexture2D) -> bool,
    UnloadRenderTexture: (target: RenderTexture2D) -> (),
    UpdateTexture: (texture: Texture2D, pixels: FFIPointer) -> (),
    UpdateTextureRec: (texture: Texture2D, rec: Rectangle, pixels: FFIPointer) -> (),
    GenTextureMipmaps: (texture: FFIPointer) -> (),
    SetTextureFilter: (texture: Texture2D, filter: int) -> (),
    SetTextureWrap: (texture: Texture2D, wrap: int) -> (),
    DrawTexture: (texture: Texture2D, posX: int, posY: int, tint: Color) -> (),
    DrawTextureV: (texture: Texture2D, position: Vector2, tint: Color) -> (),
    DrawTextureEx: (texture: Texture2D, position: Vector2, rotation: float, scale: float, tint: Color) -> (),
    DrawTextureRec: (texture: Texture2D, source: Rectangle, position: Vector2, tint: Color) -> (),
    DrawTexturePro: (texture: Texture2D, source: Rectangle, dest: Rectangle, origin: Vector2, rotation: float, tint: Color) -> (),
    DrawTextureNPatch: (texture: Texture2D, nPatchInfo: NPatchInfo, dest: Rectangle, origin: Vector2, rotation: float, tint: Color) -> (),
    ColorIsEqual: (col1: Color, col2: Color) -> bool,
    Fade: (color: Color, alpha: float) -> Color,
    ColorToInt: (color: Color) -> int,
    ColorNormalize: (color: Color) -> Vector4,
    ColorFromNormalized: (normalized: Vector4) -> Color,
    ColorToHSV: (color: Color) -> Vector3,
    ColorFromHSV: (hue: float, saturation: float, value: float) -> Color,
    ColorTint: (color: Color, tint: Color) -> Color,
    ColorBrightness: (color: Color, factor: float) -> Color,
    ColorContrast: (color: Color, contrast: float) -> Color,
    ColorAlpha: (color: Color, alpha: float) -> Color,
    ColorAlphaBlend: (dst: Color, src: Color, tint: Color) -> Color,
    ColorLerp: (color1: Color, color2: Color, factor: float) -> Color,
    GetColor: (hexValue: uint) -> Color,
    GetPixelColor: (srcPtr: FFIPointer, format: int) -> Color,
    SetPixelColor: (dstPtr: FFIPointer, color: Color, format: int) -> (),
    GetPixelDataSize: (width: int, height: int, format: int) -> int,
};

return {
    def = {
        -- Image LoadImage(const char *fileName);
        LoadImage = fn(Image, {cstring}),
        -- Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize);
        LoadImageRaw = fn(Image, {cstring, int, int, int, int}),
        -- Image LoadImageAnim(const char *fileName, int *frames);
        LoadImageAnim = fn(Image, {cstring, ffi.types.pointer}),
        -- Image LoadImageAnimFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int *frames);
        LoadImageAnimFromMemory = fn(Image, {cstring, ffi.types.pointer, int, ffi.types.pointer}),
        -- Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize);
        LoadImageFromMemory = fn(Image, {cstring, ffi.types.pointer, int}),
        -- Image LoadImageFromTexture(Texture2D texture);
        LoadImageFromTexture = fn(Image, {Texture2D}),
        -- Image LoadImageFromScreen(void);
        LoadImageFromScreen = fn(Image, {}),
        -- bool IsImageValid(Image image);
        IsImageValid = fn(bool, {Image}),
        -- void UnloadImage(Image image);
        UnloadImage = fn(void, {Image}),
        -- bool ExportImage(Image image, const char *fileName);
        ExportImage = fn(bool, {Image, cstring}),
        -- unsigned char *ExportImageToMemory(Image image, const char *fileType, int *fileSize);
        ExportImageToMemory = fn(ffi.types.pointer, {Image, cstring, ffi.types.pointer}),
        -- bool ExportImageAsCode(Image image, const char *fileName);
        ExportImageAsCode = fn(bool, {Image, cstring}),

        -- Image GenImageColor(int width, int height, Color color);
        GenImageColor = fn(Image, {int, int, Color}),
        -- Image GenImageGradientLinear(int width, int height, int direction, Color start, Color end);
        GenImageGradientLinear = fn(Image, {int, int, int, Color, Color}),
        -- Image GenImageGradientRadial(int width, int height, float density, Color inner, Color outer);
        GenImageGradientRadial = fn(Image, {int, int, float, Color, Color}),
        -- Image GenImageGradientSquare(int width, int height, float density, Color inner, Color outer);
        GenImageGradientSquare = fn(Image, {int, int, float, Color, Color}),
        -- Image GenImageChecked(int width, int height, int checksX, int checksY, Color col1, Color col2);
        GenImageChecked = fn(Image, {int, int, int, int, Color, Color}),
        -- Image GenImageWhiteNoise(int width, int height, float factor);
        GenImageWhiteNoise = fn(Image, {int, int, float}),
        -- Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float scale);
        GenImagePerlinNoise = fn(Image, {int, int, int, int, float}),
        -- Image GenImageCellular(int width, int height, int tileSize);
        GenImageCellular = fn(Image, {int, int, int}),
        -- Image GenImageText(int width, int height, const char *text);
        GenImageText = fn(Image, {int, int, cstring}),

        -- Image ImageCopy(Image image);
        ImageCopy = fn(Image, {Image}),
        -- Image ImageFromImage(Image image, Rectangle rec);
        ImageFromImage = fn(Image, {Image, Rectangle}),
        -- Image ImageFromChannel(Image image, int selectedChannel);
        ImageFromChannel = fn(Image, {Image, int}),
        -- Image ImageText(const char *text, int fontSize, Color color);
        ImageText = fn(Image, {cstring, int, Color}),
        -- Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint);
        ImageTextEx = fn(Image, {Font, cstring, float, float, Color}),
        -- void ImageFormat(Image *image, int newFormat);
        ImageFormat = fn(void, {ffi.types.pointer, int}),
        -- void ImageToPOT(Image *image, Color fill);
        ImageToPOT = fn(void, {ffi.types.pointer, Color}),
        -- void ImageCrop(Image *image, Rectangle crop);
        ImageCrop = fn(void, {ffi.types.pointer, Rectangle}),
        -- void ImageAlphaCrop(Image *image, float threshold);
        ImageAlphaCrop = fn(void, {ffi.types.pointer, float}),
        -- void ImageAlphaClear(Image *image, Color color, float threshold);
        ImageAlphaClear = fn(void, {ffi.types.pointer, Color, float}),
        -- void ImageAlphaMask(Image *image, Image alphaMask);
        ImageAlphaMask = fn(void, {ffi.types.pointer, Image}),
        -- void ImageAlphaPremultiply(Image *image);
        ImageAlphaPremultiply = fn(void, {ffi.types.pointer}),
        -- void ImageBlurGaussian(Image *image, int blurSize);
        ImageBlurGaussian = fn(void, {ffi.types.pointer, int}),
        -- void ImageKernelConvolution(Image *image, const float *kernel, int kernelSize);
        ImageKernelConvolution = fn(void, {ffi.types.pointer, ffi.types.pointer, int}),
        -- void ImageResize(Image *image, int newWidth, int newHeight);
        ImageResize = fn(void, {ffi.types.pointer, int, int}),
        -- void ImageResizeNN(Image *image, int newWidth,int newHeight);
        ImageResizeNN = fn(void, {ffi.types.pointer, int, int}),
        -- void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color fill);
        ImageResizeCanvas = fn(void, {ffi.types.pointer, int, int, int, int, Color}),
        -- void ImageMipmaps(Image *image);
        ImageMipmaps = fn(void, {ffi.types.pointer}),
        -- void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp);
        ImageDither = fn(void, {ffi.types.pointer, int, int, int, int}),
        -- void ImageFlipVertical(Image *image);
        ImageFlipVertical = fn(void, {ffi.types.pointer}),
        -- void ImageFlipHorizontal(Image *image);
        ImageFlipHorizontal = fn(void, {ffi.types.pointer}),
        -- void ImageRotate(Image *image, int degrees);
        ImageRotate = fn(void, {ffi.types.pointer, int}),
        -- void ImageRotateCW(Image *image);
        ImageRotateCW = fn(void, {ffi.types.pointer}),
        -- void ImageRotateCCW(Image *image);
        ImageRotateCCW = fn(void, {ffi.types.pointer}),
        -- void ImageColorTint(Image *image, Color color);
        ImageColorTint = fn(void, {ffi.types.pointer, Color}),
        -- void ImageColorInvert(Image *image);
        ImageColorInvert = fn(void, {ffi.types.pointer}),
        -- void ImageColorGrayscale(Image *image);
        ImageColorGrayscale = fn(void, {ffi.types.pointer}),
        -- void ImageColorContrast(Image *image, float contrast);
        ImageColorContrast = fn(void, {ffi.types.pointer, float}),
        -- void ImageColorBrightness(Image *image, int brightness);
        ImageColorBrightness = fn(void, {ffi.types.pointer, int}),
        -- void ImageColorReplace(Image *image, Color color, Color replace);
        ImageColorReplace = fn(void, {ffi.types.pointer, Color, Color}),
        -- Color *LoadImageColors(Image image);
        LoadImageColors = fn(ffi.types.pointer, {Image}),
        -- Color *LoadImagePalette(Image image, int maxPaletteSize, int *colorCount);
        LoadImagePalette = fn(ffi.types.pointer, {Image, int, ffi.types.pointer}),
        -- void UnloadImageColors(Color *colors);
        UnloadImageColors = fn(void, {ffi.types.pointer}),
        -- void UnloadImagePalette(Color *colors);
        UnloadImagePalette = fn(void, {ffi.types.pointer}),
        -- Rectangle GetImageAlphaBorder(Image image, float threshold);
        GetImageAlphaBorder = fn(Rectangle, {Image, float}),
        -- Color GetImageColor(Image image, int x, int y);
        GetImageColor = fn(Color, {Image, int, int}),

        -- void ImageClearBackground(Image *dst, Color color);
        ImageClearBackground = fn(void, {ffi.types.pointer, Color}),
        -- void ImageDrawPixel(Image *dst, int posX, int posY, Color color);
        ImageDrawPixel = fn(void, {ffi.types.pointer, int, int, Color}),
        -- void ImageDrawPixelV(Image *dst, Vector2 position, Color color);
        ImageDrawPixelV = fn(void, {ffi.types.pointer, Vector2, Color}),
        -- void ImageDrawLine(Image *dst, int startPosX, int startPosY, int endPosX, int endPosY, Color color);
        ImageDrawLine = fn(void, {ffi.types.pointer, int, int, int, int, Color}),
        -- void ImageDrawLineV(Image *dst, Vector2 start, Vector2 end, Color color);
        ImageDrawLineV = fn(void, {ffi.types.pointer, Vector2, Vector2, Color}),
        -- void ImageDrawLineEx(Image *dst, Vector2 start, Vector2 end, int thick, Color color);
        ImageDrawLineEx = fn(void, {ffi.types.pointer, Vector2, Vector2, int, Color}),
        -- void ImageDrawCircle(Image *dst, int centerX, int centerY, int radius, Color color);
        ImageDrawCircle = fn(void, {ffi.types.pointer, int, int, int, Color}),
        -- void ImageDrawCircleV(Image *dst, Vector2 center, int radius, Color color);
        ImageDrawCircleV = fn(void, {ffi.types.pointer, Vector2, int, Color}),
        -- void ImageDrawCircleLines(Image *dst, int centerX, int centerY, int radius, Color color);
        ImageDrawCircleLines = fn(void, {ffi.types.pointer, int, int, int, Color}),
        -- void ImageDrawCircleLinesV(Image *dst, Vector2 center, int radius, Color color);
        ImageDrawCircleLinesV = fn(void, {ffi.types.pointer, Vector2, int, Color}),
        -- void ImageDrawRectangle(Image *dst, int posX, int posY, int width, int height, Color color);
        ImageDrawRectangle = fn(void, {ffi.types.pointer, int, int, int, int, Color}),
        -- void ImageDrawRectangleV(Image *dst, Vector2 position, Vector2 size, Color color);
        ImageDrawRectangleV = fn(void, {ffi.types.pointer, Vector2, Vector2, Color}),
        -- void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color);
        ImageDrawRectangleRec = fn(void, {ffi.types.pointer, Rectangle, Color}),
        -- void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color color);
        ImageDrawRectangleLines = fn(void, {ffi.types.pointer, Rectangle, int, Color}),
        -- void ImageDrawTriangle(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color);
        ImageDrawTriangle = fn(void, {ffi.types.pointer, Vector2, Vector2, Vector2, Color}),
        -- void ImageDrawTriangleEx(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3);
        ImageDrawTriangleEx = fn(void, {ffi.types.pointer, Vector2, Vector2, Vector2, Color, Color, Color}),
        -- void ImageDrawTriangleLines(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color);
        ImageDrawTriangleLines = fn(void, {ffi.types.pointer, Vector2, Vector2, Vector2, Color}),
        -- void ImageDrawTriangleFan(Image *dst, Vector2 *points, int pointCount, Color color);
        ImageDrawTriangleFan = fn(void, {ffi.types.pointer, ffi.types.pointer, int, Color}),
        -- void ImageDrawTriangleStrip(Image *dst, Vector2 *points, int pointCount, Color color);
        ImageDrawTriangleStrip = fn(void, {ffi.types.pointer, ffi.types.pointer, int, Color}),
        -- void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint);
        ImageDraw = fn(void, {ffi.types.pointer, Image, Rectangle, Rectangle, Color}),
        -- void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color);
        ImageDrawText = fn(void, {ffi.types.pointer, cstring, int, int, int, Color}),
        -- void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint);
        ImageDrawTextEx = fn(void, {ffi.types.pointer, Font, cstring, Vector2, float, float, Color}),

        -- Texture2D LoadTexture(const char *fileName);
        LoadTexture = fn(Texture2D, {cstring}),
        -- Texture2D LoadTextureFromImage(Image image);
        LoadTextureFromImage = fn(Texture2D, {Image}),
        -- TextureCubemap LoadTextureCubemap(Image image, int layout);
        LoadTextureCubemap = fn(TextureCubemap, {Image, int}),
        -- RenderTexture2D LoadRenderTexture(int width, int height);
        LoadRenderTexture = fn(RenderTexture2D, {int, int}),
        -- bool IsTextureValid(Texture2D texture);
        IsTextureValid = fn(bool, {Texture2D}),
        -- void UnloadTexture(Texture2D texture);
        UnloadTexture = fn(void, {Texture2D}),
        -- bool IsRenderTextureValid(RenderTexture2D target);
        IsRenderTextureValid = fn(bool, {RenderTexture2D}),
        -- void UnloadRenderTexture(RenderTexture2D target);
        UnloadRenderTexture = fn(void, {RenderTexture2D}),
        -- void UpdateTexture(Texture2D texture, const void *pixels);
        UpdateTexture = fn(void, {Texture2D, ffi.types.pointer}),
        -- void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels);
        UpdateTextureRec = fn(void, {Texture2D, Rectangle, ffi.types.pointer}),

        -- void GenTextureMipmaps(Texture2D *texture);
        GenTextureMipmaps = fn(void, {ffi.types.pointer}),
        -- void SetTextureFilter(Texture2D texture, int filter);
        SetTextureFilter = fn(void, {Texture2D, int}),
        -- void SetTextureWrap(Texture2D texture, int wrap);
        SetTextureWrap = fn(void, {Texture2D, int}),

        -- void DrawTexture(Texture2D texture, int posX, int posY, Color tint);
        DrawTexture = fn(void, {Texture2D, int, int, Color}),
        -- void DrawTextureV(Texture2D texture, Vector2 position, Color tint);
        DrawTextureV = fn(void, {Texture2D, Vector2, Color}),
        -- void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint);
        DrawTextureEx = fn(void, {Texture2D, Vector2, float, float, Color}),
        -- void DrawTextureRec(Texture2D texture, Rectangle source, Vector2 position, Color tint);
        DrawTextureRec = fn(void, {Texture2D, Rectangle, Vector2, Color}),
        -- void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, Color tint);
        DrawTexturePro = fn(void, {Texture2D, Rectangle, Rectangle, Vector2, float, Color}),
        -- void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest, Vector2 origin, float rotation, Color tint);
        DrawTextureNPatch = fn(void, {Texture2D, NPatchInfo, Rectangle, Vector2, float, Color}),

        -- bool ColorIsEqual(Color col1, Color col2);
        ColorIsEqual = fn(bool, {Color, Color}),
        -- Color Fade(Color color, float alpha);
        Fade = fn(Color, {Color, float}),
        -- int ColorToInt(Color color);
        ColorToInt = fn(int, {Color}),
        -- Vector4 ColorNormalize(Color color);
        ColorNormalize = fn(Vector4, {Color}),
        -- Color ColorFromNormalized(Vector4 normalized);
        ColorFromNormalized = fn(Color, {Vector4}),
        -- Vector3 ColorToHSV(Color color);
        ColorToHSV = fn(Vector3, {Color}),
        -- Color ColorFromHSV(float hue, float saturation, float value);
        ColorFromHSV = fn(Color, {float, float, float}),
        -- Color ColorTint(Color color, Color tint);
        ColorTint = fn(Color, {Color, Color}),
        -- Color ColorBrightness(Color color, float factor);
        ColorBrightness = fn(Color, {Color, float}),
        -- Color ColorContrast(Color color, float contrast);
        ColorContrast = fn(Color, {Color, float}),
        -- Color ColorAlpha(Color color, float alpha);
        ColorAlpha = fn(Color, {Color, float}),
        -- Color ColorAlphaBlend(Color dst, Color src, Color tint);
        ColorAlphaBlend = fn(Color, {Color, Color, Color}),
        -- Color ColorLerp(Color color1, Color color2, float factor);
        ColorLerp = fn(Color, {Color, Color, float}),
        -- Color GetColor(unsigned int hexValue);
        GetColor = fn(Color, {uint}),
        -- Color GetPixelColor(void *srcPtr, int format);
        GetPixelColor = fn(Color, {ffi.types.pointer, int}),
        -- void SetPixelColor(void *dstPtr, Color color, int format);
        SetPixelColor = fn(void, {ffi.types.pointer, Color, int}),
        -- int GetPixelDataSize(int width, int height, int format);
        GetPixelDataSize = fn(int, {int, int, int}),
    }
}


@attr_1 @attr_2
local function a()
end

local b = @attr_1 @attr_2 function() end

c(@attr_1 @attr_2 function() end)

@attr_1
local function d()
end

local e = @attr_1 function() end

f(@attr_1 function() end)

@attr_1 @attr_2 local function g() end
@attr1 local function h() end

---@doc_comment
@attr_1
local function i() end


const x = 5
const MY_CONST = "hello"
const y: number = 10
const function foo()
	return 1
end


-- Crazy assignment code from AmaranthineCodices
a, b, c.d.e[f][g][1], h:i().j[k]:l()[m] = true, false, 1, 4


a = foo and bar
b = foo and bar or baz
c = 1 + 2 * 3 - 4 ^ 2
d = a + i < b / 2 + 1
e = 5 + x ^ 2 * 8
f = a < y and y <= z
g = -x ^ 2
h = x ^ y ^ z


local num = 0.5
local num2 = 0.5e5
local num3 = .5
local num4 = .5e5
local num5 = 1.


local function foo(a, b) end
local function bar(...) end
local function baz(a, b, ...) end


--[=[
	never have i used these weird equals signs comments
	but im sure someone does
]=]


--[[
local emotes = {
	[":thinking:"] = "http://www.roblox.com/asset/?id=643340245",
	[":bug:"] = "http://www.roblox.com/asset/?id=860037275"
}
]]


--[=[

	This description starts one line down,

	And has a line in the middle, followed by trailing lines.

	```lua
	function test()
		print("indentation")

		do
			print("more indented")
		end
	end
	```

	@class indentation

]=]


local x = [[
local emotes = {
	[":thinking:"] = "http://www.roblox.com/asset/?id=643340245",
	[":bug:"] = "http://www.roblox.com/asset/?id=860037275"
}
]]


for index = 1, 10 do call(index) end
for _ = start, final do end
for _ = 1, 10, 2 do end


--`signatures` the value defaults to zero or is ignored if `signatures.length
--=== 0`. Whenever possible implementors should make an active decision about


local blacklist = {
	["Audio file failed to load (18)."] = true;
	["HTTP 0 (HTTP 429 (HTTP/1.1 429 ProvisionedThroughputExceeded))"] = true;
	["LoadCharacter can only be called when Player is in the world"] = true;
}