//
// This file was autogenerated.
//



RAYLIB_VERSION_MAJOR :: 5;
RAYLIB_VERSION_MINOR :: 5;
RAYLIB_VERSION_PATCH :: 0;
RAYLIB_VERSION :: "5.5";

PI :: 3.14159265358979323846;

DEG2RAD :: PI/180.0;

RAD2DEG :: 180.0/PI;

GetMouseRay :: GetScreenToWorldRay;

EPSILON :: 0.000001;

// Vector2, 2 components
Vector2 :: struct {
    x: float; // Vector x component
    y: float; // Vector y component
}

// Vector3, 3 components
Vector3 :: struct {
    x: float; // Vector x component
    y: float; // Vector y component
    z: float; // Vector z component
}

// Vector4, 4 components
Vector4 :: struct {
    x: float; // Vector x component
    y: float; // Vector y component
    z: float; // Vector z component
    w: float; // Vector w component
}

// Quaternion, 4 components (Vector4 alias)
Quaternion :: Vector4;

// Matrix, 4x4 components, column major, OpenGL style, right-handed
Matrix :: struct {
    m0:  float; // Matrix first row (4 components)
    m4:  float; // Matrix first row (4 components)
    m8:  float; // Matrix first row (4 components)
    m12: float; // Matrix first row (4 components)
    m1:  float; // Matrix second row (4 components)
    m5:  float; // Matrix second row (4 components)
    m9:  float; // Matrix second row (4 components)
    m13: float; // Matrix second row (4 components)
    m2:  float; // Matrix third row (4 components)
    m6:  float; // Matrix third row (4 components)
    m10: float; // Matrix third row (4 components)
    m14: float; // Matrix third row (4 components)
    m3:  float; // Matrix fourth row (4 components)
    m7:  float; // Matrix fourth row (4 components)
    m11: float; // Matrix fourth row (4 components)
    m15: float; // Matrix fourth row (4 components)
}

// Color, 4 components, R8G8B8A8 (32bit)
Color :: struct {
    r: u8; // Color red value
    g: u8; // Color green value
    b: u8; // Color blue value
    a: u8; // Color alpha value
}

// Rectangle, 4 components
Rectangle :: struct {
    x:      float; // Rectangle top-left corner position x
    y:      float; // Rectangle top-left corner position y
    width:  float; // Rectangle width
    height: float; // Rectangle height
}

// Image, pixel data stored in CPU memory (RAM)
Image :: struct {
    data:    *void; // Image raw data
    width:   s32; // Image base width
    height:  s32; // Image base height
    mipmaps: s32; // Mipmap levels, 1 by default
    format:  s32; // Data format (PixelFormat type)
}

// Texture, tex data stored in GPU memory (VRAM)
Texture :: struct {
    id:      u32; // OpenGL texture id
    width:   s32; // Texture base width
    height:  s32; // Texture base height
    mipmaps: s32; // Mipmap levels, 1 by default
    format:  s32; // Data format (PixelFormat type)
}

// Texture2D, same as Texture
Texture2D :: Texture;

// TextureCubemap, same as Texture
TextureCubemap :: Texture;

// RenderTexture, fbo for texture rendering
RenderTexture :: struct {
    id:      u32; // OpenGL framebuffer object id
    texture: Texture; // Color buffer attachment texture
    depth:   Texture; // Depth buffer attachment texture
}

// RenderTexture2D, same as RenderTexture
RenderTexture2D :: RenderTexture;

// NPatchInfo, n-patch layout info
NPatchInfo :: struct {
    source: Rectangle; // Texture source rectangle
    left:   s32; // Left border offset
    top:    s32; // Top border offset
    right:  s32; // Right border offset
    bottom: s32; // Bottom border offset
    layout: s32; // Layout of the n-patch: 3x3, 1x3 or 3x1
}

// GlyphInfo, font characters glyphs info
GlyphInfo :: struct {
    value:    s32; // Character value (Unicode)
    offsetX:  s32; // Character offset X when drawing
    offsetY:  s32; // Character offset Y when drawing
    advanceX: s32; // Character advance position X
    image:    Image; // Character image data
}

// Font, font texture and GlyphInfo array data
Font :: struct {
    baseSize:     s32; // Base size (default chars height)
    glyphCount:   s32; // Number of glyph characters
    glyphPadding: s32; // Padding around the glyph characters
    texture:      Texture2D; // Texture atlas containing the glyphs
    recs:         *Rectangle; // Rectangles in texture for the glyphs
    glyphs:       *GlyphInfo; // Glyphs info data
}

// Camera, defines position/orientation in 3d space
Camera3D :: struct {
    position:   Vector3; // Camera position
    target:     Vector3; // Camera target it looks-at
    up:         Vector3; // Camera up vector (rotation over its axis)
    fovy:       float; // Camera field-of-view aperture in Y (degrees) in perspective, used as near plane width in orthographic
    projection: s32; // Camera projection: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC
}

Camera :: Camera3D;

// Camera2D, defines position/orientation in 2d space
Camera2D :: struct {
    offset:   Vector2; // Camera offset (displacement from target)
    target:   Vector2; // Camera target (rotation and zoom origin)
    rotation: float; // Camera rotation in degrees
    zoom:     float; // Camera zoom (scaling), should be 1.0f by default
}

// Mesh, vertex data and vao/vbo
Mesh :: struct {
    vertexCount:   s32; // Number of vertices stored in arrays
    triangleCount: s32; // Number of triangles stored (indexed or not)

    vertices:      *float; // Vertex position (XYZ - 3 components per vertex) (shader-location = 0)
    texcoords:     *float; // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
    texcoords2:    *float; // Vertex texture second coordinates (UV - 2 components per vertex) (shader-location = 5)
    normals:       *float; // Vertex normals (XYZ - 3 components per vertex) (shader-location = 2)
    tangents:      *float; // Vertex tangents (XYZW - 4 components per vertex) (shader-location = 4)
    colors:        *u8; // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
    indices:       *u16; // Vertex indices (in case vertex data comes indexed)

    animVertices:  *float; // Animated vertex positions (after bones transformations)
    animNormals:   *float; // Animated normals (after bones transformations)
    boneIds:       *u8; // Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning) (shader-location = 6)
    boneWeights:   *float; // Vertex bone weight, up to 4 bones influence by vertex (skinning) (shader-location = 7)
    boneMatrices:  *Matrix; // Bones animated transformation matrices
    boneCount:     s32; // Number of bones

    vaoId:         u32; // OpenGL Vertex Array Object id
    vboId:         *u32; // OpenGL Vertex Buffer Objects id (default vertex data)
}

// Shader
Shader :: struct {
    id:   u32; // Shader program id
    locs: *s32; // Shader locations array (RL_MAX_SHADER_LOCATIONS)
}

// MaterialMap
MaterialMap :: struct {
    texture: Texture2D; // Material map texture
    color:   Color; // Material map color
    value:   float; // Material map value
}

// Material, includes shader and maps
Material :: struct {
    shader: Shader; // Material shader
    maps:   *MaterialMap; // Material maps array (MAX_MATERIAL_MAPS)
    params: [4] float; // Material generic parameters (if required)
}

// Transform, vertex transformation data
Transform :: struct {
    translation: Vector3; // Translation
    rotation:    Quaternion; // Rotation
    scale:       Vector3; // Scale
}

// Bone, skeletal animation bone
BoneInfo :: struct {
    name:   [32] u8; // Bone name
    parent: s32; // Bone parent
}

// Model, meshes, materials and animation data
Model :: struct {
    transform:     Matrix; // Local transform matrix

    meshCount:     s32; // Number of meshes
    materialCount: s32; // Number of materials
    meshes:        *Mesh; // Meshes array
    materials:     *Material; // Materials array
    meshMaterial:  *s32; // Mesh material number

    boneCount:     s32; // Number of bones
    bones:         *BoneInfo; // Bones information (skeleton)
    bindPose:      *Transform; // Bones base transformation (pose)
}

// ModelAnimation
ModelAnimation :: struct {
    boneCount:  s32; // Number of bones
    frameCount: s32; // Number of animation frames
    bones:      *BoneInfo; // Bones information (skeleton)
    framePoses: **Transform; // Poses array by frame
    name:       [32] u8; // Animation name
}

// Ray, ray for raycasting
Ray :: struct {
    position:  Vector3; // Ray position (origin)
    direction: Vector3; // Ray direction (normalized)
}

// RayCollision, ray hit information
RayCollision :: struct {
    hit:      bool; // Did the ray hit something?
    distance: float; // Distance to the nearest hit
    point:    Vector3; // Point of the nearest hit
    normal:   Vector3; // Surface normal of hit
}

// BoundingBox
BoundingBox :: struct {
    min: Vector3; // Minimum vertex box-corner
    max: Vector3; // Maximum vertex box-corner
}

// Wave, audio wave data
Wave :: struct {
    frameCount: u32; // Total number of frames (considering channels)
    sampleRate: u32; // Frequency (samples per second)
    sampleSize: u32; // Bit depth (bits per sample): 8, 16, 32 (24 not supported)
    channels:   u32; // Number of channels (1-mono, 2-stereo, ...)
    data:       *void; // Buffer data pointer
}

rAudioBuffer :: struct {}
rAudioProcessor :: struct {}

// AudioStream, custom audio stream
AudioStream :: struct {
    buffer:     *rAudioBuffer; // Pointer to internal data used by the audio system
    processor:  *rAudioProcessor; // Pointer to internal data processor, useful for audio effects

    sampleRate: u32; // Frequency (samples per second)
    sampleSize: u32; // Bit depth (bits per sample): 8, 16, 32 (24 not supported)
    channels:   u32; // Number of channels (1-mono, 2-stereo, ...)
}

// Sound
Sound :: struct {
    stream:     AudioStream; // Audio stream
    frameCount: u32; // Total number of frames (considering channels)
}

// Music, audio stream, anything longer than ~10 seconds should be streamed
Music :: struct {
    stream:     AudioStream; // Audio stream
    frameCount: u32; // Total number of frames (considering channels)
    looping:    bool; // Music looping enable

    ctxType:    s32; // Type of music context (audio filetype)
    ctxData:    *void; // Audio context data, depends on type
}

// VrDeviceInfo, Head-Mounted-Display device parameters
VrDeviceInfo :: struct {
    hResolution:            s32; // Horizontal resolution in pixels
    vResolution:            s32; // Vertical resolution in pixels
    hScreenSize:            float; // Horizontal size in meters
    vScreenSize:            float; // Vertical size in meters
    eyeToScreenDistance:    float; // Distance between eye and display in meters
    lensSeparationDistance: float; // Lens separation distance in meters
    interpupillaryDistance: float; // IPD (distance between pupils) in meters
    lensDistortionValues:   [4] float; // Lens distortion constant parameters
    chromaAbCorrection:     [4] float; // Chromatic aberration correction parameters
}

// VrStereoConfig, VR stereo rendering configuration for simulator
VrStereoConfig :: struct {
    projection:        [2] Matrix; // VR projection matrices (per eye)
    viewOffset:        [2] Matrix; // VR view offset matrices (per eye)
    leftLensCenter:    [2] float; // VR left lens center
    rightLensCenter:   [2] float; // VR right lens center
    leftScreenCenter:  [2] float; // VR left screen center
    rightScreenCenter: [2] float; // VR right screen center
    scale:             [2] float; // VR distortion scale
    scaleIn:           [2] float; // VR distortion scale in
}

// File path list
FilePathList :: struct {
    capacity: u32; // Filepaths max entries
    count:    u32; // Filepaths entries count
    paths:    **u8; // Filepaths entries
}

// Automation event
AutomationEvent :: struct {
    frame:  u32; // Event frame
    type:   u32; // Event type (AutomationEventType)
    params: [4] s32; // Event parameters (if required)
}

// Automation event list
AutomationEventList :: struct {
    capacity: u32; // Events max entries (MAX_AUTOMATION_EVENTS)
    count:    u32; // Events entries count
    events:   *AutomationEvent; // Events entries
}

//----------------------------------------------------------------------------------
// Enumerators Definition
//----------------------------------------------------------------------------------
// System/Window config flags
// NOTE: Every bit registers one state (use it with bit masks)
// By default all flags are set to 0
ConfigFlags :: enum u32 {
    VSYNC_HINT               :: 64;
    FULLSCREEN_MODE          :: 2;
    WINDOW_RESIZABLE         :: 4;
    WINDOW_UNDECORATED       :: 8;
    WINDOW_HIDDEN            :: 128;
    WINDOW_MINIMIZED         :: 512;
    WINDOW_MAXIMIZED         :: 1024;
    WINDOW_UNFOCUSED         :: 2048;
    WINDOW_TOPMOST           :: 4096;
    WINDOW_ALWAYS_RUN        :: 256;
    WINDOW_TRANSPARENT       :: 16;
    WINDOW_HIGHDPI           :: 8192;
    WINDOW_MOUSE_PASSTHROUGH :: 16384;
    BORDERLESS_WINDOWED_MODE :: 32768;
    MSAA_4X_HINT             :: 32;
    INTERLACED_HINT          :: 65536;

    FLAG_VSYNC_HINT               :: VSYNC_HINT;
    FLAG_FULLSCREEN_MODE          :: FULLSCREEN_MODE;
    FLAG_WINDOW_RESIZABLE         :: WINDOW_RESIZABLE;
    FLAG_WINDOW_UNDECORATED       :: WINDOW_UNDECORATED;
    FLAG_WINDOW_HIDDEN            :: WINDOW_HIDDEN;
    FLAG_WINDOW_MINIMIZED         :: WINDOW_MINIMIZED;
    FLAG_WINDOW_MAXIMIZED         :: WINDOW_MAXIMIZED;
    FLAG_WINDOW_UNFOCUSED         :: WINDOW_UNFOCUSED;
    FLAG_WINDOW_TOPMOST           :: WINDOW_TOPMOST;
    FLAG_WINDOW_ALWAYS_RUN        :: WINDOW_ALWAYS_RUN;
    FLAG_WINDOW_TRANSPARENT       :: WINDOW_TRANSPARENT;
    FLAG_WINDOW_HIGHDPI           :: WINDOW_HIGHDPI;
    FLAG_WINDOW_MOUSE_PASSTHROUGH :: WINDOW_MOUSE_PASSTHROUGH;
    FLAG_BORDERLESS_WINDOWED_MODE :: BORDERLESS_WINDOWED_MODE;
    FLAG_MSAA_4X_HINT             :: MSAA_4X_HINT;
    FLAG_INTERLACED_HINT          :: INTERLACED_HINT;
}

// Trace log level
// NOTE: Organized by priority level
TraceLogLevel :: enum u32 {
    ALL     :: 0;
    TRACE   :: 1;
    DEBUG   :: 2;
    INFO    :: 3;
    WARNING :: 4;
    ERROR   :: 5;
    FATAL   :: 6;
    NONE    :: 7;

    LOG_ALL     :: ALL;
    LOG_TRACE   :: TRACE;
    LOG_DEBUG   :: DEBUG;
    LOG_INFO    :: INFO;
    LOG_WARNING :: WARNING;
    LOG_ERROR   :: ERROR;
    LOG_FATAL   :: FATAL;
    LOG_NONE    :: NONE;
}

// Keyboard keys (US keyboard layout)
// NOTE: Use GetKeyPressed() to allow redefining
// required keys for alternative layouts
KeyboardKey :: enum u32 {
    NULL          :: 0;

    APOSTROPHE    :: 39;
    COMMA         :: 44;
    MINUS         :: 45;
    PERIOD        :: 46;
    SLASH         :: 47;
    ZERO          :: 48;
    ONE           :: 49;
    TWO           :: 50;
    THREE         :: 51;
    FOUR          :: 52;
    FIVE          :: 53;
    SIX           :: 54;
    SEVEN         :: 55;
    EIGHT         :: 56;
    NINE          :: 57;
    SEMICOLON     :: 59;
    EQUAL         :: 61;
    A             :: 65;
    B             :: 66;
    C             :: 67;
    D             :: 68;
    E             :: 69;
    F             :: 70;
    G             :: 71;
    H             :: 72;
    I             :: 73;
    J             :: 74;
    K             :: 75;
    L             :: 76;
    M             :: 77;
    N             :: 78;
    O             :: 79;
    P             :: 80;
    Q             :: 81;
    R             :: 82;
    S             :: 83;
    T             :: 84;
    U             :: 85;
    V             :: 86;
    W             :: 87;
    X             :: 88;
    Y             :: 89;
    Z             :: 90;
    LEFT_BRACKET  :: 91;
    BACKSLASH     :: 92;
    RIGHT_BRACKET :: 93;
    GRAVE         :: 96;

    SPACE         :: 32;
    ESCAPE        :: 256;
    ENTER         :: 257;
    TAB           :: 258;
    BACKSPACE     :: 259;
    INSERT        :: 260;
    DELETE        :: 261;
    RIGHT         :: 262;
    LEFT          :: 263;
    DOWN          :: 264;
    UP            :: 265;
    PAGE_UP       :: 266;
    PAGE_DOWN     :: 267;
    HOME          :: 268;
    END           :: 269;
    CAPS_LOCK     :: 280;
    SCROLL_LOCK   :: 281;
    NUM_LOCK      :: 282;
    PRINT_SCREEN  :: 283;
    PAUSE         :: 284;
    F1            :: 290;
    F2            :: 291;
    F3            :: 292;
    F4            :: 293;
    F5            :: 294;
    F6            :: 295;
    F7            :: 296;
    F8            :: 297;
    F9            :: 298;
    F10           :: 299;
    F11           :: 300;
    F12           :: 301;
    LEFT_SHIFT    :: 340;
    LEFT_CONTROL  :: 341;
    LEFT_ALT      :: 342;
    LEFT_SUPER    :: 343;
    RIGHT_SHIFT   :: 344;
    RIGHT_CONTROL :: 345;
    RIGHT_ALT     :: 346;
    RIGHT_SUPER   :: 347;
    KB_MENU       :: 348;

    KP_0          :: 320;
    KP_1          :: 321;
    KP_2          :: 322;
    KP_3          :: 323;
    KP_4          :: 324;
    KP_5          :: 325;
    KP_6          :: 326;
    KP_7          :: 327;
    KP_8          :: 328;
    KP_9          :: 329;
    KP_DECIMAL    :: 330;
    KP_DIVIDE     :: 331;
    KP_MULTIPLY   :: 332;
    KP_SUBTRACT   :: 333;
    KP_ADD        :: 334;
    KP_ENTER      :: 335;
    KP_EQUAL      :: 336;

    BACK          :: 4;
    MENU          :: 5;
    VOLUME_UP     :: 24;
    VOLUME_DOWN   :: 25;

    KEY_NULL          :: NULL;

    KEY_APOSTROPHE    :: APOSTROPHE;
    KEY_COMMA         :: COMMA;
    KEY_MINUS         :: MINUS;
    KEY_PERIOD        :: PERIOD;
    KEY_SLASH         :: SLASH;
    KEY_ZERO          :: ZERO;
    KEY_ONE           :: ONE;
    KEY_TWO           :: TWO;
    KEY_THREE         :: THREE;
    KEY_FOUR          :: FOUR;
    KEY_FIVE          :: FIVE;
    KEY_SIX           :: SIX;
    KEY_SEVEN         :: SEVEN;
    KEY_EIGHT         :: EIGHT;
    KEY_NINE          :: NINE;
    KEY_SEMICOLON     :: SEMICOLON;
    KEY_EQUAL         :: EQUAL;
    KEY_A             :: A;
    KEY_B             :: B;
    KEY_C             :: C;
    KEY_D             :: D;
    KEY_E             :: E;
    KEY_F             :: F;
    KEY_G             :: G;
    KEY_H             :: H;
    KEY_I             :: I;
    KEY_J             :: J;
    KEY_K             :: K;
    KEY_L             :: L;
    KEY_M             :: M;
    KEY_N             :: N;
    KEY_O             :: O;
    KEY_P             :: P;
    KEY_Q             :: Q;
    KEY_R             :: R;
    KEY_S             :: S;
    KEY_T             :: T;
    KEY_U             :: U;
    KEY_V             :: V;
    KEY_W             :: W;
    KEY_X             :: X;
    KEY_Y             :: Y;
    KEY_Z             :: Z;
    KEY_LEFT_BRACKET  :: LEFT_BRACKET;
    KEY_BACKSLASH     :: BACKSLASH;
    KEY_RIGHT_BRACKET :: RIGHT_BRACKET;
    KEY_GRAVE         :: GRAVE;

    KEY_SPACE         :: SPACE;
    KEY_ESCAPE        :: ESCAPE;
    KEY_ENTER         :: ENTER;
    KEY_TAB           :: TAB;
    KEY_BACKSPACE     :: BACKSPACE;
    KEY_INSERT        :: INSERT;
    KEY_DELETE        :: DELETE;
    KEY_RIGHT         :: RIGHT;
    KEY_LEFT          :: LEFT;
    KEY_DOWN          :: DOWN;
    KEY_UP            :: UP;
    KEY_PAGE_UP       :: PAGE_UP;
    KEY_PAGE_DOWN     :: PAGE_DOWN;
    KEY_HOME          :: HOME;
    KEY_END           :: END;
    KEY_CAPS_LOCK     :: CAPS_LOCK;
    KEY_SCROLL_LOCK   :: SCROLL_LOCK;
    KEY_NUM_LOCK      :: NUM_LOCK;
    KEY_PRINT_SCREEN  :: PRINT_SCREEN;
    KEY_PAUSE         :: PAUSE;
    KEY_F1            :: F1;
    KEY_F2            :: F2;
    KEY_F3            :: F3;
    KEY_F4            :: F4;
    KEY_F5            :: F5;
    KEY_F6            :: F6;
    KEY_F7            :: F7;
    KEY_F8            :: F8;
    KEY_F9            :: F9;
    KEY_F10           :: F10;
    KEY_F11           :: F11;
    KEY_F12           :: F12;
    KEY_LEFT_SHIFT    :: LEFT_SHIFT;
    KEY_LEFT_CONTROL  :: LEFT_CONTROL;
    KEY_LEFT_ALT      :: LEFT_ALT;
    KEY_LEFT_SUPER    :: LEFT_SUPER;
    KEY_RIGHT_SHIFT   :: RIGHT_SHIFT;
    KEY_RIGHT_CONTROL :: RIGHT_CONTROL;
    KEY_RIGHT_ALT     :: RIGHT_ALT;
    KEY_RIGHT_SUPER   :: RIGHT_SUPER;
    KEY_KB_MENU       :: KB_MENU;

    KEY_KP_0          :: KP_0;
    KEY_KP_1          :: KP_1;
    KEY_KP_2          :: KP_2;
    KEY_KP_3          :: KP_3;
    KEY_KP_4          :: KP_4;
    KEY_KP_5          :: KP_5;
    KEY_KP_6          :: KP_6;
    KEY_KP_7          :: KP_7;
    KEY_KP_8          :: KP_8;
    KEY_KP_9          :: KP_9;
    KEY_KP_DECIMAL    :: KP_DECIMAL;
    KEY_KP_DIVIDE     :: KP_DIVIDE;
    KEY_KP_MULTIPLY   :: KP_MULTIPLY;
    KEY_KP_SUBTRACT   :: KP_SUBTRACT;
    KEY_KP_ADD        :: KP_ADD;
    KEY_KP_ENTER      :: KP_ENTER;
    KEY_KP_EQUAL      :: KP_EQUAL;

    KEY_BACK          :: BACK;
    KEY_MENU          :: MENU;
    KEY_VOLUME_UP     :: VOLUME_UP;
    KEY_VOLUME_DOWN   :: VOLUME_DOWN;
}

// Mouse buttons
MouseButton :: enum u32 {
    LEFT    :: 0;
    RIGHT   :: 1;
    MIDDLE  :: 2;
    SIDE    :: 3;
    EXTRA   :: 4;
    FORWARD :: 5;
    BACK    :: 6;

    MOUSE_BUTTON_LEFT    :: LEFT;
    MOUSE_BUTTON_RIGHT   :: RIGHT;
    MOUSE_BUTTON_MIDDLE  :: MIDDLE;
    MOUSE_BUTTON_SIDE    :: SIDE;
    MOUSE_BUTTON_EXTRA   :: EXTRA;
    MOUSE_BUTTON_FORWARD :: FORWARD;
    MOUSE_BUTTON_BACK    :: BACK;
}

// Mouse cursor
MouseCursor :: enum u32 {
    DEFAULT       :: 0;
    ARROW         :: 1;
    IBEAM         :: 2;
    CROSSHAIR     :: 3;
    POINTING_HAND :: 4;
    RESIZE_EW     :: 5;
    RESIZE_NS     :: 6;
    RESIZE_NWSE   :: 7;
    RESIZE_NESW   :: 8;
    RESIZE_ALL    :: 9;
    NOT_ALLOWED   :: 10;

    MOUSE_CURSOR_DEFAULT       :: DEFAULT;
    MOUSE_CURSOR_ARROW         :: ARROW;
    MOUSE_CURSOR_IBEAM         :: IBEAM;
    MOUSE_CURSOR_CROSSHAIR     :: CROSSHAIR;
    MOUSE_CURSOR_POINTING_HAND :: POINTING_HAND;
    MOUSE_CURSOR_RESIZE_EW     :: RESIZE_EW;
    MOUSE_CURSOR_RESIZE_NS     :: RESIZE_NS;
    MOUSE_CURSOR_RESIZE_NWSE   :: RESIZE_NWSE;
    MOUSE_CURSOR_RESIZE_NESW   :: RESIZE_NESW;
    MOUSE_CURSOR_RESIZE_ALL    :: RESIZE_ALL;
    MOUSE_CURSOR_NOT_ALLOWED   :: NOT_ALLOWED;
}

// Gamepad buttons
GamepadButton :: enum u32 {
    UNKNOWN          :: 0;
    LEFT_FACE_UP     :: 1;
    LEFT_FACE_RIGHT  :: 2;
    LEFT_FACE_DOWN   :: 3;
    LEFT_FACE_LEFT   :: 4;
    RIGHT_FACE_UP    :: 5;
    RIGHT_FACE_RIGHT :: 6;
    RIGHT_FACE_DOWN  :: 7;
    RIGHT_FACE_LEFT  :: 8;
    LEFT_TRIGGER_1   :: 9;
    LEFT_TRIGGER_2   :: 10;
    RIGHT_TRIGGER_1  :: 11;
    RIGHT_TRIGGER_2  :: 12;
    MIDDLE_LEFT      :: 13;
    MIDDLE           :: 14;
    MIDDLE_RIGHT     :: 15;
    LEFT_THUMB       :: 16;
    RIGHT_THUMB      :: 17;

    GAMEPAD_BUTTON_UNKNOWN          :: UNKNOWN;
    GAMEPAD_BUTTON_LEFT_FACE_UP     :: LEFT_FACE_UP;
    GAMEPAD_BUTTON_LEFT_FACE_RIGHT  :: LEFT_FACE_RIGHT;
    GAMEPAD_BUTTON_LEFT_FACE_DOWN   :: LEFT_FACE_DOWN;
    GAMEPAD_BUTTON_LEFT_FACE_LEFT   :: LEFT_FACE_LEFT;
    GAMEPAD_BUTTON_RIGHT_FACE_UP    :: RIGHT_FACE_UP;
    GAMEPAD_BUTTON_RIGHT_FACE_RIGHT :: RIGHT_FACE_RIGHT;
    GAMEPAD_BUTTON_RIGHT_FACE_DOWN  :: RIGHT_FACE_DOWN;
    GAMEPAD_BUTTON_RIGHT_FACE_LEFT  :: RIGHT_FACE_LEFT;
    GAMEPAD_BUTTON_LEFT_TRIGGER_1   :: LEFT_TRIGGER_1;
    GAMEPAD_BUTTON_LEFT_TRIGGER_2   :: LEFT_TRIGGER_2;
    GAMEPAD_BUTTON_RIGHT_TRIGGER_1  :: RIGHT_TRIGGER_1;
    GAMEPAD_BUTTON_RIGHT_TRIGGER_2  :: RIGHT_TRIGGER_2;
    GAMEPAD_BUTTON_MIDDLE_LEFT      :: MIDDLE_LEFT;
    GAMEPAD_BUTTON_MIDDLE           :: MIDDLE;
    GAMEPAD_BUTTON_MIDDLE_RIGHT     :: MIDDLE_RIGHT;
    GAMEPAD_BUTTON_LEFT_THUMB       :: LEFT_THUMB;
    GAMEPAD_BUTTON_RIGHT_THUMB      :: RIGHT_THUMB;
}

// Gamepad axis
GamepadAxis :: enum u32 {
    LEFT_X        :: 0;
    LEFT_Y        :: 1;
    RIGHT_X       :: 2;
    RIGHT_Y       :: 3;
    LEFT_TRIGGER  :: 4;
    RIGHT_TRIGGER :: 5;

    GAMEPAD_AXIS_LEFT_X        :: LEFT_X;
    GAMEPAD_AXIS_LEFT_Y        :: LEFT_Y;
    GAMEPAD_AXIS_RIGHT_X       :: RIGHT_X;
    GAMEPAD_AXIS_RIGHT_Y       :: RIGHT_Y;
    GAMEPAD_AXIS_LEFT_TRIGGER  :: LEFT_TRIGGER;
    GAMEPAD_AXIS_RIGHT_TRIGGER :: RIGHT_TRIGGER;
}

// Material map index
MaterialMapIndex :: enum u32 {
    ALBEDO     :: 0;
    METALNESS  :: 1;
    NORMAL     :: 2;
    ROUGHNESS  :: 3;
    OCCLUSION  :: 4;
    EMISSION   :: 5;
    HEIGHT     :: 6;
    CUBEMAP    :: 7;
    IRRADIANCE :: 8;
    PREFILTER  :: 9;
    BRDF       :: 10;

    MATERIAL_MAP_ALBEDO     :: ALBEDO;
    MATERIAL_MAP_METALNESS  :: METALNESS;
    MATERIAL_MAP_NORMAL     :: NORMAL;
    MATERIAL_MAP_ROUGHNESS  :: ROUGHNESS;
    MATERIAL_MAP_OCCLUSION  :: OCCLUSION;
    MATERIAL_MAP_EMISSION   :: EMISSION;
    MATERIAL_MAP_HEIGHT     :: HEIGHT;
    MATERIAL_MAP_CUBEMAP    :: CUBEMAP;
    MATERIAL_MAP_IRRADIANCE :: IRRADIANCE;
    MATERIAL_MAP_PREFILTER  :: PREFILTER;
    MATERIAL_MAP_BRDF       :: BRDF;
}

// Shader location index
ShaderLocationIndex :: enum u32 {
    VERTEX_POSITION    :: 0;
    VERTEX_TEXCOORD01  :: 1;
    VERTEX_TEXCOORD02  :: 2;
    VERTEX_NORMAL      :: 3;
    VERTEX_TANGENT     :: 4;
    VERTEX_COLOR       :: 5;
    MATRIX_MVP         :: 6;
    MATRIX_VIEW        :: 7;
    MATRIX_PROJECTION  :: 8;
    MATRIX_MODEL       :: 9;
    MATRIX_NORMAL      :: 10;
    VECTOR_VIEW        :: 11;
    COLOR_DIFFUSE      :: 12;
    COLOR_SPECULAR     :: 13;
    COLOR_AMBIENT      :: 14;
    MAP_ALBEDO         :: 15;
    MAP_METALNESS      :: 16;
    MAP_NORMAL         :: 17;
    MAP_ROUGHNESS      :: 18;
    MAP_OCCLUSION      :: 19;
    MAP_EMISSION       :: 20;
    MAP_HEIGHT         :: 21;
    MAP_CUBEMAP        :: 22;
    MAP_IRRADIANCE     :: 23;
    MAP_PREFILTER      :: 24;
    MAP_BRDF           :: 25;
    VERTEX_BONEIDS     :: 26;
    VERTEX_BONEWEIGHTS :: 27;
    BONE_MATRICES      :: 28;

    SHADER_LOC_VERTEX_POSITION    :: VERTEX_POSITION;
    SHADER_LOC_VERTEX_TEXCOORD01  :: VERTEX_TEXCOORD01;
    SHADER_LOC_VERTEX_TEXCOORD02  :: VERTEX_TEXCOORD02;
    SHADER_LOC_VERTEX_NORMAL      :: VERTEX_NORMAL;
    SHADER_LOC_VERTEX_TANGENT     :: VERTEX_TANGENT;
    SHADER_LOC_VERTEX_COLOR       :: VERTEX_COLOR;
    SHADER_LOC_MATRIX_MVP         :: MATRIX_MVP;
    SHADER_LOC_MATRIX_VIEW        :: MATRIX_VIEW;
    SHADER_LOC_MATRIX_PROJECTION  :: MATRIX_PROJECTION;
    SHADER_LOC_MATRIX_MODEL       :: MATRIX_MODEL;
    SHADER_LOC_MATRIX_NORMAL      :: MATRIX_NORMAL;
    SHADER_LOC_VECTOR_VIEW        :: VECTOR_VIEW;
    SHADER_LOC_COLOR_DIFFUSE      :: COLOR_DIFFUSE;
    SHADER_LOC_COLOR_SPECULAR     :: COLOR_SPECULAR;
    SHADER_LOC_COLOR_AMBIENT      :: COLOR_AMBIENT;
    SHADER_LOC_MAP_ALBEDO         :: MAP_ALBEDO;
    SHADER_LOC_MAP_METALNESS      :: MAP_METALNESS;
    SHADER_LOC_MAP_NORMAL         :: MAP_NORMAL;
    SHADER_LOC_MAP_ROUGHNESS      :: MAP_ROUGHNESS;
    SHADER_LOC_MAP_OCCLUSION      :: MAP_OCCLUSION;
    SHADER_LOC_MAP_EMISSION       :: MAP_EMISSION;
    SHADER_LOC_MAP_HEIGHT         :: MAP_HEIGHT;
    SHADER_LOC_MAP_CUBEMAP        :: MAP_CUBEMAP;
    SHADER_LOC_MAP_IRRADIANCE     :: MAP_IRRADIANCE;
    SHADER_LOC_MAP_PREFILTER      :: MAP_PREFILTER;
    SHADER_LOC_MAP_BRDF           :: MAP_BRDF;
    SHADER_LOC_VERTEX_BONEIDS     :: VERTEX_BONEIDS;
    SHADER_LOC_VERTEX_BONEWEIGHTS :: VERTEX_BONEWEIGHTS;
    SHADER_LOC_BONE_MATRICES      :: BONE_MATRICES;
}

// Shader uniform data type
ShaderUniformDataType :: enum u32 {
    FLOAT     :: 0;
    VEC2      :: 1;
    VEC3      :: 2;
    VEC4      :: 3;
    INT       :: 4;
    IVEC2     :: 5;
    IVEC3     :: 6;
    IVEC4     :: 7;
    SAMPLER2D :: 8;

    SHADER_UNIFORM_FLOAT     :: FLOAT;
    SHADER_UNIFORM_VEC2      :: VEC2;
    SHADER_UNIFORM_VEC3      :: VEC3;
    SHADER_UNIFORM_VEC4      :: VEC4;
    SHADER_UNIFORM_INT       :: INT;
    SHADER_UNIFORM_IVEC2     :: IVEC2;
    SHADER_UNIFORM_IVEC3     :: IVEC3;
    SHADER_UNIFORM_IVEC4     :: IVEC4;
    SHADER_UNIFORM_SAMPLER2D :: SAMPLER2D;
}

// Shader attribute data types
ShaderAttributeDataType :: enum u32 {
    FLOAT :: 0;
    VEC2  :: 1;
    VEC3  :: 2;
    VEC4  :: 3;

    SHADER_ATTRIB_FLOAT :: FLOAT;
    SHADER_ATTRIB_VEC2  :: VEC2;
    SHADER_ATTRIB_VEC3  :: VEC3;
    SHADER_ATTRIB_VEC4  :: VEC4;
}

// Pixel formats
// NOTE: Support depends on OpenGL version and platform
PixelFormat :: enum u32 {
    UNCOMPRESSED_GRAYSCALE    :: 1;
    UNCOMPRESSED_GRAY_ALPHA   :: 2;
    UNCOMPRESSED_R5G6B5       :: 3;
    UNCOMPRESSED_R8G8B8       :: 4;
    UNCOMPRESSED_R5G5B5A1     :: 5;
    UNCOMPRESSED_R4G4B4A4     :: 6;
    UNCOMPRESSED_R8G8B8A8     :: 7;
    UNCOMPRESSED_R32          :: 8;
    UNCOMPRESSED_R32G32B32    :: 9;
    UNCOMPRESSED_R32G32B32A32 :: 10;
    UNCOMPRESSED_R16          :: 11;
    UNCOMPRESSED_R16G16B16    :: 12;
    UNCOMPRESSED_R16G16B16A16 :: 13;
    COMPRESSED_DXT1_RGB       :: 14;
    COMPRESSED_DXT1_RGBA      :: 15;
    COMPRESSED_DXT3_RGBA      :: 16;
    COMPRESSED_DXT5_RGBA      :: 17;
    COMPRESSED_ETC1_RGB       :: 18;
    COMPRESSED_ETC2_RGB       :: 19;
    COMPRESSED_ETC2_EAC_RGBA  :: 20;
    COMPRESSED_PVRT_RGB       :: 21;
    COMPRESSED_PVRT_RGBA      :: 22;
    COMPRESSED_ASTC_4x4_RGBA  :: 23;
    COMPRESSED_ASTC_8x8_RGBA  :: 24;

    PIXELFORMAT_UNCOMPRESSED_GRAYSCALE    :: UNCOMPRESSED_GRAYSCALE;
    PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA   :: UNCOMPRESSED_GRAY_ALPHA;
    PIXELFORMAT_UNCOMPRESSED_R5G6B5       :: UNCOMPRESSED_R5G6B5;
    PIXELFORMAT_UNCOMPRESSED_R8G8B8       :: UNCOMPRESSED_R8G8B8;
    PIXELFORMAT_UNCOMPRESSED_R5G5B5A1     :: UNCOMPRESSED_R5G5B5A1;
    PIXELFORMAT_UNCOMPRESSED_R4G4B4A4     :: UNCOMPRESSED_R4G4B4A4;
    PIXELFORMAT_UNCOMPRESSED_R8G8B8A8     :: UNCOMPRESSED_R8G8B8A8;
    PIXELFORMAT_UNCOMPRESSED_R32          :: UNCOMPRESSED_R32;
    PIXELFORMAT_UNCOMPRESSED_R32G32B32    :: UNCOMPRESSED_R32G32B32;
    PIXELFORMAT_UNCOMPRESSED_R32G32B32A32 :: UNCOMPRESSED_R32G32B32A32;
    PIXELFORMAT_UNCOMPRESSED_R16          :: UNCOMPRESSED_R16;
    PIXELFORMAT_UNCOMPRESSED_R16G16B16    :: UNCOMPRESSED_R16G16B16;
    PIXELFORMAT_UNCOMPRESSED_R16G16B16A16 :: UNCOMPRESSED_R16G16B16A16;
    PIXELFORMAT_COMPRESSED_DXT1_RGB       :: COMPRESSED_DXT1_RGB;
    PIXELFORMAT_COMPRESSED_DXT1_RGBA      :: COMPRESSED_DXT1_RGBA;
    PIXELFORMAT_COMPRESSED_DXT3_RGBA      :: COMPRESSED_DXT3_RGBA;
    PIXELFORMAT_COMPRESSED_DXT5_RGBA      :: COMPRESSED_DXT5_RGBA;
    PIXELFORMAT_COMPRESSED_ETC1_RGB       :: COMPRESSED_ETC1_RGB;
    PIXELFORMAT_COMPRESSED_ETC2_RGB       :: COMPRESSED_ETC2_RGB;
    PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA  :: COMPRESSED_ETC2_EAC_RGBA;
    PIXELFORMAT_COMPRESSED_PVRT_RGB       :: COMPRESSED_PVRT_RGB;
    PIXELFORMAT_COMPRESSED_PVRT_RGBA      :: COMPRESSED_PVRT_RGBA;
    PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA  :: COMPRESSED_ASTC_4x4_RGBA;
    PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA  :: COMPRESSED_ASTC_8x8_RGBA;
}

// Texture parameters: filter mode
// NOTE 1: Filtering considers mipmaps if available in the texture
// NOTE 2: Filter is accordingly set for minification and magnification
TextureFilter :: enum u32 {
    POINT           :: 0;
    BILINEAR        :: 1;
    TRILINEAR       :: 2;
    ANISOTROPIC_4X  :: 3;
    ANISOTROPIC_8X  :: 4;
    ANISOTROPIC_16X :: 5;

    TEXTURE_FILTER_POINT           :: POINT;
    TEXTURE_FILTER_BILINEAR        :: BILINEAR;
    TEXTURE_FILTER_TRILINEAR       :: TRILINEAR;
    TEXTURE_FILTER_ANISOTROPIC_4X  :: ANISOTROPIC_4X;
    TEXTURE_FILTER_ANISOTROPIC_8X  :: ANISOTROPIC_8X;
    TEXTURE_FILTER_ANISOTROPIC_16X :: ANISOTROPIC_16X;
}

// Texture parameters: wrap mode
TextureWrap :: enum u32 {
    REPEAT        :: 0;
    CLAMP         :: 1;
    MIRROR_REPEAT :: 2;
    MIRROR_CLAMP  :: 3;

    TEXTURE_WRAP_REPEAT        :: REPEAT;
    TEXTURE_WRAP_CLAMP         :: CLAMP;
    TEXTURE_WRAP_MIRROR_REPEAT :: MIRROR_REPEAT;
    TEXTURE_WRAP_MIRROR_CLAMP  :: MIRROR_CLAMP;
}

// Cubemap layouts
CubemapLayout :: enum u32 {
    AUTO_DETECT         :: 0;
    LINE_VERTICAL       :: 1;
    LINE_HORIZONTAL     :: 2;
    CROSS_THREE_BY_FOUR :: 3;
    CROSS_FOUR_BY_THREE :: 4;

    CUBEMAP_LAYOUT_AUTO_DETECT         :: AUTO_DETECT;
    CUBEMAP_LAYOUT_LINE_VERTICAL       :: LINE_VERTICAL;
    CUBEMAP_LAYOUT_LINE_HORIZONTAL     :: LINE_HORIZONTAL;
    CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR :: CROSS_THREE_BY_FOUR;
    CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE :: CROSS_FOUR_BY_THREE;
}

// Font type, defines generation method
FontType :: enum u32 {
    DEFAULT :: 0;
    BITMAP  :: 1;
    SDF     :: 2;

    FONT_DEFAULT :: DEFAULT;
    FONT_BITMAP  :: BITMAP;
    FONT_SDF     :: SDF;
}

// Color blending modes (pre-defined)
BlendMode :: enum u32 {
    ALPHA             :: 0;
    ADDITIVE          :: 1;
    MULTIPLIED        :: 2;
    ADD_COLORS        :: 3;
    SUBTRACT_COLORS   :: 4;
    ALPHA_PREMULTIPLY :: 5;
    CUSTOM            :: 6;
    CUSTOM_SEPARATE   :: 7;

    BLEND_ALPHA             :: ALPHA;
    BLEND_ADDITIVE          :: ADDITIVE;
    BLEND_MULTIPLIED        :: MULTIPLIED;
    BLEND_ADD_COLORS        :: ADD_COLORS;
    BLEND_SUBTRACT_COLORS   :: SUBTRACT_COLORS;
    BLEND_ALPHA_PREMULTIPLY :: ALPHA_PREMULTIPLY;
    BLEND_CUSTOM            :: CUSTOM;
    BLEND_CUSTOM_SEPARATE   :: CUSTOM_SEPARATE;
}

// Gesture
// NOTE: Provided as bit-wise flags to enable only desired gestures
Gesture :: enum u32 {
    NONE        :: 0;
    TAP         :: 1;
    DOUBLETAP   :: 2;
    HOLD        :: 4;
    DRAG        :: 8;
    SWIPE_RIGHT :: 16;
    SWIPE_LEFT  :: 32;
    SWIPE_UP    :: 64;
    SWIPE_DOWN  :: 128;
    PINCH_IN    :: 256;
    PINCH_OUT   :: 512;

    GESTURE_NONE        :: NONE;
    GESTURE_TAP         :: TAP;
    GESTURE_DOUBLETAP   :: DOUBLETAP;
    GESTURE_HOLD        :: HOLD;
    GESTURE_DRAG        :: DRAG;
    GESTURE_SWIPE_RIGHT :: SWIPE_RIGHT;
    GESTURE_SWIPE_LEFT  :: SWIPE_LEFT;
    GESTURE_SWIPE_UP    :: SWIPE_UP;
    GESTURE_SWIPE_DOWN  :: SWIPE_DOWN;
    GESTURE_PINCH_IN    :: PINCH_IN;
    GESTURE_PINCH_OUT   :: PINCH_OUT;
}

// Camera system modes
CameraMode :: enum u32 {
    CUSTOM       :: 0;
    FREE         :: 1;
    ORBITAL      :: 2;
    FIRST_PERSON :: 3;
    THIRD_PERSON :: 4;

    CAMERA_CUSTOM       :: CUSTOM;
    CAMERA_FREE         :: FREE;
    CAMERA_ORBITAL      :: ORBITAL;
    CAMERA_FIRST_PERSON :: FIRST_PERSON;
    CAMERA_THIRD_PERSON :: THIRD_PERSON;
}

// Camera projection
CameraProjection :: enum u32 {
    PERSPECTIVE  :: 0;
    ORTHOGRAPHIC :: 1;

    CAMERA_PERSPECTIVE  :: PERSPECTIVE;
    CAMERA_ORTHOGRAPHIC :: ORTHOGRAPHIC;
}

// N-patch layout
NPatchLayout :: enum u32 {
    NINE_PATCH             :: 0;
    THREE_PATCH_VERTICAL   :: 1;
    THREE_PATCH_HORIZONTAL :: 2;

    NPATCH_NINE_PATCH             :: NINE_PATCH;
    NPATCH_THREE_PATCH_VERTICAL   :: THREE_PATCH_VERTICAL;
    NPATCH_THREE_PATCH_HORIZONTAL :: THREE_PATCH_HORIZONTAL;
}

// Callbacks to hook some internal functions
// WARNING: These callbacks are intended for advanced users
TraceLogCallback :: *void /* function type contained C va_list argument */;
LoadFileDataCallback :: #type (fileName: *u8, dataSize: *s32) -> *u8 #c_call;
SaveFileDataCallback :: #type (fileName: *u8, data: *void, dataSize: s32) -> bool #c_call;
LoadFileTextCallback :: #type (fileName: *u8) -> *u8 #c_call;
SaveFileTextCallback :: #type (fileName: *u8, text: *u8) -> bool #c_call;

// Window-related functions
InitWindow :: (width: s32, height: s32, title: *u8) -> void #foreign libraylib;
CloseWindow :: () -> void #foreign libraylib;
WindowShouldClose :: () -> bool #foreign libraylib;
IsWindowReady :: () -> bool #foreign libraylib;
IsWindowFullscreen :: () -> bool #foreign libraylib;
IsWindowHidden :: () -> bool #foreign libraylib;
IsWindowMinimized :: () -> bool #foreign libraylib;
IsWindowMaximized :: () -> bool #foreign libraylib;
IsWindowFocused :: () -> bool #foreign libraylib;
IsWindowResized :: () -> bool #foreign libraylib;
IsWindowState :: (flag: u32) -> bool #foreign libraylib;
SetWindowState :: (flags: ConfigFlags) -> void #foreign libraylib;
ClearWindowState :: (flags: ConfigFlags) -> void #foreign libraylib;
ToggleFullscreen :: () -> void #foreign libraylib;
ToggleBorderlessWindowed :: () -> void #foreign libraylib;
MaximizeWindow :: () -> void #foreign libraylib;
MinimizeWindow :: () -> void #foreign libraylib;
RestoreWindow :: () -> void #foreign libraylib;
SetWindowIcon :: (image: Image) -> void #foreign libraylib;
SetWindowIcons :: (images: *Image, count: s32) -> void #foreign libraylib;
SetWindowTitle :: (title: *u8) -> void #foreign libraylib;
SetWindowPosition :: (x: s32, y: s32) -> void #foreign libraylib;
SetWindowMonitor :: (monitor: s32) -> void #foreign libraylib;
SetWindowMinSize :: (width: s32, height: s32) -> void #foreign libraylib;
SetWindowMaxSize :: (width: s32, height: s32) -> void #foreign libraylib;
SetWindowSize :: (width: s32, height: s32) -> void #foreign libraylib;
SetWindowOpacity :: (opacity: float) -> void #foreign libraylib;
SetWindowFocused :: () -> void #foreign libraylib;
GetWindowHandle :: () -> *void #foreign libraylib;
GetScreenWidth :: () -> s32 #foreign libraylib;
GetScreenHeight :: () -> s32 #foreign libraylib;
GetRenderWidth :: () -> s32 #foreign libraylib;
GetRenderHeight :: () -> s32 #foreign libraylib;
GetMonitorCount :: () -> s32 #foreign libraylib;
GetCurrentMonitor :: () -> s32 #foreign libraylib;
GetMonitorPosition :: (monitor: s32) -> Vector2 #foreign libraylib;
GetMonitorWidth :: (monitor: s32) -> s32 #foreign libraylib;
GetMonitorHeight :: (monitor: s32) -> s32 #foreign libraylib;
GetMonitorPhysicalWidth :: (monitor: s32) -> s32 #foreign libraylib;
GetMonitorPhysicalHeight :: (monitor: s32) -> s32 #foreign libraylib;
GetMonitorRefreshRate :: (monitor: s32) -> s32 #foreign libraylib;
GetWindowPosition :: () -> Vector2 #foreign libraylib;
GetWindowScaleDPI :: () -> Vector2 #foreign libraylib;
GetMonitorName :: (monitor: s32) -> *u8 #foreign libraylib;
SetClipboardText :: (text: *u8) -> void #foreign libraylib;
GetClipboardText :: () -> *u8 #foreign libraylib;
GetClipboardImage :: () -> Image #foreign libraylib;
EnableEventWaiting :: () -> void #foreign libraylib;
DisableEventWaiting :: () -> void #foreign libraylib;

// Cursor-related functions
ShowCursor :: () -> void #foreign libraylib;
HideCursor :: () -> void #foreign libraylib;
IsCursorHidden :: () -> bool #foreign libraylib;
EnableCursor :: () -> void #foreign libraylib;
DisableCursor :: () -> void #foreign libraylib;
IsCursorOnScreen :: () -> bool #foreign libraylib;

// Drawing-related functions
ClearBackground :: (color: Color) -> void #foreign libraylib;
BeginDrawing :: () -> void #foreign libraylib;
EndDrawing :: () -> void #foreign libraylib;
BeginMode2D :: (camera: Camera2D) -> void #foreign libraylib;
EndMode2D :: () -> void #foreign libraylib;
BeginMode3D :: (camera: Camera3D) -> void #foreign libraylib;
EndMode3D :: () -> void #foreign libraylib;
BeginTextureMode :: (target: RenderTexture2D) -> void #foreign libraylib;
EndTextureMode :: () -> void #foreign libraylib;
BeginShaderMode :: (shader: Shader) -> void #foreign libraylib;
EndShaderMode :: () -> void #foreign libraylib;
BeginBlendMode :: (mode: s32) -> void #foreign libraylib;
EndBlendMode :: () -> void #foreign libraylib;
BeginScissorMode :: (x: s32, y: s32, width: s32, height: s32) -> void #foreign libraylib;
EndScissorMode :: () -> void #foreign libraylib;
BeginVrStereoMode :: (config: VrStereoConfig) -> void #foreign libraylib;
EndVrStereoMode :: () -> void #foreign libraylib;

// VR stereo config functions for VR simulator
LoadVrStereoConfig :: (device: VrDeviceInfo) -> VrStereoConfig #foreign libraylib;
UnloadVrStereoConfig :: (config: VrStereoConfig) -> void #foreign libraylib;

// Shader management functions
// NOTE: Shader functionality is not available on OpenGL 1.1
LoadShader :: (vsFileName: *u8, fsFileName: *u8) -> Shader #foreign libraylib;
LoadShaderFromMemory :: (vsCode: *u8, fsCode: *u8) -> Shader #foreign libraylib;
IsShaderValid :: (shader: Shader) -> bool #foreign libraylib;
GetShaderLocation :: (shader: Shader, uniformName: *u8) -> s32 #foreign libraylib;
GetShaderLocationAttrib :: (shader: Shader, attribName: *u8) -> s32 #foreign libraylib;
SetShaderValue :: (shader: Shader, locIndex: s32, value: *void, uniformType: s32) -> void #foreign libraylib;
SetShaderValueV :: (shader: Shader, locIndex: s32, value: *void, uniformType: s32, count: s32) -> void #foreign libraylib;
SetShaderValueMatrix :: (shader: Shader, locIndex: s32, mat: Matrix) -> void #foreign libraylib;
SetShaderValueTexture :: (shader: Shader, locIndex: s32, texture: Texture2D) -> void #foreign libraylib;
UnloadShader :: (shader: Shader) -> void #foreign libraylib;

GetScreenToWorldRay :: (position: Vector2, camera: Camera) -> Ray #foreign libraylib;
GetScreenToWorldRayEx :: (position: Vector2, camera: Camera, width: s32, height: s32) -> Ray #foreign libraylib;
GetWorldToScreen :: (position: Vector3, camera: Camera) -> Vector2 #foreign libraylib;
GetWorldToScreenEx :: (position: Vector3, camera: Camera, width: s32, height: s32) -> Vector2 #foreign libraylib;
GetWorldToScreen2D :: (position: Vector2, camera: Camera2D) -> Vector2 #foreign libraylib;
GetScreenToWorld2D :: (position: Vector2, camera: Camera2D) -> Vector2 #foreign libraylib;
GetCameraMatrix :: (camera: Camera) -> Matrix #foreign libraylib;
GetCameraMatrix2D :: (camera: Camera2D) -> Matrix #foreign libraylib;

// Timing-related functions
SetTargetFPS :: (fps: s32) -> void #foreign libraylib;
GetFrameTime :: () -> float #foreign libraylib;
GetTime :: () -> float64 #foreign libraylib;
GetFPS :: () -> s32 #foreign libraylib;

// Custom frame control functions
// NOTE: Those functions are intended for advanced users that want full control over the frame processing
// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timing + PollInputEvents()
// To avoid that behaviour and control frame processes manually, enable in config.h: SUPPORT_CUSTOM_FRAME_CONTROL
SwapScreenBuffer :: () -> void #foreign libraylib;
PollInputEvents :: () -> void #foreign libraylib;
WaitTime :: (seconds: float64) -> void #foreign libraylib;

// Random values generation functions
SetRandomSeed :: (seed: u32) -> void #foreign libraylib;
GetRandomValue :: (min: s32, max: s32) -> s32 #foreign libraylib;
LoadRandomSequence :: (count: u32, min: s32, max: s32) -> *s32 #foreign libraylib;
UnloadRandomSequence :: (sequence: *s32) -> void #foreign libraylib;

// Misc. functions
TakeScreenshot :: (fileName: *u8) -> void #foreign libraylib;
SetConfigFlags :: (flags: ConfigFlags) -> void #foreign libraylib;
OpenURL :: (url: *u8) -> void #foreign libraylib;

// NOTE: Following functions implemented in module [utils]
//------------------------------------------------------------------
TraceLog_CFormat :: (logLevel: s32, text: *u8, __args: ..Any) -> void #foreign libraylib "TraceLog";
TraceLog :: (logLevel: s32, text: string, __args: ..Any) {
    push_allocator(temp);
    formatted_text_builder: String_Builder;
    print_to_builder(*formatted_text_builder, text, ..__args);
    append(*formatted_text_builder, "\0");
    formatted_text := builder_to_string(*formatted_text_builder);
    TraceLog_CFormat(logLevel, "%s", formatted_text.data);
} @PrintLike
SetTraceLogLevel :: (logLevel: s32) -> void #foreign libraylib;
MemAlloc :: (size: u32) -> *void #foreign libraylib;
MemRealloc :: (ptr: *void, size: u32) -> *void #foreign libraylib;
MemFree :: (ptr: *void) -> void #foreign libraylib;

// Set custom callbacks
// WARNING: Callbacks setup is intended for advanced users
SetTraceLogCallback :: (callback: TraceLogCallback) -> void #foreign libraylib;
SetLoadFileDataCallback :: (callback: LoadFileDataCallback) -> void #foreign libraylib;
SetSaveFileDataCallback :: (callback: SaveFileDataCallback) -> void #foreign libraylib;
SetLoadFileTextCallback :: (callback: LoadFileTextCallback) -> void #foreign libraylib;
SetSaveFileTextCallback :: (callback: SaveFileTextCallback) -> void #foreign libraylib;

// Files management functions
LoadFileData :: (fileName: *u8, dataSize: *s32) -> *u8 #foreign libraylib;
UnloadFileData :: (data: *u8) -> void #foreign libraylib;
SaveFileData :: (fileName: *u8, data: *void, dataSize: s32) -> bool #foreign libraylib;
ExportDataAsCode :: (data: *u8, dataSize: s32, fileName: *u8) -> bool #foreign libraylib;
LoadFileText :: (fileName: *u8) -> *u8 #foreign libraylib;
UnloadFileText :: (text: *u8) -> void #foreign libraylib;
SaveFileText :: (fileName: *u8, text: *u8) -> bool #foreign libraylib;

// File system functions
FileExists :: (fileName: *u8) -> bool #foreign libraylib;
DirectoryExists :: (dirPath: *u8) -> bool #foreign libraylib;
IsFileExtension :: (fileName: *u8, ext: *u8) -> bool #foreign libraylib;
GetFileLength :: (fileName: *u8) -> s32 #foreign libraylib;
GetFileExtension :: (fileName: *u8) -> *u8 #foreign libraylib;
GetFileName :: (filePath: *u8) -> *u8 #foreign libraylib;
GetFileNameWithoutExt :: (filePath: *u8) -> *u8 #foreign libraylib;
GetDirectoryPath :: (filePath: *u8) -> *u8 #foreign libraylib;
GetPrevDirectoryPath :: (dirPath: *u8) -> *u8 #foreign libraylib;
GetWorkingDirectory :: () -> *u8 #foreign libraylib;
GetApplicationDirectory :: () -> *u8 #foreign libraylib;
MakeDirectory :: (dirPath: *u8) -> s32 #foreign libraylib;
ChangeDirectory :: (dir: *u8) -> bool #foreign libraylib;
IsPathFile :: (path: *u8) -> bool #foreign libraylib;
IsFileNameValid :: (fileName: *u8) -> bool #foreign libraylib;
LoadDirectoryFiles :: (dirPath: *u8) -> FilePathList #foreign libraylib;
LoadDirectoryFilesEx :: (basePath: *u8, filter: *u8, scanSubdirs: bool) -> FilePathList #foreign libraylib;
UnloadDirectoryFiles :: (files: FilePathList) -> void #foreign libraylib;
IsFileDropped :: () -> bool #foreign libraylib;
LoadDroppedFiles :: () -> FilePathList #foreign libraylib;
UnloadDroppedFiles :: (files: FilePathList) -> void #foreign libraylib;
GetFileModTime :: (fileName: *u8) -> s64 #foreign libraylib;

// Compression/Encoding functionality
CompressData :: (data: *u8, dataSize: s32, compDataSize: *s32) -> *u8 #foreign libraylib;
DecompressData :: (compData: *u8, compDataSize: s32, dataSize: *s32) -> *u8 #foreign libraylib;
EncodeDataBase64 :: (data: *u8, dataSize: s32, outputSize: *s32) -> *u8 #foreign libraylib;
DecodeDataBase64 :: (data: *u8, outputSize: *s32) -> *u8 #foreign libraylib;
ComputeCRC32 :: (data: *u8, dataSize: s32) -> u32 #foreign libraylib;
ComputeMD5 :: (data: *u8, dataSize: s32) -> *u32 #foreign libraylib;
ComputeSHA1 :: (data: *u8, dataSize: s32) -> *u32 #foreign libraylib;

// Automation events functionality
LoadAutomationEventList :: (fileName: *u8) -> AutomationEventList #foreign libraylib;
UnloadAutomationEventList :: (list: AutomationEventList) -> void #foreign libraylib;
ExportAutomationEventList :: (list: AutomationEventList, fileName: *u8) -> bool #foreign libraylib;
SetAutomationEventList :: (list: *AutomationEventList) -> void #foreign libraylib;
SetAutomationEventBaseFrame :: (frame: s32) -> void #foreign libraylib;
StartAutomationEventRecording :: () -> void #foreign libraylib;
StopAutomationEventRecording :: () -> void #foreign libraylib;
PlayAutomationEvent :: (event: AutomationEvent) -> void #foreign libraylib;

// Input-related functions: keyboard
IsKeyPressed :: (key: KeyboardKey) -> bool #foreign libraylib;
IsKeyPressedRepeat :: (key: KeyboardKey) -> bool #foreign libraylib;
IsKeyDown :: (key: KeyboardKey) -> bool #foreign libraylib;
IsKeyReleased :: (key: KeyboardKey) -> bool #foreign libraylib;
IsKeyUp :: (key: KeyboardKey) -> bool #foreign libraylib;
GetKeyPressed :: () -> s32 #foreign libraylib;
GetCharPressed :: () -> s32 #foreign libraylib;
SetExitKey :: (key: KeyboardKey) -> void #foreign libraylib;

// Input-related functions: gamepads
IsGamepadAvailable :: (gamepad: s32) -> bool #foreign libraylib;
GetGamepadName :: (gamepad: s32) -> *u8 #foreign libraylib;
IsGamepadButtonPressed :: (gamepad: s32, button: GamepadButton) -> bool #foreign libraylib;
IsGamepadButtonDown :: (gamepad: s32, button: GamepadButton) -> bool #foreign libraylib;
IsGamepadButtonReleased :: (gamepad: s32, button: GamepadButton) -> bool #foreign libraylib;
IsGamepadButtonUp :: (gamepad: s32, button: GamepadButton) -> bool #foreign libraylib;
GetGamepadButtonPressed :: () -> s32 #foreign libraylib;
GetGamepadAxisCount :: (gamepad: s32) -> s32 #foreign libraylib;
GetGamepadAxisMovement :: (gamepad: s32, axis: GamepadAxis) -> float #foreign libraylib;
SetGamepadMappings :: (mappings: *u8) -> s32 #foreign libraylib;
SetGamepadVibration :: (gamepad: s32, leftMotor: float, rightMotor: float, duration: float) -> void #foreign libraylib;

// Input-related functions: mouse
IsMouseButtonPressed :: (button: MouseButton) -> bool #foreign libraylib;
IsMouseButtonDown :: (button: MouseButton) -> bool #foreign libraylib;
IsMouseButtonReleased :: (button: MouseButton) -> bool #foreign libraylib;
IsMouseButtonUp :: (button: MouseButton) -> bool #foreign libraylib;
GetMouseX :: () -> s32 #foreign libraylib;
GetMouseY :: () -> s32 #foreign libraylib;
GetMousePosition :: () -> Vector2 #foreign libraylib;
GetMouseDelta :: () -> Vector2 #foreign libraylib;
SetMousePosition :: (x: s32, y: s32) -> void #foreign libraylib;
SetMouseOffset :: (offsetX: s32, offsetY: s32) -> void #foreign libraylib;
SetMouseScale :: (scaleX: float, scaleY: float) -> void #foreign libraylib;
GetMouseWheelMove :: () -> float #foreign libraylib;
GetMouseWheelMoveV :: () -> Vector2 #foreign libraylib;
SetMouseCursor :: (cursor: s32) -> void #foreign libraylib;

// Input-related functions: touch
GetTouchX :: () -> s32 #foreign libraylib;
GetTouchY :: () -> s32 #foreign libraylib;
GetTouchPosition :: (index: s32) -> Vector2 #foreign libraylib;
GetTouchPointId :: (index: s32) -> s32 #foreign libraylib;
GetTouchPointCount :: () -> s32 #foreign libraylib;

//------------------------------------------------------------------------------------
// Gestures and Touch Handling Functions (Module: rgestures)
//------------------------------------------------------------------------------------
SetGesturesEnabled :: (flags: Gesture) -> void #foreign libraylib;
IsGestureDetected :: (gesture: Gesture) -> bool #foreign libraylib;
GetGestureDetected :: () -> Gesture #foreign libraylib;
GetGestureHoldDuration :: () -> float #foreign libraylib;
GetGestureDragVector :: () -> Vector2 #foreign libraylib;
GetGestureDragAngle :: () -> float #foreign libraylib;
GetGesturePinchVector :: () -> Vector2 #foreign libraylib;
GetGesturePinchAngle :: () -> float #foreign libraylib;

//------------------------------------------------------------------------------------
// Camera System Functions (Module: rcamera)
//------------------------------------------------------------------------------------
UpdateCamera :: (camera: *Camera, mode: CameraMode) -> void #foreign libraylib;
UpdateCameraPro :: (camera: *Camera, movement: Vector3, rotation: Vector3, zoom: float) -> void #foreign libraylib;

//------------------------------------------------------------------------------------
// Basic Shapes Drawing Functions (Module: shapes)
//------------------------------------------------------------------------------------
// Set texture and rectangle to be used on shapes drawing
// NOTE: It can be useful when using basic shapes and one single font,
// defining a font char white rectangle would allow drawing everything in a single draw call
SetShapesTexture :: (texture: Texture2D, source: Rectangle) -> void #foreign libraylib;
GetShapesTexture :: () -> Texture2D #foreign libraylib;
GetShapesTextureRectangle :: () -> Rectangle #foreign libraylib;

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

// Splines drawing functions
DrawSplineLinear :: (points: *Vector2, pointCount: s32, thick: float, color: Color) -> void #foreign libraylib;
DrawSplineBasis :: (points: *Vector2, pointCount: s32, thick: float, color: Color) -> void #foreign libraylib;
DrawSplineCatmullRom :: (points: *Vector2, pointCount: s32, thick: float, color: Color) -> void #foreign libraylib;
DrawSplineBezierQuadratic :: (points: *Vector2, pointCount: s32, thick: float, color: Color) -> void #foreign libraylib;
DrawSplineBezierCubic :: (points: *Vector2, pointCount: s32, thick: float, color: Color) -> void #foreign libraylib;
DrawSplineSegmentLinear :: (p1: Vector2, p2: Vector2, thick: float, color: Color) -> void #foreign libraylib;
DrawSplineSegmentBasis :: (p1: Vector2, p2: Vector2, p3: Vector2, p4: Vector2, thick: float, color: Color) -> void #foreign libraylib;
DrawSplineSegmentCatmullRom :: (p1: Vector2, p2: Vector2, p3: Vector2, p4: Vector2, thick: float, color: Color) -> void #foreign libraylib;
DrawSplineSegmentBezierQuadratic :: (p1: Vector2, c2: Vector2, p3: Vector2, thick: float, color: Color) -> void #foreign libraylib;
DrawSplineSegmentBezierCubic :: (p1: Vector2, c2: Vector2, c3: Vector2, p4: Vector2, thick: float, color: Color) -> void #foreign libraylib;

// Spline segment point evaluation functions, for a given t [0.0f .. 1.0f]
GetSplinePointLinear :: (startPos: Vector2, endPos: Vector2, t: float) -> Vector2 #foreign libraylib;
GetSplinePointBasis :: (p1: Vector2, p2: Vector2, p3: Vector2, p4: Vector2, t: float) -> Vector2 #foreign libraylib;
GetSplinePointCatmullRom :: (p1: Vector2, p2: Vector2, p3: Vector2, p4: Vector2, t: float) -> Vector2 #foreign libraylib;
GetSplinePointBezierQuad :: (p1: Vector2, c2: Vector2, p3: Vector2, t: float) -> Vector2 #foreign libraylib;
GetSplinePointBezierCubic :: (p1: Vector2, c2: Vector2, c3: Vector2, p4: Vector2, t: float) -> Vector2 #foreign libraylib;

// Basic shapes collision detection functions
CheckCollisionRecs :: (rec1: Rectangle, rec2: Rectangle) -> bool #foreign libraylib;
CheckCollisionCircles :: (center1: Vector2, radius1: float, center2: Vector2, radius2: float) -> bool #foreign libraylib;
CheckCollisionCircleRec :: (center: Vector2, radius: float, rec: Rectangle) -> bool #foreign libraylib;
CheckCollisionCircleLine :: (center: Vector2, radius: float, p1: Vector2, p2: Vector2) -> bool #foreign libraylib;
CheckCollisionPointRec :: (point: Vector2, rec: Rectangle) -> bool #foreign libraylib;
CheckCollisionPointCircle :: (point: Vector2, center: Vector2, radius: float) -> bool #foreign libraylib;
CheckCollisionPointTriangle :: (point: Vector2, p1: Vector2, p2: Vector2, p3: Vector2) -> bool #foreign libraylib;
CheckCollisionPointLine :: (point: Vector2, p1: Vector2, p2: Vector2, threshold: s32) -> bool #foreign libraylib;
CheckCollisionPointPoly :: (point: Vector2, points: *Vector2, pointCount: s32) -> bool #foreign libraylib;
CheckCollisionLines :: (startPos1: Vector2, endPos1: Vector2, startPos2: Vector2, endPos2: Vector2, collisionPoint: *Vector2) -> bool #foreign libraylib;
GetCollisionRec :: (rec1: Rectangle, rec2: Rectangle) -> Rectangle #foreign libraylib;

// Image loading functions
// NOTE: These functions do not require GPU access
LoadImage :: (fileName: *u8) -> Image #foreign libraylib;
LoadImageRaw :: (fileName: *u8, width: s32, height: s32, format: PixelFormat, headerSize: s32) -> Image #foreign libraylib;
LoadImageAnim :: (fileName: *u8, frames: *s32) -> Image #foreign libraylib;
LoadImageAnimFromMemory :: (fileType: *u8, fileData: *u8, dataSize: s32, frames: *s32) -> Image #foreign libraylib;
LoadImageFromMemory :: (fileType: *u8, fileData: *u8, dataSize: s32) -> Image #foreign libraylib;
LoadImageFromTexture :: (texture: Texture2D) -> Image #foreign libraylib;
LoadImageFromScreen :: () -> Image #foreign libraylib;
IsImageValid :: (image: Image) -> bool #foreign libraylib;
UnloadImage :: (image: Image) -> void #foreign libraylib;
ExportImage :: (image: Image, fileName: *u8) -> bool #foreign libraylib;
ExportImageToMemory :: (image: Image, fileType: *u8, fileSize: *s32) -> *u8 #foreign libraylib;
ExportImageAsCode :: (image: Image, fileName: *u8) -> bool #foreign libraylib;

// Image generation functions
GenImageColor :: (width: s32, height: s32, color: Color) -> Image #foreign libraylib;
GenImageGradientLinear :: (width: s32, height: s32, direction: s32, start: Color, end: Color) -> Image #foreign libraylib;
GenImageGradientRadial :: (width: s32, height: s32, density: float, inner: Color, outer: Color) -> Image #foreign libraylib;
GenImageGradientSquare :: (width: s32, height: s32, density: float, inner: Color, outer: Color) -> Image #foreign libraylib;
GenImageChecked :: (width: s32, height: s32, checksX: s32, checksY: s32, col1: Color, col2: Color) -> Image #foreign libraylib;
GenImageWhiteNoise :: (width: s32, height: s32, factor: float) -> Image #foreign libraylib;
GenImagePerlinNoise :: (width: s32, height: s32, offsetX: s32, offsetY: s32, scale: float) -> Image #foreign libraylib;
GenImageCellular :: (width: s32, height: s32, tileSize: s32) -> Image #foreign libraylib;
GenImageText :: (width: s32, height: s32, text: *u8) -> Image #foreign libraylib;

// Image manipulation functions
ImageCopy :: (image: Image) -> Image #foreign libraylib;
ImageFromImage :: (image: Image, rec: Rectangle) -> Image #foreign libraylib;
ImageFromChannel :: (image: Image, selectedChannel: s32) -> Image #foreign libraylib;
ImageText :: (text: *u8, fontSize: s32, color: Color) -> Image #foreign libraylib;
ImageTextEx :: (font: Font, text: *u8, fontSize: float, spacing: float, tint: Color) -> Image #foreign libraylib;
ImageFormat :: (image: *Image, newFormat: PixelFormat) -> void #foreign libraylib;
ImageToPOT :: (image: *Image, fill: Color) -> void #foreign libraylib;
ImageCrop :: (image: *Image, crop: Rectangle) -> void #foreign libraylib;
ImageAlphaCrop :: (image: *Image, threshold: float) -> void #foreign libraylib;
ImageAlphaClear :: (image: *Image, color: Color, threshold: float) -> void #foreign libraylib;
ImageAlphaMask :: (image: *Image, alphaMask: Image) -> void #foreign libraylib;
ImageAlphaPremultiply :: (image: *Image) -> void #foreign libraylib;
ImageBlurGaussian :: (image: *Image, blurSize: s32) -> void #foreign libraylib;
ImageKernelConvolution :: (image: *Image, kernel: *float, kernelSize: s32) -> void #foreign libraylib;
ImageResize :: (image: *Image, newWidth: s32, newHeight: s32) -> void #foreign libraylib;
ImageResizeNN :: (image: *Image, newWidth: s32, newHeight: s32) -> void #foreign libraylib;
ImageResizeCanvas :: (image: *Image, newWidth: s32, newHeight: s32, offsetX: s32, offsetY: s32, fill: Color) -> void #foreign libraylib;
ImageMipmaps :: (image: *Image) -> void #foreign libraylib;
ImageDither :: (image: *Image, rBpp: s32, gBpp: s32, bBpp: s32, aBpp: s32) -> void #foreign libraylib;
ImageFlipVertical :: (image: *Image) -> void #foreign libraylib;
ImageFlipHorizontal :: (image: *Image) -> void #foreign libraylib;
ImageRotate :: (image: *Image, degrees: s32) -> void #foreign libraylib;
ImageRotateCW :: (image: *Image) -> void #foreign libraylib;
ImageRotateCCW :: (image: *Image) -> void #foreign libraylib;
ImageColorTint :: (image: *Image, color: Color) -> void #foreign libraylib;
ImageColorInvert :: (image: *Image) -> void #foreign libraylib;
ImageColorGrayscale :: (image: *Image) -> void #foreign libraylib;
ImageColorContrast :: (image: *Image, contrast: float) -> void #foreign libraylib;
ImageColorBrightness :: (image: *Image, brightness: s32) -> void #foreign libraylib;
ImageColorReplace :: (image: *Image, color: Color, replace: Color) -> void #foreign libraylib;
LoadImageColors :: (image: Image) -> *Color #foreign libraylib;
LoadImagePalette :: (image: Image, maxPaletteSize: s32, colorCount: *s32) -> *Color #foreign libraylib;
UnloadImageColors :: (colors: *Color) -> void #foreign libraylib;
UnloadImagePalette :: (colors: *Color) -> void #foreign libraylib;
GetImageAlphaBorder :: (image: Image, threshold: float) -> Rectangle #foreign libraylib;
GetImageColor :: (image: Image, x: s32, y: s32) -> Color #foreign libraylib;

// Image drawing functions
// NOTE: Image software-rendering functions (CPU)
ImageClearBackground :: (dst: *Image, color: Color) -> void #foreign libraylib;
ImageDrawPixel :: (dst: *Image, posX: s32, posY: s32, color: Color) -> void #foreign libraylib;
ImageDrawPixelV :: (dst: *Image, position: Vector2, color: Color) -> void #foreign libraylib;
ImageDrawLine :: (dst: *Image, startPosX: s32, startPosY: s32, endPosX: s32, endPosY: s32, color: Color) -> void #foreign libraylib;
ImageDrawLineV :: (dst: *Image, start: Vector2, end: Vector2, color: Color) -> void #foreign libraylib;
ImageDrawLineEx :: (dst: *Image, start: Vector2, end: Vector2, thick: s32, color: Color) -> void #foreign libraylib;
ImageDrawCircle :: (dst: *Image, centerX: s32, centerY: s32, radius: s32, color: Color) -> void #foreign libraylib;
ImageDrawCircleV :: (dst: *Image, center: Vector2, radius: s32, color: Color) -> void #foreign libraylib;
ImageDrawCircleLines :: (dst: *Image, centerX: s32, centerY: s32, radius: s32, color: Color) -> void #foreign libraylib;
ImageDrawCircleLinesV :: (dst: *Image, center: Vector2, radius: s32, color: Color) -> void #foreign libraylib;
ImageDrawRectangle :: (dst: *Image, posX: s32, posY: s32, width: s32, height: s32, color: Color) -> void #foreign libraylib;
ImageDrawRectangleV :: (dst: *Image, position: Vector2, size: Vector2, color: Color) -> void #foreign libraylib;
ImageDrawRectangleRec :: (dst: *Image, rec: Rectangle, color: Color) -> void #foreign libraylib;
ImageDrawRectangleLines :: (dst: *Image, rec: Rectangle, thick: s32, color: Color) -> void #foreign libraylib;
ImageDrawTriangle :: (dst: *Image, v1: Vector2, v2: Vector2, v3: Vector2, color: Color) -> void #foreign libraylib;
ImageDrawTriangleEx :: (dst: *Image, v1: Vector2, v2: Vector2, v3: Vector2, c1: Color, c2: Color, c3: Color) -> void #foreign libraylib;
ImageDrawTriangleLines :: (dst: *Image, v1: Vector2, v2: Vector2, v3: Vector2, color: Color) -> void #foreign libraylib;
ImageDrawTriangleFan :: (dst: *Image, points: *Vector2, pointCount: s32, color: Color) -> void #foreign libraylib;
ImageDrawTriangleStrip :: (dst: *Image, points: *Vector2, pointCount: s32, color: Color) -> void #foreign libraylib;
ImageDraw :: (dst: *Image, src: Image, srcRec: Rectangle, dstRec: Rectangle, tint: Color) -> void #foreign libraylib;
ImageDrawText :: (dst: *Image, text: *u8, posX: s32, posY: s32, fontSize: s32, color: Color) -> void #foreign libraylib;
ImageDrawTextEx :: (dst: *Image, font: Font, text: *u8, position: Vector2, fontSize: float, spacing: float, tint: Color) -> void #foreign libraylib;

// Texture loading functions
// NOTE: These functions require GPU access
LoadTexture :: (fileName: *u8) -> Texture2D #foreign libraylib;
LoadTextureFromImage :: (image: Image) -> Texture2D #foreign libraylib;
LoadTextureCubemap :: (image: Image, layout: CubemapLayout) -> TextureCubemap #foreign libraylib;
LoadRenderTexture :: (width: s32, height: s32) -> RenderTexture2D #foreign libraylib;
IsTextureValid :: (texture: Texture2D) -> bool #foreign libraylib;
UnloadTexture :: (texture: Texture2D) -> void #foreign libraylib;
IsRenderTextureValid :: (target: RenderTexture2D) -> bool #foreign libraylib;
UnloadRenderTexture :: (target: RenderTexture2D) -> void #foreign libraylib;
UpdateTexture :: (texture: Texture2D, pixels: *void) -> void #foreign libraylib;
UpdateTextureRec :: (texture: Texture2D, rec: Rectangle, pixels: *void) -> void #foreign libraylib;

// Texture configuration functions
GenTextureMipmaps :: (texture: *Texture2D) -> void #foreign libraylib;
SetTextureFilter :: (texture: Texture2D, filter: TextureFilter) -> void #foreign libraylib;
SetTextureWrap :: (texture: Texture2D, wrap: TextureWrap) -> void #foreign libraylib;

// Texture drawing functions
DrawTexture :: (texture: Texture2D, posX: s32, posY: s32, tint: Color) -> void #foreign libraylib;
DrawTextureV :: (texture: Texture2D, position: Vector2, tint: Color) -> void #foreign libraylib;
DrawTextureEx :: (texture: Texture2D, position: Vector2, rotation: float, scale: float, tint: Color) -> void #foreign libraylib;
DrawTextureRec :: (texture: Texture2D, source: Rectangle, position: Vector2, tint: Color) -> void #foreign libraylib;
DrawTexturePro :: (texture: Texture2D, source: Rectangle, dest: Rectangle, origin: Vector2, rotation: float, tint: Color) -> void #foreign libraylib;
DrawTextureNPatch :: (texture: Texture2D, nPatchInfo: NPatchInfo, dest: Rectangle, origin: Vector2, rotation: float, tint: Color) -> void #foreign libraylib;

// Color/pixel related functions
ColorIsEqual :: (col1: Color, col2: Color) -> bool #foreign libraylib;
Fade :: (color: Color, alpha: float) -> Color #foreign libraylib;
ColorToInt :: (color: Color) -> s32 #foreign libraylib;
ColorNormalize :: (color: Color) -> Vector4 #foreign libraylib;
ColorFromNormalized :: (normalized: Vector4) -> Color #foreign libraylib;
ColorToHSV :: (color: Color) -> Vector3 #foreign libraylib;
ColorFromHSV :: (hue: float, saturation: float, value: float) -> Color #foreign libraylib;
ColorTint :: (color: Color, tint: Color) -> Color #foreign libraylib;
ColorBrightness :: (color: Color, factor: float) -> Color #foreign libraylib;
ColorContrast :: (color: Color, contrast: float) -> Color #foreign libraylib;
ColorAlpha :: (color: Color, alpha: float) -> Color #foreign libraylib;
ColorAlphaBlend :: (dst: Color, src: Color, tint: Color) -> Color #foreign libraylib;
ColorLerp :: (color1: Color, color2: Color, factor: float) -> Color #foreign libraylib;
GetColor :: (hexValue: u32) -> Color #foreign libraylib;
GetPixelColor :: (srcPtr: *void, format: PixelFormat) -> Color #foreign libraylib;
SetPixelColor :: (dstPtr: *void, color: Color, format: PixelFormat) -> void #foreign libraylib;
GetPixelDataSize :: (width: s32, height: s32, format: PixelFormat) -> s32 #foreign libraylib;

// Font loading/unloading functions
GetFontDefault :: () -> Font #foreign libraylib;
LoadFont :: (fileName: *u8) -> Font #foreign libraylib;
LoadFontEx :: (fileName: *u8, fontSize: s32, codepoints: *s32, codepointCount: s32) -> Font #foreign libraylib;
LoadFontFromImage :: (image: Image, key: Color, firstChar: s32) -> Font #foreign libraylib;
LoadFontFromMemory :: (fileType: *u8, fileData: *u8, dataSize: s32, fontSize: s32, codepoints: *s32, codepointCount: s32) -> Font #foreign libraylib;
IsFontValid :: (font: Font) -> bool #foreign libraylib;
LoadFontData :: (fileData: *u8, dataSize: s32, fontSize: s32, codepoints: *s32, codepointCount: s32, type: s32) -> *GlyphInfo #foreign libraylib;
GenImageFontAtlas :: (glyphs: *GlyphInfo, glyphRecs: **Rectangle, glyphCount: s32, fontSize: s32, padding: s32, packMethod: s32) -> Image #foreign libraylib;
UnloadFontData :: (glyphs: *GlyphInfo, glyphCount: s32) -> void #foreign libraylib;
UnloadFont :: (font: Font) -> void #foreign libraylib;
ExportFontAsCode :: (font: Font, fileName: *u8) -> bool #foreign libraylib;

// Text drawing functions
DrawFPS :: (posX: s32, posY: s32) -> void #foreign libraylib;
DrawText :: (text: *u8, posX: s32, posY: s32, fontSize: s32, color: Color) -> void #foreign libraylib;
DrawTextEx :: (font: Font, text: *u8, position: Vector2, fontSize: float, spacing: float, tint: Color) -> void #foreign libraylib;
DrawTextPro :: (font: Font, text: *u8, position: Vector2, origin: Vector2, rotation: float, fontSize: float, spacing: float, tint: Color) -> void #foreign libraylib;
DrawTextCodepoint :: (font: Font, codepoint: s32, position: Vector2, fontSize: float, tint: Color) -> void #foreign libraylib;
DrawTextCodepoints :: (font: Font, codepoints: *s32, codepointCount: s32, position: Vector2, fontSize: float, spacing: float, tint: Color) -> void #foreign libraylib;

// Text font info functions
SetTextLineSpacing :: (spacing: s32) -> void #foreign libraylib;
MeasureText :: (text: *u8, fontSize: s32) -> s32 #foreign libraylib;
MeasureTextEx :: (font: Font, text: *u8, fontSize: float, spacing: float) -> Vector2 #foreign libraylib;
GetGlyphIndex :: (font: Font, codepoint: s32) -> s32 #foreign libraylib;
GetGlyphInfo :: (font: Font, codepoint: s32) -> GlyphInfo #foreign libraylib;
GetGlyphAtlasRec :: (font: Font, codepoint: s32) -> Rectangle #foreign libraylib;

// Text codepoints management functions (unicode characters)
LoadUTF8 :: (codepoints: *s32, length: s32) -> *u8 #foreign libraylib;
UnloadUTF8 :: (text: *u8) -> void #foreign libraylib;
LoadCodepoints :: (text: *u8, count: *s32) -> *s32 #foreign libraylib;
UnloadCodepoints :: (codepoints: *s32) -> void #foreign libraylib;
GetCodepointCount :: (text: *u8) -> s32 #foreign libraylib;
GetCodepoint :: (text: *u8, codepointSize: *s32) -> s32 #foreign libraylib;
GetCodepointNext :: (text: *u8, codepointSize: *s32) -> s32 #foreign libraylib;
GetCodepointPrevious :: (text: *u8, codepointSize: *s32) -> s32 #foreign libraylib;
CodepointToUTF8 :: (codepoint: s32, utf8Size: *s32) -> *u8 #foreign libraylib;

// Text strings management functions (no UTF-8 strings, only byte chars)
// NOTE: Some strings allocate memory internally for returned strings, just be careful!
TextCopy :: (dst: *u8, src: *u8) -> s32 #foreign libraylib;
TextIsEqual :: (text1: *u8, text2: *u8) -> bool #foreign libraylib;
TextLength :: (text: *u8) -> u32 #foreign libraylib;
TextFormat_CFormat :: (text: *u8, __args: ..Any) -> *u8 #foreign libraylib "TextFormat";
TextFormat :: (text: string, __args: ..Any) -> *u8 {
    push_allocator(temp);
    formatted_text_builder: String_Builder;
    print_to_builder(*formatted_text_builder, text, ..__args);
    append(*formatted_text_builder, "\0");
    formatted_text := builder_to_string(*formatted_text_builder);
    return TextFormat_CFormat("%s", formatted_text.data);
} @PrintLike
TextSubtext :: (text: *u8, position: s32, length: s32) -> *u8 #foreign libraylib;
TextReplace :: (text: *u8, replace: *u8, by: *u8) -> *u8 #foreign libraylib;
TextInsert :: (text: *u8, insert: *u8, position: s32) -> *u8 #foreign libraylib;
TextJoin :: (textList: **u8, count: s32, delimiter: *u8) -> *u8 #foreign libraylib;
TextSplit :: (text: *u8, delimiter: u8, count: *s32) -> **u8 #foreign libraylib;
TextAppend :: (text: *u8, append: *u8, position: *s32) -> void #foreign libraylib;
TextFindIndex :: (text: *u8, find: *u8) -> s32 #foreign libraylib;
TextToUpper :: (text: *u8) -> *u8 #foreign libraylib;
TextToLower :: (text: *u8) -> *u8 #foreign libraylib;
TextToPascal :: (text: *u8) -> *u8 #foreign libraylib;
TextToSnake :: (text: *u8) -> *u8 #foreign libraylib;
TextToCamel :: (text: *u8) -> *u8 #foreign libraylib;

TextToInteger :: (text: *u8) -> s32 #foreign libraylib;
TextToFloat :: (text: *u8) -> float #foreign libraylib;

// Basic geometric 3D shapes drawing functions
DrawLine3D :: (startPos: Vector3, endPos: Vector3, color: Color) -> void #foreign libraylib;
DrawPoint3D :: (position: Vector3, color: Color) -> void #foreign libraylib;
DrawCircle3D :: (center: Vector3, radius: float, rotationAxis: Vector3, rotationAngle: float, color: Color) -> void #foreign libraylib;
DrawTriangle3D :: (v1: Vector3, v2: Vector3, v3: Vector3, color: Color) -> void #foreign libraylib;
DrawTriangleStrip3D :: (points: *Vector3, pointCount: s32, color: Color) -> void #foreign libraylib;
DrawCube :: (position: Vector3, width: float, height: float, length: float, color: Color) -> void #foreign libraylib;
DrawCubeV :: (position: Vector3, size: Vector3, color: Color) -> void #foreign libraylib;
DrawCubeWires :: (position: Vector3, width: float, height: float, length: float, color: Color) -> void #foreign libraylib;
DrawCubeWiresV :: (position: Vector3, size: Vector3, color: Color) -> void #foreign libraylib;
DrawSphere :: (centerPos: Vector3, radius: float, color: Color) -> void #foreign libraylib;
DrawSphereEx :: (centerPos: Vector3, radius: float, rings: s32, slices: s32, color: Color) -> void #foreign libraylib;
DrawSphereWires :: (centerPos: Vector3, radius: float, rings: s32, slices: s32, color: Color) -> void #foreign libraylib;
DrawCylinder :: (position: Vector3, radiusTop: float, radiusBottom: float, height: float, slices: s32, color: Color) -> void #foreign libraylib;
DrawCylinderEx :: (startPos: Vector3, endPos: Vector3, startRadius: float, endRadius: float, sides: s32, color: Color) -> void #foreign libraylib;
DrawCylinderWires :: (position: Vector3, radiusTop: float, radiusBottom: float, height: float, slices: s32, color: Color) -> void #foreign libraylib;
DrawCylinderWiresEx :: (startPos: Vector3, endPos: Vector3, startRadius: float, endRadius: float, sides: s32, color: Color) -> void #foreign libraylib;
DrawCapsule :: (startPos: Vector3, endPos: Vector3, radius: float, slices: s32, rings: s32, color: Color) -> void #foreign libraylib;
DrawCapsuleWires :: (startPos: Vector3, endPos: Vector3, radius: float, slices: s32, rings: s32, color: Color) -> void #foreign libraylib;
DrawPlane :: (centerPos: Vector3, size: Vector2, color: Color) -> void #foreign libraylib;
DrawRay :: (ray: Ray, color: Color) -> void #foreign libraylib;
DrawGrid :: (slices: s32, spacing: float) -> void #foreign libraylib;

// Model management functions
LoadModel :: (fileName: *u8) -> Model #foreign libraylib;
LoadModelFromMesh :: (mesh: Mesh) -> Model #foreign libraylib;
IsModelValid :: (model: Model) -> bool #foreign libraylib;
UnloadModel :: (model: Model) -> void #foreign libraylib;
GetModelBoundingBox :: (model: Model) -> BoundingBox #foreign libraylib;

// Model drawing functions
DrawModel :: (model: Model, position: Vector3, scale: float, tint: Color) -> void #foreign libraylib;
DrawModelEx :: (model: Model, position: Vector3, rotationAxis: Vector3, rotationAngle: float, scale: Vector3, tint: Color) -> void #foreign libraylib;
DrawModelWires :: (model: Model, position: Vector3, scale: float, tint: Color) -> void #foreign libraylib;
DrawModelWiresEx :: (model: Model, position: Vector3, rotationAxis: Vector3, rotationAngle: float, scale: Vector3, tint: Color) -> void #foreign libraylib;
DrawModelPoints :: (model: Model, position: Vector3, scale: float, tint: Color) -> void #foreign libraylib;
DrawModelPointsEx :: (model: Model, position: Vector3, rotationAxis: Vector3, rotationAngle: float, scale: Vector3, tint: Color) -> void #foreign libraylib;
DrawBoundingBox :: (box: BoundingBox, color: Color) -> void #foreign libraylib;
DrawBillboard :: (camera: Camera, texture: Texture2D, position: Vector3, scale: float, tint: Color) -> void #foreign libraylib;
DrawBillboardRec :: (camera: Camera, texture: Texture2D, source: Rectangle, position: Vector3, size: Vector2, tint: Color) -> void #foreign libraylib;
DrawBillboardPro :: (camera: Camera, texture: Texture2D, source: Rectangle, position: Vector3, up: Vector3, size: Vector2, origin: Vector2, rotation: float, tint: Color) -> void #foreign libraylib;

// Mesh management functions
UploadMesh :: (mesh: *Mesh, dynamic: bool) -> void #foreign libraylib;
UpdateMeshBuffer :: (mesh: Mesh, index: s32, data: *void, dataSize: s32, offset: s32) -> void #foreign libraylib;
UnloadMesh :: (mesh: Mesh) -> void #foreign libraylib;
DrawMesh :: (mesh: Mesh, material: Material, transform: Matrix) -> void #foreign libraylib;
DrawMeshInstanced :: (mesh: Mesh, material: Material, transforms: *Matrix, instances: s32) -> void #foreign libraylib;
GetMeshBoundingBox :: (mesh: Mesh) -> BoundingBox #foreign libraylib;
GenMeshTangents :: (mesh: *Mesh) -> void #foreign libraylib;
ExportMesh :: (mesh: Mesh, fileName: *u8) -> bool #foreign libraylib;
ExportMeshAsCode :: (mesh: Mesh, fileName: *u8) -> bool #foreign libraylib;

// Mesh generation functions
GenMeshPoly :: (sides: s32, radius: float) -> Mesh #foreign libraylib;
GenMeshPlane :: (width: float, length: float, resX: s32, resZ: s32) -> Mesh #foreign libraylib;
GenMeshCube :: (width: float, height: float, length: float) -> Mesh #foreign libraylib;
GenMeshSphere :: (radius: float, rings: s32, slices: s32) -> Mesh #foreign libraylib;
GenMeshHemiSphere :: (radius: float, rings: s32, slices: s32) -> Mesh #foreign libraylib;
GenMeshCylinder :: (radius: float, height: float, slices: s32) -> Mesh #foreign libraylib;
GenMeshCone :: (radius: float, height: float, slices: s32) -> Mesh #foreign libraylib;
GenMeshTorus :: (radius: float, size: float, radSeg: s32, sides: s32) -> Mesh #foreign libraylib;
GenMeshKnot :: (radius: float, size: float, radSeg: s32, sides: s32) -> Mesh #foreign libraylib;
GenMeshHeightmap :: (heightmap: Image, size: Vector3) -> Mesh #foreign libraylib;
GenMeshCubicmap :: (cubicmap: Image, cubeSize: Vector3) -> Mesh #foreign libraylib;

// Material loading/unloading functions
LoadMaterials :: (fileName: *u8, materialCount: *s32) -> *Material #foreign libraylib;
LoadMaterialDefault :: () -> Material #foreign libraylib;
IsMaterialValid :: (material: Material) -> bool #foreign libraylib;
UnloadMaterial :: (material: Material) -> void #foreign libraylib;
SetMaterialTexture :: (material: *Material, mapType: MaterialMapIndex, texture: Texture2D) -> void #foreign libraylib;
SetModelMeshMaterial :: (model: *Model, meshId: s32, materialId: s32) -> void #foreign libraylib;

// Model animations loading/unloading functions
LoadModelAnimations :: (fileName: *u8, animCount: *s32) -> *ModelAnimation #foreign libraylib;
UpdateModelAnimation :: (model: Model, anim: ModelAnimation, frame: s32) -> void #foreign libraylib;
UpdateModelAnimationBones :: (model: Model, anim: ModelAnimation, frame: s32) -> void #foreign libraylib;
UnloadModelAnimation :: (anim: ModelAnimation) -> void #foreign libraylib;
UnloadModelAnimations :: (animations: *ModelAnimation, animCount: s32) -> void #foreign libraylib;
IsModelAnimationValid :: (model: Model, anim: ModelAnimation) -> bool #foreign libraylib;

// Collision detection functions
CheckCollisionSpheres :: (center1: Vector3, radius1: float, center2: Vector3, radius2: float) -> bool #foreign libraylib;
CheckCollisionBoxes :: (box1: BoundingBox, box2: BoundingBox) -> bool #foreign libraylib;
CheckCollisionBoxSphere :: (box: BoundingBox, center: Vector3, radius: float) -> bool #foreign libraylib;
GetRayCollisionSphere :: (ray: Ray, center: Vector3, radius: float) -> RayCollision #foreign libraylib;
GetRayCollisionBox :: (ray: Ray, box: BoundingBox) -> RayCollision #foreign libraylib;
GetRayCollisionMesh :: (ray: Ray, mesh: Mesh, transform: Matrix) -> RayCollision #foreign libraylib;
GetRayCollisionTriangle :: (ray: Ray, p1: Vector3, p2: Vector3, p3: Vector3) -> RayCollision #foreign libraylib;
GetRayCollisionQuad :: (ray: Ray, p1: Vector3, p2: Vector3, p3: Vector3, p4: Vector3) -> RayCollision #foreign libraylib;

//------------------------------------------------------------------------------------
// Audio Loading and Playing Functions (Module: audio)
//------------------------------------------------------------------------------------
AudioCallback :: #type (bufferData: *void, frames: u32) -> void #c_call;

// Audio device management functions
InitAudioDevice :: () -> void #foreign libraylib;
CloseAudioDevice :: () -> void #foreign libraylib;
IsAudioDeviceReady :: () -> bool #foreign libraylib;
SetMasterVolume :: (volume: float) -> void #foreign libraylib;
GetMasterVolume :: () -> float #foreign libraylib;

// Wave/Sound loading/unloading functions
LoadWave :: (fileName: *u8) -> Wave #foreign libraylib;
LoadWaveFromMemory :: (fileType: *u8, fileData: *u8, dataSize: s32) -> Wave #foreign libraylib;
IsWaveValid :: (wave: Wave) -> bool #foreign libraylib;
LoadSound :: (fileName: *u8) -> Sound #foreign libraylib;
LoadSoundFromWave :: (wave: Wave) -> Sound #foreign libraylib;
LoadSoundAlias :: (source: Sound) -> Sound #foreign libraylib;
IsSoundValid :: (sound: Sound) -> bool #foreign libraylib;
UpdateSound :: (sound: Sound, data: *void, sampleCount: s32) -> void #foreign libraylib;
UnloadWave :: (wave: Wave) -> void #foreign libraylib;
UnloadSound :: (sound: Sound) -> void #foreign libraylib;
UnloadSoundAlias :: (alias: Sound) -> void #foreign libraylib;
ExportWave :: (wave: Wave, fileName: *u8) -> bool #foreign libraylib;
ExportWaveAsCode :: (wave: Wave, fileName: *u8) -> bool #foreign libraylib;

// Wave/Sound management functions
PlaySound :: (sound: Sound) -> void #foreign libraylib;
StopSound :: (sound: Sound) -> void #foreign libraylib;
PauseSound :: (sound: Sound) -> void #foreign libraylib;
ResumeSound :: (sound: Sound) -> void #foreign libraylib;
IsSoundPlaying :: (sound: Sound) -> bool #foreign libraylib;
SetSoundVolume :: (sound: Sound, volume: float) -> void #foreign libraylib;
SetSoundPitch :: (sound: Sound, pitch: float) -> void #foreign libraylib;
SetSoundPan :: (sound: Sound, pan: float) -> void #foreign libraylib;
WaveCopy :: (wave: Wave) -> Wave #foreign libraylib;
WaveCrop :: (wave: *Wave, initFrame: s32, finalFrame: s32) -> void #foreign libraylib;
WaveFormat :: (wave: *Wave, sampleRate: s32, sampleSize: s32, channels: s32) -> void #foreign libraylib;
LoadWaveSamples :: (wave: Wave) -> *float #foreign libraylib;
UnloadWaveSamples :: (samples: *float) -> void #foreign libraylib;

// Music management functions
LoadMusicStream :: (fileName: *u8) -> Music #foreign libraylib;
LoadMusicStreamFromMemory :: (fileType: *u8, data: *u8, dataSize: s32) -> Music #foreign libraylib;
IsMusicValid :: (music: Music) -> bool #foreign libraylib;
UnloadMusicStream :: (music: Music) -> void #foreign libraylib;
PlayMusicStream :: (music: Music) -> void #foreign libraylib;
IsMusicStreamPlaying :: (music: Music) -> bool #foreign libraylib;
UpdateMusicStream :: (music: Music) -> void #foreign libraylib;
StopMusicStream :: (music: Music) -> void #foreign libraylib;
PauseMusicStream :: (music: Music) -> void #foreign libraylib;
ResumeMusicStream :: (music: Music) -> void #foreign libraylib;
SeekMusicStream :: (music: Music, position: float) -> void #foreign libraylib;
SetMusicVolume :: (music: Music, volume: float) -> void #foreign libraylib;
SetMusicPitch :: (music: Music, pitch: float) -> void #foreign libraylib;
SetMusicPan :: (music: Music, pan: float) -> void #foreign libraylib;
GetMusicTimeLength :: (music: Music) -> float #foreign libraylib;
GetMusicTimePlayed :: (music: Music) -> float #foreign libraylib;

// AudioStream management functions
LoadAudioStream :: (sampleRate: u32, sampleSize: u32, channels: u32) -> AudioStream #foreign libraylib;
IsAudioStreamValid :: (stream: AudioStream) -> bool #foreign libraylib;
UnloadAudioStream :: (stream: AudioStream) -> void #foreign libraylib;
UpdateAudioStream :: (stream: AudioStream, data: *void, frameCount: s32) -> void #foreign libraylib;
IsAudioStreamProcessed :: (stream: AudioStream) -> bool #foreign libraylib;
PlayAudioStream :: (stream: AudioStream) -> void #foreign libraylib;
PauseAudioStream :: (stream: AudioStream) -> void #foreign libraylib;
ResumeAudioStream :: (stream: AudioStream) -> void #foreign libraylib;
IsAudioStreamPlaying :: (stream: AudioStream) -> bool #foreign libraylib;
StopAudioStream :: (stream: AudioStream) -> void #foreign libraylib;
SetAudioStreamVolume :: (stream: AudioStream, volume: float) -> void #foreign libraylib;
SetAudioStreamPitch :: (stream: AudioStream, pitch: float) -> void #foreign libraylib;
SetAudioStreamPan :: (stream: AudioStream, pan: float) -> void #foreign libraylib;
SetAudioStreamBufferSizeDefault :: (size: s32) -> void #foreign libraylib;
SetAudioStreamCallback :: (stream: AudioStream, callback: AudioCallback) -> void #foreign libraylib;

AttachAudioStreamProcessor :: (stream: AudioStream, processor: AudioCallback) -> void #foreign libraylib;
DetachAudioStreamProcessor :: (stream: AudioStream, processor: AudioCallback) -> void #foreign libraylib;

AttachAudioMixedProcessor :: (processor: AudioCallback) -> void #foreign libraylib;
DetachAudioMixedProcessor :: (processor: AudioCallback) -> void #foreign libraylib;

// NOTE: Helper types to be used instead of array return types for *ToFloat functions
float3 :: struct {
    v: [3] float;
}

float16 :: struct {
    v: [16] float;
}

// Clamp float value
Clamp :: (value: float, min: float, max: float) -> float #foreign libraylib;

// Calculate linear interpolation between two floats
Lerp :: (start: float, end: float, amount: float) -> float #foreign libraylib;

// Normalize input value within input range
Normalize :: (value: float, start: float, end: float) -> float #foreign libraylib;

// Remap input value within input range to output range
Remap :: (value: float, inputStart: float, inputEnd: float, outputStart: float, outputEnd: float) -> float #foreign libraylib;

// Wrap input value from min to max
Wrap :: (value: float, min: float, max: float) -> float #foreign libraylib;

// Check whether two given floats are almost equal
FloatEquals :: (x: float, y: float) -> s32 #foreign libraylib;

// Vector with components value 0.0f
Vector2Zero :: () -> Vector2 #foreign libraylib;

// Vector with components value 1.0f
Vector2One :: () -> Vector2 #foreign libraylib;

// Add two vectors (v1 + v2)
Vector2Add :: (v1: Vector2, v2: Vector2) -> Vector2 #foreign libraylib;

// Add vector and float value
Vector2AddValue :: (v: Vector2, add: float) -> Vector2 #foreign libraylib;

// Subtract two vectors (v1 - v2)
Vector2Subtract :: (v1: Vector2, v2: Vector2) -> Vector2 #foreign libraylib;

// Subtract vector by float value
Vector2SubtractValue :: (v: Vector2, sub: float) -> Vector2 #foreign libraylib;

// Calculate vector length
Vector2Length :: (v: Vector2) -> float #foreign libraylib;

// Calculate vector square length
Vector2LengthSqr :: (v: Vector2) -> float #foreign libraylib;

// Calculate two vectors dot product
Vector2DotProduct :: (v1: Vector2, v2: Vector2) -> float #foreign libraylib;

// Calculate distance between two vectors
Vector2Distance :: (v1: Vector2, v2: Vector2) -> float #foreign libraylib;

// Calculate square distance between two vectors
Vector2DistanceSqr :: (v1: Vector2, v2: Vector2) -> float #foreign libraylib;

// Calculate angle between two vectors
// NOTE: Angle is calculated from origin point (0, 0)
Vector2Angle :: (v1: Vector2, v2: Vector2) -> float #foreign libraylib;

// Calculate angle defined by a two vectors line
// NOTE: Parameters need to be normalized
// Current implementation should be aligned with glm::angle
Vector2LineAngle :: (start: Vector2, end: Vector2) -> float #foreign libraylib;

// Scale vector (multiply by value)
Vector2Scale :: (v: Vector2, scale: float) -> Vector2 #foreign libraylib;

// Multiply vector by vector
Vector2Multiply :: (v1: Vector2, v2: Vector2) -> Vector2 #foreign libraylib;

// Negate vector
Vector2Negate :: (v: Vector2) -> Vector2 #foreign libraylib;

// Divide vector by vector
Vector2Divide :: (v1: Vector2, v2: Vector2) -> Vector2 #foreign libraylib;

// Normalize provided vector
Vector2Normalize :: (v: Vector2) -> Vector2 #foreign libraylib;

// Transforms a Vector2 by a given Matrix
Vector2Transform :: (v: Vector2, mat: Matrix) -> Vector2 #foreign libraylib;

// Calculate linear interpolation between two vectors
Vector2Lerp :: (v1: Vector2, v2: Vector2, amount: float) -> Vector2 #foreign libraylib;

// Calculate reflected vector to normal
Vector2Reflect :: (v: Vector2, normal: Vector2) -> Vector2 #foreign libraylib;

// Get min value for each pair of components
Vector2Min :: (v1: Vector2, v2: Vector2) -> Vector2 #foreign libraylib;

// Get max value for each pair of components
Vector2Max :: (v1: Vector2, v2: Vector2) -> Vector2 #foreign libraylib;

// Rotate vector by angle
Vector2Rotate :: (v: Vector2, angle: float) -> Vector2 #foreign libraylib;

// Move Vector towards target
Vector2MoveTowards :: (v: Vector2, target: Vector2, maxDistance: float) -> Vector2 #foreign libraylib;

// Invert the given vector
Vector2Invert :: (v: Vector2) -> Vector2 #foreign libraylib;

// Clamp the components of the vector between
// min and max values specified by the given vectors
Vector2Clamp :: (v: Vector2, min: Vector2, max: Vector2) -> Vector2 #foreign libraylib;

// Clamp the magnitude of the vector between two min and max values
Vector2ClampValue :: (v: Vector2, min: float, max: float) -> Vector2 #foreign libraylib;

// Check whether two given vectors are almost equal
Vector2Equals :: (p: Vector2, q: Vector2) -> s32 #foreign libraylib;

// Compute the direction of a refracted ray
// v: normalized direction of the incoming ray
// n: normalized normal vector of the interface of two optical media
// r: ratio of the refractive index of the medium from where the ray comes
//    to the refractive index of the medium on the other side of the surface
Vector2Refract :: (v: Vector2, n: Vector2, r: float) -> Vector2 #foreign libraylib;

// Vector with components value 0.0f
Vector3Zero :: () -> Vector3 #foreign libraylib;

// Vector with components value 1.0f
Vector3One :: () -> Vector3 #foreign libraylib;

// Add two vectors
Vector3Add :: (v1: Vector3, v2: Vector3) -> Vector3 #foreign libraylib;

// Add vector and float value
Vector3AddValue :: (v: Vector3, add: float) -> Vector3 #foreign libraylib;

// Subtract two vectors
Vector3Subtract :: (v1: Vector3, v2: Vector3) -> Vector3 #foreign libraylib;

// Subtract vector by float value
Vector3SubtractValue :: (v: Vector3, sub: float) -> Vector3 #foreign libraylib;

// Multiply vector by scalar
Vector3Scale :: (v: Vector3, scalar: float) -> Vector3 #foreign libraylib;

// Multiply vector by vector
Vector3Multiply :: (v1: Vector3, v2: Vector3) -> Vector3 #foreign libraylib;

// Calculate two vectors cross product
Vector3CrossProduct :: (v1: Vector3, v2: Vector3) -> Vector3 #foreign libraylib;

// Calculate one vector perpendicular vector
Vector3Perpendicular :: (v: Vector3) -> Vector3 #foreign libraylib;

// Calculate vector length
Vector3Length :: (v: Vector3) -> float #foreign libraylib;

// Calculate vector square length
Vector3LengthSqr :: (v: Vector3) -> float #foreign libraylib;

// Calculate two vectors dot product
Vector3DotProduct :: (v1: Vector3, v2: Vector3) -> float #foreign libraylib;

// Calculate distance between two vectors
Vector3Distance :: (v1: Vector3, v2: Vector3) -> float #foreign libraylib;

// Calculate square distance between two vectors
Vector3DistanceSqr :: (v1: Vector3, v2: Vector3) -> float #foreign libraylib;

// Calculate angle between two vectors
Vector3Angle :: (v1: Vector3, v2: Vector3) -> float #foreign libraylib;

// Negate provided vector (invert direction)
Vector3Negate :: (v: Vector3) -> Vector3 #foreign libraylib;

// Divide vector by vector
Vector3Divide :: (v1: Vector3, v2: Vector3) -> Vector3 #foreign libraylib;

// Normalize provided vector
Vector3Normalize :: (v: Vector3) -> Vector3 #foreign libraylib;

//Calculate the projection of the vector v1 on to v2
Vector3Project :: (v1: Vector3, v2: Vector3) -> Vector3 #foreign libraylib;

//Calculate the rejection of the vector v1 on to v2
Vector3Reject :: (v1: Vector3, v2: Vector3) -> Vector3 #foreign libraylib;

// Orthonormalize provided vectors
// Makes vectors normalized and orthogonal to each other
// Gram-Schmidt function implementation
Vector3OrthoNormalize :: (v1: *Vector3, v2: *Vector3) -> void #foreign libraylib;

// Transforms a Vector3 by a given Matrix
Vector3Transform :: (v: Vector3, mat: Matrix) -> Vector3 #foreign libraylib;

// Transform a vector by quaternion rotation
Vector3RotateByQuaternion :: (v: Vector3, q: Quaternion) -> Vector3 #foreign libraylib;

// Rotates a vector around an axis
Vector3RotateByAxisAngle :: (v: Vector3, axis: Vector3, angle: float) -> Vector3 #foreign libraylib;

// Move Vector towards target
Vector3MoveTowards :: (v: Vector3, target: Vector3, maxDistance: float) -> Vector3 #foreign libraylib;

// Calculate linear interpolation between two vectors
Vector3Lerp :: (v1: Vector3, v2: Vector3, amount: float) -> Vector3 #foreign libraylib;

// Calculate cubic hermite interpolation between two vectors and their tangents
// as described in the GLTF 2.0 specification: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#interpolation-cubic
Vector3CubicHermite :: (v1: Vector3, tangent1: Vector3, v2: Vector3, tangent2: Vector3, amount: float) -> Vector3 #foreign libraylib;

// Calculate reflected vector to normal
Vector3Reflect :: (v: Vector3, normal: Vector3) -> Vector3 #foreign libraylib;

// Get min value for each pair of components
Vector3Min :: (v1: Vector3, v2: Vector3) -> Vector3 #foreign libraylib;

// Get max value for each pair of components
Vector3Max :: (v1: Vector3, v2: Vector3) -> Vector3 #foreign libraylib;

// Compute barycenter coordinates (u, v, w) for point p with respect to triangle (a, b, c)
// NOTE: Assumes P is on the plane of the triangle
Vector3Barycenter :: (p: Vector3, a: Vector3, b: Vector3, c: Vector3) -> Vector3 #foreign libraylib;

// Projects a Vector3 from screen space into object space
// NOTE: We are avoiding calling other raymath functions despite available
Vector3Unproject :: (source: Vector3, projection: Matrix, view: Matrix) -> Vector3 #foreign libraylib;

// Get Vector3 as float array
Vector3ToFloatV :: (v: Vector3) -> float3 #foreign libraylib;

// Invert the given vector
Vector3Invert :: (v: Vector3) -> Vector3 #foreign libraylib;

// Clamp the components of the vector between
// min and max values specified by the given vectors
Vector3Clamp :: (v: Vector3, min: Vector3, max: Vector3) -> Vector3 #foreign libraylib;

// Clamp the magnitude of the vector between two values
Vector3ClampValue :: (v: Vector3, min: float, max: float) -> Vector3 #foreign libraylib;

// Check whether two given vectors are almost equal
Vector3Equals :: (p: Vector3, q: Vector3) -> s32 #foreign libraylib;

// Compute the direction of a refracted ray
// v: normalized direction of the incoming ray
// n: normalized normal vector of the interface of two optical media
// r: ratio of the refractive index of the medium from where the ray comes
//    to the refractive index of the medium on the other side of the surface
Vector3Refract :: (v: Vector3, n: Vector3, r: float) -> Vector3 #foreign libraylib;

//----------------------------------------------------------------------------------
// Module Functions Definition - Vector4 math
//----------------------------------------------------------------------------------
Vector4Zero :: () -> Vector4 #foreign libraylib;

Vector4One :: () -> Vector4 #foreign libraylib;

Vector4Add :: (v1: Vector4, v2: Vector4) -> Vector4 #foreign libraylib;

Vector4AddValue :: (v: Vector4, add: float) -> Vector4 #foreign libraylib;

Vector4Subtract :: (v1: Vector4, v2: Vector4) -> Vector4 #foreign libraylib;

Vector4SubtractValue :: (v: Vector4, add: float) -> Vector4 #foreign libraylib;

Vector4Length :: (v: Vector4) -> float #foreign libraylib;

Vector4LengthSqr :: (v: Vector4) -> float #foreign libraylib;

Vector4DotProduct :: (v1: Vector4, v2: Vector4) -> float #foreign libraylib;

// Calculate distance between two vectors
Vector4Distance :: (v1: Vector4, v2: Vector4) -> float #foreign libraylib;

// Calculate square distance between two vectors
Vector4DistanceSqr :: (v1: Vector4, v2: Vector4) -> float #foreign libraylib;

Vector4Scale :: (v: Vector4, scale: float) -> Vector4 #foreign libraylib;

// Multiply vector by vector
Vector4Multiply :: (v1: Vector4, v2: Vector4) -> Vector4 #foreign libraylib;

// Negate vector
Vector4Negate :: (v: Vector4) -> Vector4 #foreign libraylib;

// Divide vector by vector
Vector4Divide :: (v1: Vector4, v2: Vector4) -> Vector4 #foreign libraylib;

// Normalize provided vector
Vector4Normalize :: (v: Vector4) -> Vector4 #foreign libraylib;

// Get min value for each pair of components
Vector4Min :: (v1: Vector4, v2: Vector4) -> Vector4 #foreign libraylib;

// Get max value for each pair of components
Vector4Max :: (v1: Vector4, v2: Vector4) -> Vector4 #foreign libraylib;

// Calculate linear interpolation between two vectors
Vector4Lerp :: (v1: Vector4, v2: Vector4, amount: float) -> Vector4 #foreign libraylib;

// Move Vector towards target
Vector4MoveTowards :: (v: Vector4, target: Vector4, maxDistance: float) -> Vector4 #foreign libraylib;

// Invert the given vector
Vector4Invert :: (v: Vector4) -> Vector4 #foreign libraylib;

// Check whether two given vectors are almost equal
Vector4Equals :: (p: Vector4, q: Vector4) -> s32 #foreign libraylib;

// Compute matrix determinant
MatrixDeterminant :: (mat: Matrix) -> float #foreign libraylib;

// Get the trace of the matrix (sum of the values along the diagonal)
MatrixTrace :: (mat: Matrix) -> float #foreign libraylib;

// Transposes provided matrix
MatrixTranspose :: (mat: Matrix) -> Matrix #foreign libraylib;

// Invert provided matrix
MatrixInvert :: (mat: Matrix) -> Matrix #foreign libraylib;

// Get identity matrix
MatrixIdentity :: () -> Matrix #foreign libraylib;

// Add two matrices
MatrixAdd :: (left: Matrix, right: Matrix) -> Matrix #foreign libraylib;

// Subtract two matrices (left - right)
MatrixSubtract :: (left: Matrix, right: Matrix) -> Matrix #foreign libraylib;

// Get two matrix multiplication
// NOTE: When multiplying matrices... the order matters!
MatrixMultiply :: (left: Matrix, right: Matrix) -> Matrix #foreign libraylib;

// Get translation matrix
MatrixTranslate :: (x: float, y: float, z: float) -> Matrix #foreign libraylib;

// Create rotation matrix from axis and angle
// NOTE: Angle should be provided in radians
MatrixRotate :: (axis: Vector3, angle: float) -> Matrix #foreign libraylib;

// Get x-rotation matrix
// NOTE: Angle must be provided in radians
MatrixRotateX :: (angle: float) -> Matrix #foreign libraylib;

// Get y-rotation matrix
// NOTE: Angle must be provided in radians
MatrixRotateY :: (angle: float) -> Matrix #foreign libraylib;

// Get z-rotation matrix
// NOTE: Angle must be provided in radians
MatrixRotateZ :: (angle: float) -> Matrix #foreign libraylib;

// Get xyz-rotation matrix
// NOTE: Angle must be provided in radians
MatrixRotateXYZ :: (angle: Vector3) -> Matrix #foreign libraylib;

// Get zyx-rotation matrix
// NOTE: Angle must be provided in radians
MatrixRotateZYX :: (angle: Vector3) -> Matrix #foreign libraylib;

// Get scaling matrix
MatrixScale :: (x: float, y: float, z: float) -> Matrix #foreign libraylib;

// Get perspective projection matrix
MatrixFrustum :: (left: float64, right: float64, bottom: float64, top: float64, nearPlane: float64, farPlane: float64) -> Matrix #foreign libraylib;

// Get perspective projection matrix
// NOTE: Fovy angle must be provided in radians
MatrixPerspective :: (fovY: float64, aspect: float64, nearPlane: float64, farPlane: float64) -> Matrix #foreign libraylib;

// Get orthographic projection matrix
MatrixOrtho :: (left: float64, right: float64, bottom: float64, top: float64, nearPlane: float64, farPlane: float64) -> Matrix #foreign libraylib;

// Get camera look-at matrix (view matrix)
MatrixLookAt :: (eye: Vector3, target: Vector3, up: Vector3) -> Matrix #foreign libraylib;

// Get float array of matrix data
MatrixToFloatV :: (mat: Matrix) -> float16 #foreign libraylib;

// Add two quaternions
QuaternionAdd :: (q1: Quaternion, q2: Quaternion) -> Quaternion #foreign libraylib;

// Add quaternion and float value
QuaternionAddValue :: (q: Quaternion, add: float) -> Quaternion #foreign libraylib;

// Subtract two quaternions
QuaternionSubtract :: (q1: Quaternion, q2: Quaternion) -> Quaternion #foreign libraylib;

// Subtract quaternion and float value
QuaternionSubtractValue :: (q: Quaternion, sub: float) -> Quaternion #foreign libraylib;

// Get identity quaternion
QuaternionIdentity :: () -> Quaternion #foreign libraylib;

// Computes the length of a quaternion
QuaternionLength :: (q: Quaternion) -> float #foreign libraylib;

// Normalize provided quaternion
QuaternionNormalize :: (q: Quaternion) -> Quaternion #foreign libraylib;

// Invert provided quaternion
QuaternionInvert :: (q: Quaternion) -> Quaternion #foreign libraylib;

// Calculate two quaternion multiplication
QuaternionMultiply :: (q1: Quaternion, q2: Quaternion) -> Quaternion #foreign libraylib;

// Scale quaternion by float value
QuaternionScale :: (q: Quaternion, mul: float) -> Quaternion #foreign libraylib;

// Divide two quaternions
QuaternionDivide :: (q1: Quaternion, q2: Quaternion) -> Quaternion #foreign libraylib;

// Calculate linear interpolation between two quaternions
QuaternionLerp :: (q1: Quaternion, q2: Quaternion, amount: float) -> Quaternion #foreign libraylib;

// Calculate slerp-optimized interpolation between two quaternions
QuaternionNlerp :: (q1: Quaternion, q2: Quaternion, amount: float) -> Quaternion #foreign libraylib;

// Calculates spherical linear interpolation between two quaternions
QuaternionSlerp :: (q1: Quaternion, q2: Quaternion, amount: float) -> Quaternion #foreign libraylib;

// Calculate quaternion cubic spline interpolation using Cubic Hermite Spline algorithm
// as described in the GLTF 2.0 specification: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#interpolation-cubic
QuaternionCubicHermiteSpline :: (q1: Quaternion, outTangent1: Quaternion, q2: Quaternion, inTangent2: Quaternion, t: float) -> Quaternion #foreign libraylib;

// Calculate quaternion based on the rotation from one vector to another
QuaternionFromVector3ToVector3 :: (from: Vector3, to: Vector3) -> Quaternion #foreign libraylib;

// Get a quaternion for a given rotation matrix
QuaternionFromMatrix :: (mat: Matrix) -> Quaternion #foreign libraylib;

// Get a matrix for a given quaternion
QuaternionToMatrix :: (q: Quaternion) -> Matrix #foreign libraylib;

// Get rotation quaternion for an angle and axis
// NOTE: Angle must be provided in radians
QuaternionFromAxisAngle :: (axis: Vector3, angle: float) -> Quaternion #foreign libraylib;

// Get the rotation angle and axis for a given quaternion
QuaternionToAxisAngle :: (q: Quaternion, outAxis: *Vector3, outAngle: *float) -> void #foreign libraylib;

// Get the quaternion equivalent to Euler angles
// NOTE: Rotation order is ZYX
QuaternionFromEuler :: (pitch: float, yaw: float, roll: float) -> Quaternion #foreign libraylib;

// Get the Euler angles equivalent to quaternion (roll, pitch, yaw)
// NOTE: Angles are returned in a Vector3 struct in radians
QuaternionToEuler :: (q: Quaternion) -> Vector3 #foreign libraylib;

// Transform a quaternion given a transformation matrix
QuaternionTransform :: (q: Quaternion, mat: Matrix) -> Quaternion #foreign libraylib;

// Check whether two given quaternions are almost equal
QuaternionEquals :: (p: Quaternion, q: Quaternion) -> s32 #foreign libraylib;

// Decompose a transformation matrix into its rotational, translational and scaling components
MatrixDecompose :: (mat: Matrix, translation: *Vector3, rotation: *Quaternion, scale: *Vector3) -> void #foreign libraylib;

#scope_file

#import "Basic"; // For assert, push_context


#run {
    {
        info := type_info(Vector2);
        for info.members {
            if it.name == {
                case "x";
                    assert(it.offset_in_bytes == 0, "Vector2.x has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Vector2.x has unexpected size % instead of 4", it.type.runtime_size);
                case "y";
                    assert(it.offset_in_bytes == 4, "Vector2.y has unexpected offset % instead of 4", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Vector2.y has unexpected size % instead of 4", it.type.runtime_size);
            }
        }
        assert(size_of(Vector2) == 8, "Vector2 has size % instead of 8", size_of(Vector2));
    }

    {
        info := type_info(Vector3);
        for info.members {
            if it.name == {
                case "x";
                    assert(it.offset_in_bytes == 0, "Vector3.x has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Vector3.x has unexpected size % instead of 4", it.type.runtime_size);
                case "y";
                    assert(it.offset_in_bytes == 4, "Vector3.y has unexpected offset % instead of 4", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Vector3.y has unexpected size % instead of 4", it.type.runtime_size);
                case "z";
                    assert(it.offset_in_bytes == 8, "Vector3.z has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Vector3.z has unexpected size % instead of 4", it.type.runtime_size);
            }
        }
        assert(size_of(Vector3) == 12, "Vector3 has size % instead of 12", size_of(Vector3));
    }

    {
        info := type_info(Vector4);
        for info.members {
            if it.name == {
                case "x";
                    assert(it.offset_in_bytes == 0, "Vector4.x has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Vector4.x has unexpected size % instead of 4", it.type.runtime_size);
                case "y";
                    assert(it.offset_in_bytes == 4, "Vector4.y has unexpected offset % instead of 4", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Vector4.y has unexpected size % instead of 4", it.type.runtime_size);
                case "z";
                    assert(it.offset_in_bytes == 8, "Vector4.z has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Vector4.z has unexpected size % instead of 4", it.type.runtime_size);
                case "w";
                    assert(it.offset_in_bytes == 12, "Vector4.w has unexpected offset % instead of 12", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Vector4.w has unexpected size % instead of 4", it.type.runtime_size);
            }
        }
        assert(size_of(Vector4) == 16, "Vector4 has size % instead of 16", size_of(Vector4));
    }

    {
        info := type_info(Matrix);
        for info.members {
            if it.name == {
                case "m0";
                    assert(it.offset_in_bytes == 0, "Matrix.m0 has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Matrix.m0 has unexpected size % instead of 4", it.type.runtime_size);
                case "m4";
                    assert(it.offset_in_bytes == 4, "Matrix.m4 has unexpected offset % instead of 4", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Matrix.m4 has unexpected size % instead of 4", it.type.runtime_size);
                case "m8";
                    assert(it.offset_in_bytes == 8, "Matrix.m8 has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Matrix.m8 has unexpected size % instead of 4", it.type.runtime_size);
                case "m12";
                    assert(it.offset_in_bytes == 12, "Matrix.m12 has unexpected offset % instead of 12", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Matrix.m12 has unexpected size % instead of 4", it.type.runtime_size);
                case "m1";
                    assert(it.offset_in_bytes == 16, "Matrix.m1 has unexpected offset % instead of 16", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Matrix.m1 has unexpected size % instead of 4", it.type.runtime_size);
                case "m5";
                    assert(it.offset_in_bytes == 20, "Matrix.m5 has unexpected offset % instead of 20", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Matrix.m5 has unexpected size % instead of 4", it.type.runtime_size);
                case "m9";
                    assert(it.offset_in_bytes == 24, "Matrix.m9 has unexpected offset % instead of 24", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Matrix.m9 has unexpected size % instead of 4", it.type.runtime_size);
                case "m13";
                    assert(it.offset_in_bytes == 28, "Matrix.m13 has unexpected offset % instead of 28", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Matrix.m13 has unexpected size % instead of 4", it.type.runtime_size);
                case "m2";
                    assert(it.offset_in_bytes == 32, "Matrix.m2 has unexpected offset % instead of 32", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Matrix.m2 has unexpected size % instead of 4", it.type.runtime_size);
                case "m6";
                    assert(it.offset_in_bytes == 36, "Matrix.m6 has unexpected offset % instead of 36", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Matrix.m6 has unexpected size % instead of 4", it.type.runtime_size);
                case "m10";
                    assert(it.offset_in_bytes == 40, "Matrix.m10 has unexpected offset % instead of 40", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Matrix.m10 has unexpected size % instead of 4", it.type.runtime_size);
                case "m14";
                    assert(it.offset_in_bytes == 44, "Matrix.m14 has unexpected offset % instead of 44", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Matrix.m14 has unexpected size % instead of 4", it.type.runtime_size);
                case "m3";
                    assert(it.offset_in_bytes == 48, "Matrix.m3 has unexpected offset % instead of 48", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Matrix.m3 has unexpected size % instead of 4", it.type.runtime_size);
                case "m7";
                    assert(it.offset_in_bytes == 52, "Matrix.m7 has unexpected offset % instead of 52", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Matrix.m7 has unexpected size % instead of 4", it.type.runtime_size);
                case "m11";
                    assert(it.offset_in_bytes == 56, "Matrix.m11 has unexpected offset % instead of 56", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Matrix.m11 has unexpected size % instead of 4", it.type.runtime_size);
                case "m15";
                    assert(it.offset_in_bytes == 60, "Matrix.m15 has unexpected offset % instead of 60", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Matrix.m15 has unexpected size % instead of 4", it.type.runtime_size);
            }
        }
        assert(size_of(Matrix) == 64, "Matrix has size % instead of 64", size_of(Matrix));
    }

    {
        info := type_info(Color);
        for info.members {
            if it.name == {
                case "r";
                    assert(it.offset_in_bytes == 0, "Color.r has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 1, "Color.r has unexpected size % instead of 1", it.type.runtime_size);
                case "g";
                    assert(it.offset_in_bytes == 1, "Color.g has unexpected offset % instead of 1", it.offset_in_bytes);
                    assert(it.type.runtime_size == 1, "Color.g has unexpected size % instead of 1", it.type.runtime_size);
                case "b";
                    assert(it.offset_in_bytes == 2, "Color.b has unexpected offset % instead of 2", it.offset_in_bytes);
                    assert(it.type.runtime_size == 1, "Color.b has unexpected size % instead of 1", it.type.runtime_size);
                case "a";
                    assert(it.offset_in_bytes == 3, "Color.a has unexpected offset % instead of 3", it.offset_in_bytes);
                    assert(it.type.runtime_size == 1, "Color.a has unexpected size % instead of 1", it.type.runtime_size);
            }
        }
        assert(size_of(Color) == 4, "Color has size % instead of 4", size_of(Color));
    }

    {
        info := type_info(Rectangle);
        for info.members {
            if it.name == {
                case "x";
                    assert(it.offset_in_bytes == 0, "Rectangle.x has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Rectangle.x has unexpected size % instead of 4", it.type.runtime_size);
                case "y";
                    assert(it.offset_in_bytes == 4, "Rectangle.y has unexpected offset % instead of 4", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Rectangle.y has unexpected size % instead of 4", it.type.runtime_size);
                case "width";
                    assert(it.offset_in_bytes == 8, "Rectangle.width has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Rectangle.width has unexpected size % instead of 4", it.type.runtime_size);
                case "height";
                    assert(it.offset_in_bytes == 12, "Rectangle.height has unexpected offset % instead of 12", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Rectangle.height has unexpected size % instead of 4", it.type.runtime_size);
            }
        }
        assert(size_of(Rectangle) == 16, "Rectangle has size % instead of 16", size_of(Rectangle));
    }

    {
        info := type_info(Image);
        for info.members {
            if it.name == {
                case "data";
                    assert(it.offset_in_bytes == 0, "Image.data has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Image.data has unexpected size % instead of 8", it.type.runtime_size);
                case "width";
                    assert(it.offset_in_bytes == 8, "Image.width has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Image.width has unexpected size % instead of 4", it.type.runtime_size);
                case "height";
                    assert(it.offset_in_bytes == 12, "Image.height has unexpected offset % instead of 12", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Image.height has unexpected size % instead of 4", it.type.runtime_size);
                case "mipmaps";
                    assert(it.offset_in_bytes == 16, "Image.mipmaps has unexpected offset % instead of 16", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Image.mipmaps has unexpected size % instead of 4", it.type.runtime_size);
                case "format";
                    assert(it.offset_in_bytes == 20, "Image.format has unexpected offset % instead of 20", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Image.format has unexpected size % instead of 4", it.type.runtime_size);
            }
        }
        assert(size_of(Image) == 24, "Image has size % instead of 24", size_of(Image));
    }

    {
        info := type_info(Texture);
        for info.members {
            if it.name == {
                case "id";
                    assert(it.offset_in_bytes == 0, "Texture.id has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Texture.id has unexpected size % instead of 4", it.type.runtime_size);
                case "width";
                    assert(it.offset_in_bytes == 4, "Texture.width has unexpected offset % instead of 4", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Texture.width has unexpected size % instead of 4", it.type.runtime_size);
                case "height";
                    assert(it.offset_in_bytes == 8, "Texture.height has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Texture.height has unexpected size % instead of 4", it.type.runtime_size);
                case "mipmaps";
                    assert(it.offset_in_bytes == 12, "Texture.mipmaps has unexpected offset % instead of 12", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Texture.mipmaps has unexpected size % instead of 4", it.type.runtime_size);
                case "format";
                    assert(it.offset_in_bytes == 16, "Texture.format has unexpected offset % instead of 16", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Texture.format has unexpected size % instead of 4", it.type.runtime_size);
            }
        }
        assert(size_of(Texture) == 20, "Texture has size % instead of 20", size_of(Texture));
    }

    {
        info := type_info(RenderTexture);
        for info.members {
            if it.name == {
                case "id";
                    assert(it.offset_in_bytes == 0, "RenderTexture.id has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "RenderTexture.id has unexpected size % instead of 4", it.type.runtime_size);
                case "texture";
                    assert(it.offset_in_bytes == 4, "RenderTexture.texture has unexpected offset % instead of 4", it.offset_in_bytes);
                    assert(it.type.runtime_size == 20, "RenderTexture.texture has unexpected size % instead of 20", it.type.runtime_size);
                case "depth";
                    assert(it.offset_in_bytes == 24, "RenderTexture.depth has unexpected offset % instead of 24", it.offset_in_bytes);
                    assert(it.type.runtime_size == 20, "RenderTexture.depth has unexpected size % instead of 20", it.type.runtime_size);
            }
        }
        assert(size_of(RenderTexture) == 44, "RenderTexture has size % instead of 44", size_of(RenderTexture));
    }

    {
        info := type_info(NPatchInfo);
        for info.members {
            if it.name == {
                case "source";
                    assert(it.offset_in_bytes == 0, "NPatchInfo.source has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 16, "NPatchInfo.source has unexpected size % instead of 16", it.type.runtime_size);
                case "left";
                    assert(it.offset_in_bytes == 16, "NPatchInfo.left has unexpected offset % instead of 16", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "NPatchInfo.left has unexpected size % instead of 4", it.type.runtime_size);
                case "top";
                    assert(it.offset_in_bytes == 20, "NPatchInfo.top has unexpected offset % instead of 20", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "NPatchInfo.top has unexpected size % instead of 4", it.type.runtime_size);
                case "right";
                    assert(it.offset_in_bytes == 24, "NPatchInfo.right has unexpected offset % instead of 24", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "NPatchInfo.right has unexpected size % instead of 4", it.type.runtime_size);
                case "bottom";
                    assert(it.offset_in_bytes == 28, "NPatchInfo.bottom has unexpected offset % instead of 28", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "NPatchInfo.bottom has unexpected size % instead of 4", it.type.runtime_size);
                case "layout";
                    assert(it.offset_in_bytes == 32, "NPatchInfo.layout has unexpected offset % instead of 32", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "NPatchInfo.layout has unexpected size % instead of 4", it.type.runtime_size);
            }
        }
        assert(size_of(NPatchInfo) == 36, "NPatchInfo has size % instead of 36", size_of(NPatchInfo));
    }

    {
        info := type_info(GlyphInfo);
        for info.members {
            if it.name == {
                case "value";
                    assert(it.offset_in_bytes == 0, "GlyphInfo.value has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "GlyphInfo.value has unexpected size % instead of 4", it.type.runtime_size);
                case "offsetX";
                    assert(it.offset_in_bytes == 4, "GlyphInfo.offsetX has unexpected offset % instead of 4", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "GlyphInfo.offsetX has unexpected size % instead of 4", it.type.runtime_size);
                case "offsetY";
                    assert(it.offset_in_bytes == 8, "GlyphInfo.offsetY has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "GlyphInfo.offsetY has unexpected size % instead of 4", it.type.runtime_size);
                case "advanceX";
                    assert(it.offset_in_bytes == 12, "GlyphInfo.advanceX has unexpected offset % instead of 12", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "GlyphInfo.advanceX has unexpected size % instead of 4", it.type.runtime_size);
                case "image";
                    assert(it.offset_in_bytes == 16, "GlyphInfo.image has unexpected offset % instead of 16", it.offset_in_bytes);
                    assert(it.type.runtime_size == 24, "GlyphInfo.image has unexpected size % instead of 24", it.type.runtime_size);
            }
        }
        assert(size_of(GlyphInfo) == 40, "GlyphInfo has size % instead of 40", size_of(GlyphInfo));
    }

    {
        info := type_info(Font);
        for info.members {
            if it.name == {
                case "baseSize";
                    assert(it.offset_in_bytes == 0, "Font.baseSize has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Font.baseSize has unexpected size % instead of 4", it.type.runtime_size);
                case "glyphCount";
                    assert(it.offset_in_bytes == 4, "Font.glyphCount has unexpected offset % instead of 4", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Font.glyphCount has unexpected size % instead of 4", it.type.runtime_size);
                case "glyphPadding";
                    assert(it.offset_in_bytes == 8, "Font.glyphPadding has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Font.glyphPadding has unexpected size % instead of 4", it.type.runtime_size);
                case "texture";
                    assert(it.offset_in_bytes == 12, "Font.texture has unexpected offset % instead of 12", it.offset_in_bytes);
                    assert(it.type.runtime_size == 20, "Font.texture has unexpected size % instead of 20", it.type.runtime_size);
                case "recs";
                    assert(it.offset_in_bytes == 32, "Font.recs has unexpected offset % instead of 32", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Font.recs has unexpected size % instead of 8", it.type.runtime_size);
                case "glyphs";
                    assert(it.offset_in_bytes == 40, "Font.glyphs has unexpected offset % instead of 40", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Font.glyphs has unexpected size % instead of 8", it.type.runtime_size);
            }
        }
        assert(size_of(Font) == 48, "Font has size % instead of 48", size_of(Font));
    }

    {
        info := type_info(Camera3D);
        for info.members {
            if it.name == {
                case "position";
                    assert(it.offset_in_bytes == 0, "Camera3D.position has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 12, "Camera3D.position has unexpected size % instead of 12", it.type.runtime_size);
                case "target";
                    assert(it.offset_in_bytes == 12, "Camera3D.target has unexpected offset % instead of 12", it.offset_in_bytes);
                    assert(it.type.runtime_size == 12, "Camera3D.target has unexpected size % instead of 12", it.type.runtime_size);
                case "up";
                    assert(it.offset_in_bytes == 24, "Camera3D.up has unexpected offset % instead of 24", it.offset_in_bytes);
                    assert(it.type.runtime_size == 12, "Camera3D.up has unexpected size % instead of 12", it.type.runtime_size);
                case "fovy";
                    assert(it.offset_in_bytes == 36, "Camera3D.fovy has unexpected offset % instead of 36", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Camera3D.fovy has unexpected size % instead of 4", it.type.runtime_size);
                case "projection";
                    assert(it.offset_in_bytes == 40, "Camera3D.projection has unexpected offset % instead of 40", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Camera3D.projection has unexpected size % instead of 4", it.type.runtime_size);
            }
        }
        assert(size_of(Camera3D) == 44, "Camera3D has size % instead of 44", size_of(Camera3D));
    }

    {
        info := type_info(Camera2D);
        for info.members {
            if it.name == {
                case "offset";
                    assert(it.offset_in_bytes == 0, "Camera2D.offset has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Camera2D.offset has unexpected size % instead of 8", it.type.runtime_size);
                case "target";
                    assert(it.offset_in_bytes == 8, "Camera2D.target has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Camera2D.target has unexpected size % instead of 8", it.type.runtime_size);
                case "rotation";
                    assert(it.offset_in_bytes == 16, "Camera2D.rotation has unexpected offset % instead of 16", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Camera2D.rotation has unexpected size % instead of 4", it.type.runtime_size);
                case "zoom";
                    assert(it.offset_in_bytes == 20, "Camera2D.zoom has unexpected offset % instead of 20", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Camera2D.zoom has unexpected size % instead of 4", it.type.runtime_size);
            }
        }
        assert(size_of(Camera2D) == 24, "Camera2D has size % instead of 24", size_of(Camera2D));
    }

    {
        info := type_info(Mesh);
        for info.members {
            if it.name == {
                case "vertexCount";
                    assert(it.offset_in_bytes == 0, "Mesh.vertexCount has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Mesh.vertexCount has unexpected size % instead of 4", it.type.runtime_size);
                case "triangleCount";
                    assert(it.offset_in_bytes == 4, "Mesh.triangleCount has unexpected offset % instead of 4", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Mesh.triangleCount has unexpected size % instead of 4", it.type.runtime_size);
                case "vertices";
                    assert(it.offset_in_bytes == 8, "Mesh.vertices has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Mesh.vertices has unexpected size % instead of 8", it.type.runtime_size);
                case "texcoords";
                    assert(it.offset_in_bytes == 16, "Mesh.texcoords has unexpected offset % instead of 16", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Mesh.texcoords has unexpected size % instead of 8", it.type.runtime_size);
                case "texcoords2";
                    assert(it.offset_in_bytes == 24, "Mesh.texcoords2 has unexpected offset % instead of 24", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Mesh.texcoords2 has unexpected size % instead of 8", it.type.runtime_size);
                case "normals";
                    assert(it.offset_in_bytes == 32, "Mesh.normals has unexpected offset % instead of 32", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Mesh.normals has unexpected size % instead of 8", it.type.runtime_size);
                case "tangents";
                    assert(it.offset_in_bytes == 40, "Mesh.tangents has unexpected offset % instead of 40", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Mesh.tangents has unexpected size % instead of 8", it.type.runtime_size);
                case "colors";
                    assert(it.offset_in_bytes == 48, "Mesh.colors has unexpected offset % instead of 48", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Mesh.colors has unexpected size % instead of 8", it.type.runtime_size);
                case "indices";
                    assert(it.offset_in_bytes == 56, "Mesh.indices has unexpected offset % instead of 56", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Mesh.indices has unexpected size % instead of 8", it.type.runtime_size);
                case "animVertices";
                    assert(it.offset_in_bytes == 64, "Mesh.animVertices has unexpected offset % instead of 64", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Mesh.animVertices has unexpected size % instead of 8", it.type.runtime_size);
                case "animNormals";
                    assert(it.offset_in_bytes == 72, "Mesh.animNormals has unexpected offset % instead of 72", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Mesh.animNormals has unexpected size % instead of 8", it.type.runtime_size);
                case "boneIds";
                    assert(it.offset_in_bytes == 80, "Mesh.boneIds has unexpected offset % instead of 80", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Mesh.boneIds has unexpected size % instead of 8", it.type.runtime_size);
                case "boneWeights";
                    assert(it.offset_in_bytes == 88, "Mesh.boneWeights has unexpected offset % instead of 88", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Mesh.boneWeights has unexpected size % instead of 8", it.type.runtime_size);
                case "boneMatrices";
                    assert(it.offset_in_bytes == 96, "Mesh.boneMatrices has unexpected offset % instead of 96", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Mesh.boneMatrices has unexpected size % instead of 8", it.type.runtime_size);
                case "boneCount";
                    assert(it.offset_in_bytes == 104, "Mesh.boneCount has unexpected offset % instead of 104", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Mesh.boneCount has unexpected size % instead of 4", it.type.runtime_size);
                case "vaoId";
                    assert(it.offset_in_bytes == 108, "Mesh.vaoId has unexpected offset % instead of 108", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Mesh.vaoId has unexpected size % instead of 4", it.type.runtime_size);
                case "vboId";
                    assert(it.offset_in_bytes == 112, "Mesh.vboId has unexpected offset % instead of 112", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Mesh.vboId has unexpected size % instead of 8", it.type.runtime_size);
            }
        }
        assert(size_of(Mesh) == 120, "Mesh has size % instead of 120", size_of(Mesh));
    }

    {
        info := type_info(Shader);
        for info.members {
            if it.name == {
                case "id";
                    assert(it.offset_in_bytes == 0, "Shader.id has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Shader.id has unexpected size % instead of 4", it.type.runtime_size);
                case "locs";
                    assert(it.offset_in_bytes == 8, "Shader.locs has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Shader.locs has unexpected size % instead of 8", it.type.runtime_size);
            }
        }
        assert(size_of(Shader) == 16, "Shader has size % instead of 16", size_of(Shader));
    }

    {
        info := type_info(MaterialMap);
        for info.members {
            if it.name == {
                case "texture";
                    assert(it.offset_in_bytes == 0, "MaterialMap.texture has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 20, "MaterialMap.texture has unexpected size % instead of 20", it.type.runtime_size);
                case "color";
                    assert(it.offset_in_bytes == 20, "MaterialMap.color has unexpected offset % instead of 20", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "MaterialMap.color has unexpected size % instead of 4", it.type.runtime_size);
                case "value";
                    assert(it.offset_in_bytes == 24, "MaterialMap.value has unexpected offset % instead of 24", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "MaterialMap.value has unexpected size % instead of 4", it.type.runtime_size);
            }
        }
        assert(size_of(MaterialMap) == 28, "MaterialMap has size % instead of 28", size_of(MaterialMap));
    }

    {
        info := type_info(Material);
        for info.members {
            if it.name == {
                case "shader";
                    assert(it.offset_in_bytes == 0, "Material.shader has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 16, "Material.shader has unexpected size % instead of 16", it.type.runtime_size);
                case "maps";
                    assert(it.offset_in_bytes == 16, "Material.maps has unexpected offset % instead of 16", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Material.maps has unexpected size % instead of 8", it.type.runtime_size);
                case "params";
                    assert(it.offset_in_bytes == 24, "Material.params has unexpected offset % instead of 24", it.offset_in_bytes);
                    assert(it.type.runtime_size == 16, "Material.params has unexpected size % instead of 16", it.type.runtime_size);
            }
        }
        assert(size_of(Material) == 40, "Material has size % instead of 40", size_of(Material));
    }

    {
        info := type_info(Transform);
        for info.members {
            if it.name == {
                case "translation";
                    assert(it.offset_in_bytes == 0, "Transform.translation has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 12, "Transform.translation has unexpected size % instead of 12", it.type.runtime_size);
                case "rotation";
                    assert(it.offset_in_bytes == 12, "Transform.rotation has unexpected offset % instead of 12", it.offset_in_bytes);
                    assert(it.type.runtime_size == 16, "Transform.rotation has unexpected size % instead of 16", it.type.runtime_size);
                case "scale";
                    assert(it.offset_in_bytes == 28, "Transform.scale has unexpected offset % instead of 28", it.offset_in_bytes);
                    assert(it.type.runtime_size == 12, "Transform.scale has unexpected size % instead of 12", it.type.runtime_size);
            }
        }
        assert(size_of(Transform) == 40, "Transform has size % instead of 40", size_of(Transform));
    }

    {
        info := type_info(BoneInfo);
        for info.members {
            if it.name == {
                case "name";
                    assert(it.offset_in_bytes == 0, "BoneInfo.name has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 32, "BoneInfo.name has unexpected size % instead of 32", it.type.runtime_size);
                case "parent";
                    assert(it.offset_in_bytes == 32, "BoneInfo.parent has unexpected offset % instead of 32", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "BoneInfo.parent has unexpected size % instead of 4", it.type.runtime_size);
            }
        }
        assert(size_of(BoneInfo) == 36, "BoneInfo has size % instead of 36", size_of(BoneInfo));
    }

    {
        info := type_info(Model);
        for info.members {
            if it.name == {
                case "transform";
                    assert(it.offset_in_bytes == 0, "Model.transform has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 64, "Model.transform has unexpected size % instead of 64", it.type.runtime_size);
                case "meshCount";
                    assert(it.offset_in_bytes == 64, "Model.meshCount has unexpected offset % instead of 64", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Model.meshCount has unexpected size % instead of 4", it.type.runtime_size);
                case "materialCount";
                    assert(it.offset_in_bytes == 68, "Model.materialCount has unexpected offset % instead of 68", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Model.materialCount has unexpected size % instead of 4", it.type.runtime_size);
                case "meshes";
                    assert(it.offset_in_bytes == 72, "Model.meshes has unexpected offset % instead of 72", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Model.meshes has unexpected size % instead of 8", it.type.runtime_size);
                case "materials";
                    assert(it.offset_in_bytes == 80, "Model.materials has unexpected offset % instead of 80", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Model.materials has unexpected size % instead of 8", it.type.runtime_size);
                case "meshMaterial";
                    assert(it.offset_in_bytes == 88, "Model.meshMaterial has unexpected offset % instead of 88", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Model.meshMaterial has unexpected size % instead of 8", it.type.runtime_size);
                case "boneCount";
                    assert(it.offset_in_bytes == 96, "Model.boneCount has unexpected offset % instead of 96", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Model.boneCount has unexpected size % instead of 4", it.type.runtime_size);
                case "bones";
                    assert(it.offset_in_bytes == 104, "Model.bones has unexpected offset % instead of 104", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Model.bones has unexpected size % instead of 8", it.type.runtime_size);
                case "bindPose";
                    assert(it.offset_in_bytes == 112, "Model.bindPose has unexpected offset % instead of 112", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Model.bindPose has unexpected size % instead of 8", it.type.runtime_size);
            }
        }
        assert(size_of(Model) == 120, "Model has size % instead of 120", size_of(Model));
    }

    {
        info := type_info(ModelAnimation);
        for info.members {
            if it.name == {
                case "boneCount";
                    assert(it.offset_in_bytes == 0, "ModelAnimation.boneCount has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "ModelAnimation.boneCount has unexpected size % instead of 4", it.type.runtime_size);
                case "frameCount";
                    assert(it.offset_in_bytes == 4, "ModelAnimation.frameCount has unexpected offset % instead of 4", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "ModelAnimation.frameCount has unexpected size % instead of 4", it.type.runtime_size);
                case "bones";
                    assert(it.offset_in_bytes == 8, "ModelAnimation.bones has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "ModelAnimation.bones has unexpected size % instead of 8", it.type.runtime_size);
                case "framePoses";
                    assert(it.offset_in_bytes == 16, "ModelAnimation.framePoses has unexpected offset % instead of 16", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "ModelAnimation.framePoses has unexpected size % instead of 8", it.type.runtime_size);
                case "name";
                    assert(it.offset_in_bytes == 24, "ModelAnimation.name has unexpected offset % instead of 24", it.offset_in_bytes);
                    assert(it.type.runtime_size == 32, "ModelAnimation.name has unexpected size % instead of 32", it.type.runtime_size);
            }
        }
        assert(size_of(ModelAnimation) == 56, "ModelAnimation has size % instead of 56", size_of(ModelAnimation));
    }

    {
        info := type_info(Ray);
        for info.members {
            if it.name == {
                case "position";
                    assert(it.offset_in_bytes == 0, "Ray.position has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 12, "Ray.position has unexpected size % instead of 12", it.type.runtime_size);
                case "direction";
                    assert(it.offset_in_bytes == 12, "Ray.direction has unexpected offset % instead of 12", it.offset_in_bytes);
                    assert(it.type.runtime_size == 12, "Ray.direction has unexpected size % instead of 12", it.type.runtime_size);
            }
        }
        assert(size_of(Ray) == 24, "Ray has size % instead of 24", size_of(Ray));
    }

    {
        info := type_info(RayCollision);
        for info.members {
            if it.name == {
                case "hit";
                    assert(it.offset_in_bytes == 0, "RayCollision.hit has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 1, "RayCollision.hit has unexpected size % instead of 1", it.type.runtime_size);
                case "distance";
                    assert(it.offset_in_bytes == 4, "RayCollision.distance has unexpected offset % instead of 4", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "RayCollision.distance has unexpected size % instead of 4", it.type.runtime_size);
                case "point";
                    assert(it.offset_in_bytes == 8, "RayCollision.point has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 12, "RayCollision.point has unexpected size % instead of 12", it.type.runtime_size);
                case "normal";
                    assert(it.offset_in_bytes == 20, "RayCollision.normal has unexpected offset % instead of 20", it.offset_in_bytes);
                    assert(it.type.runtime_size == 12, "RayCollision.normal has unexpected size % instead of 12", it.type.runtime_size);
            }
        }
        assert(size_of(RayCollision) == 32, "RayCollision has size % instead of 32", size_of(RayCollision));
    }

    {
        info := type_info(BoundingBox);
        for info.members {
            if it.name == {
                case "min";
                    assert(it.offset_in_bytes == 0, "BoundingBox.min has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 12, "BoundingBox.min has unexpected size % instead of 12", it.type.runtime_size);
                case "max";
                    assert(it.offset_in_bytes == 12, "BoundingBox.max has unexpected offset % instead of 12", it.offset_in_bytes);
                    assert(it.type.runtime_size == 12, "BoundingBox.max has unexpected size % instead of 12", it.type.runtime_size);
            }
        }
        assert(size_of(BoundingBox) == 24, "BoundingBox has size % instead of 24", size_of(BoundingBox));
    }

    {
        info := type_info(Wave);
        for info.members {
            if it.name == {
                case "frameCount";
                    assert(it.offset_in_bytes == 0, "Wave.frameCount has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Wave.frameCount has unexpected size % instead of 4", it.type.runtime_size);
                case "sampleRate";
                    assert(it.offset_in_bytes == 4, "Wave.sampleRate has unexpected offset % instead of 4", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Wave.sampleRate has unexpected size % instead of 4", it.type.runtime_size);
                case "sampleSize";
                    assert(it.offset_in_bytes == 8, "Wave.sampleSize has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Wave.sampleSize has unexpected size % instead of 4", it.type.runtime_size);
                case "channels";
                    assert(it.offset_in_bytes == 12, "Wave.channels has unexpected offset % instead of 12", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Wave.channels has unexpected size % instead of 4", it.type.runtime_size);
                case "data";
                    assert(it.offset_in_bytes == 16, "Wave.data has unexpected offset % instead of 16", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Wave.data has unexpected size % instead of 8", it.type.runtime_size);
            }
        }
        assert(size_of(Wave) == 24, "Wave has size % instead of 24", size_of(Wave));
    }

    {
        info := type_info(AudioStream);
        for info.members {
            if it.name == {
                case "buffer";
                    assert(it.offset_in_bytes == 0, "AudioStream.buffer has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "AudioStream.buffer has unexpected size % instead of 8", it.type.runtime_size);
                case "processor";
                    assert(it.offset_in_bytes == 8, "AudioStream.processor has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "AudioStream.processor has unexpected size % instead of 8", it.type.runtime_size);
                case "sampleRate";
                    assert(it.offset_in_bytes == 16, "AudioStream.sampleRate has unexpected offset % instead of 16", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "AudioStream.sampleRate has unexpected size % instead of 4", it.type.runtime_size);
                case "sampleSize";
                    assert(it.offset_in_bytes == 20, "AudioStream.sampleSize has unexpected offset % instead of 20", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "AudioStream.sampleSize has unexpected size % instead of 4", it.type.runtime_size);
                case "channels";
                    assert(it.offset_in_bytes == 24, "AudioStream.channels has unexpected offset % instead of 24", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "AudioStream.channels has unexpected size % instead of 4", it.type.runtime_size);
            }
        }
        assert(size_of(AudioStream) == 32, "AudioStream has size % instead of 32", size_of(AudioStream));
    }

    {
        info := type_info(Sound);
        for info.members {
            if it.name == {
                case "stream";
                    assert(it.offset_in_bytes == 0, "Sound.stream has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 32, "Sound.stream has unexpected size % instead of 32", it.type.runtime_size);
                case "frameCount";
                    assert(it.offset_in_bytes == 32, "Sound.frameCount has unexpected offset % instead of 32", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Sound.frameCount has unexpected size % instead of 4", it.type.runtime_size);
            }
        }
        assert(size_of(Sound) == 40, "Sound has size % instead of 40", size_of(Sound));
    }

    {
        info := type_info(Music);
        for info.members {
            if it.name == {
                case "stream";
                    assert(it.offset_in_bytes == 0, "Music.stream has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 32, "Music.stream has unexpected size % instead of 32", it.type.runtime_size);
                case "frameCount";
                    assert(it.offset_in_bytes == 32, "Music.frameCount has unexpected offset % instead of 32", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Music.frameCount has unexpected size % instead of 4", it.type.runtime_size);
                case "looping";
                    assert(it.offset_in_bytes == 36, "Music.looping has unexpected offset % instead of 36", it.offset_in_bytes);
                    assert(it.type.runtime_size == 1, "Music.looping has unexpected size % instead of 1", it.type.runtime_size);
                case "ctxType";
                    assert(it.offset_in_bytes == 40, "Music.ctxType has unexpected offset % instead of 40", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Music.ctxType has unexpected size % instead of 4", it.type.runtime_size);
                case "ctxData";
                    assert(it.offset_in_bytes == 48, "Music.ctxData has unexpected offset % instead of 48", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Music.ctxData has unexpected size % instead of 8", it.type.runtime_size);
            }
        }
        assert(size_of(Music) == 56, "Music has size % instead of 56", size_of(Music));
    }

    {
        info := type_info(VrDeviceInfo);
        for info.members {
            if it.name == {
                case "hResolution";
                    assert(it.offset_in_bytes == 0, "VrDeviceInfo.hResolution has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "VrDeviceInfo.hResolution has unexpected size % instead of 4", it.type.runtime_size);
                case "vResolution";
                    assert(it.offset_in_bytes == 4, "VrDeviceInfo.vResolution has unexpected offset % instead of 4", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "VrDeviceInfo.vResolution has unexpected size % instead of 4", it.type.runtime_size);
                case "hScreenSize";
                    assert(it.offset_in_bytes == 8, "VrDeviceInfo.hScreenSize has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "VrDeviceInfo.hScreenSize has unexpected size % instead of 4", it.type.runtime_size);
                case "vScreenSize";
                    assert(it.offset_in_bytes == 12, "VrDeviceInfo.vScreenSize has unexpected offset % instead of 12", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "VrDeviceInfo.vScreenSize has unexpected size % instead of 4", it.type.runtime_size);
                case "eyeToScreenDistance";
                    assert(it.offset_in_bytes == 16, "VrDeviceInfo.eyeToScreenDistance has unexpected offset % instead of 16", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "VrDeviceInfo.eyeToScreenDistance has unexpected size % instead of 4", it.type.runtime_size);
                case "lensSeparationDistance";
                    assert(it.offset_in_bytes == 20, "VrDeviceInfo.lensSeparationDistance has unexpected offset % instead of 20", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "VrDeviceInfo.lensSeparationDistance has unexpected size % instead of 4", it.type.runtime_size);
                case "interpupillaryDistance";
                    assert(it.offset_in_bytes == 24, "VrDeviceInfo.interpupillaryDistance has unexpected offset % instead of 24", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "VrDeviceInfo.interpupillaryDistance has unexpected size % instead of 4", it.type.runtime_size);
                case "lensDistortionValues";
                    assert(it.offset_in_bytes == 28, "VrDeviceInfo.lensDistortionValues has unexpected offset % instead of 28", it.offset_in_bytes);
                    assert(it.type.runtime_size == 16, "VrDeviceInfo.lensDistortionValues has unexpected size % instead of 16", it.type.runtime_size);
                case "chromaAbCorrection";
                    assert(it.offset_in_bytes == 44, "VrDeviceInfo.chromaAbCorrection has unexpected offset % instead of 44", it.offset_in_bytes);
                    assert(it.type.runtime_size == 16, "VrDeviceInfo.chromaAbCorrection has unexpected size % instead of 16", it.type.runtime_size);
            }
        }
        assert(size_of(VrDeviceInfo) == 60, "VrDeviceInfo has size % instead of 60", size_of(VrDeviceInfo));
    }

    {
        info := type_info(VrStereoConfig);
        for info.members {
            if it.name == {
                case "projection";
                    assert(it.offset_in_bytes == 0, "VrStereoConfig.projection has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 128, "VrStereoConfig.projection has unexpected size % instead of 128", it.type.runtime_size);
                case "viewOffset";
                    assert(it.offset_in_bytes == 128, "VrStereoConfig.viewOffset has unexpected offset % instead of 128", it.offset_in_bytes);
                    assert(it.type.runtime_size == 128, "VrStereoConfig.viewOffset has unexpected size % instead of 128", it.type.runtime_size);
                case "leftLensCenter";
                    assert(it.offset_in_bytes == 256, "VrStereoConfig.leftLensCenter has unexpected offset % instead of 256", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "VrStereoConfig.leftLensCenter has unexpected size % instead of 8", it.type.runtime_size);
                case "rightLensCenter";
                    assert(it.offset_in_bytes == 264, "VrStereoConfig.rightLensCenter has unexpected offset % instead of 264", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "VrStereoConfig.rightLensCenter has unexpected size % instead of 8", it.type.runtime_size);
                case "leftScreenCenter";
                    assert(it.offset_in_bytes == 272, "VrStereoConfig.leftScreenCenter has unexpected offset % instead of 272", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "VrStereoConfig.leftScreenCenter has unexpected size % instead of 8", it.type.runtime_size);
                case "rightScreenCenter";
                    assert(it.offset_in_bytes == 280, "VrStereoConfig.rightScreenCenter has unexpected offset % instead of 280", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "VrStereoConfig.rightScreenCenter has unexpected size % instead of 8", it.type.runtime_size);
                case "scale";
                    assert(it.offset_in_bytes == 288, "VrStereoConfig.scale has unexpected offset % instead of 288", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "VrStereoConfig.scale has unexpected size % instead of 8", it.type.runtime_size);
                case "scaleIn";
                    assert(it.offset_in_bytes == 296, "VrStereoConfig.scaleIn has unexpected offset % instead of 296", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "VrStereoConfig.scaleIn has unexpected size % instead of 8", it.type.runtime_size);
            }
        }
        assert(size_of(VrStereoConfig) == 304, "VrStereoConfig has size % instead of 304", size_of(VrStereoConfig));
    }

    {
        info := type_info(FilePathList);
        for info.members {
            if it.name == {
                case "capacity";
                    assert(it.offset_in_bytes == 0, "FilePathList.capacity has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "FilePathList.capacity has unexpected size % instead of 4", it.type.runtime_size);
                case "count";
                    assert(it.offset_in_bytes == 4, "FilePathList.count has unexpected offset % instead of 4", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "FilePathList.count has unexpected size % instead of 4", it.type.runtime_size);
                case "paths";
                    assert(it.offset_in_bytes == 8, "FilePathList.paths has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "FilePathList.paths has unexpected size % instead of 8", it.type.runtime_size);
            }
        }
        assert(size_of(FilePathList) == 16, "FilePathList has size % instead of 16", size_of(FilePathList));
    }

    {
        info := type_info(AutomationEvent);
        for info.members {
            if it.name == {
                case "frame";
                    assert(it.offset_in_bytes == 0, "AutomationEvent.frame has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "AutomationEvent.frame has unexpected size % instead of 4", it.type.runtime_size);
                case "type";
                    assert(it.offset_in_bytes == 4, "AutomationEvent.type has unexpected offset % instead of 4", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "AutomationEvent.type has unexpected size % instead of 4", it.type.runtime_size);
                case "params";
                    assert(it.offset_in_bytes == 8, "AutomationEvent.params has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 16, "AutomationEvent.params has unexpected size % instead of 16", it.type.runtime_size);
            }
        }
        assert(size_of(AutomationEvent) == 24, "AutomationEvent has size % instead of 24", size_of(AutomationEvent));
    }

    {
        info := type_info(AutomationEventList);
        for info.members {
            if it.name == {
                case "capacity";
                    assert(it.offset_in_bytes == 0, "AutomationEventList.capacity has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "AutomationEventList.capacity has unexpected size % instead of 4", it.type.runtime_size);
                case "count";
                    assert(it.offset_in_bytes == 4, "AutomationEventList.count has unexpected offset % instead of 4", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "AutomationEventList.count has unexpected size % instead of 4", it.type.runtime_size);
                case "events";
                    assert(it.offset_in_bytes == 8, "AutomationEventList.events has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "AutomationEventList.events has unexpected size % instead of 8", it.type.runtime_size);
            }
        }
        assert(size_of(AutomationEventList) == 16, "AutomationEventList has size % instead of 16", size_of(AutomationEventList));
    }

    {
        info := type_info(float3);
        for info.members {
            if it.name == {
                case "v";
                    assert(it.offset_in_bytes == 0, "float3.v has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 12, "float3.v has unexpected size % instead of 12", it.type.runtime_size);
            }
        }
        assert(size_of(float3) == 12, "float3 has size % instead of 12", size_of(float3));
    }

    {
        info := type_info(float16);
        for info.members {
            if it.name == {
                case "v";
                    assert(it.offset_in_bytes == 0, "float16.v has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 64, "float16.v has unexpected size % instead of 64", it.type.runtime_size);
            }
        }
        assert(size_of(float16) == 64, "float16 has size % instead of 64", size_of(float16));
    }
}

